Add a proper logging feature. Closes #72.

This commit is contained in:
Vgr E.Barry 2015-01-03 14:52:00 -05:00
parent ee00420812
commit 55a14d6a3f
7 changed files with 107 additions and 73 deletions

2
.gitignore vendored
View File

@ -15,4 +15,4 @@ botconfig.py
*.sqlite3 *.sqlite3
# Log files # Log files
errors.log *.log

View File

@ -2,13 +2,15 @@
import botconfig import botconfig
from tools import decorators from tools import decorators
import logging
import tools.moduleloader as ld import tools.moduleloader as ld
import traceback import traceback
from settings import common as var from settings import common as var
from base64 import b64encode from base64 import b64encode
from oyoyo.parse import parse_nick from oyoyo.parse import parse_nick
import imp import imp
from tools import logger
log = logger("errors.log")
def on_privmsg(cli, rawnick, chan, msg, notice = False): def on_privmsg(cli, rawnick, chan, msg, notice = False):
currmod = ld.MODULES[ld.CURRENT_MODULE] currmod = ld.MODULES[ld.CURRENT_MODULE]
@ -31,7 +33,7 @@ def on_privmsg(cli, rawnick, chan, msg, notice = False):
if botconfig.DEBUG_MODE: if botconfig.DEBUG_MODE:
raise raise
else: else:
logging.error(traceback.format_exc()) log(traceback.format_exc())
cli.msg(chan, "An error has occurred and has been logged.") cli.msg(chan, "An error has occurred and has been logged.")
for x in set(list(COMMANDS.keys()) + (list(currmod.COMMANDS.keys()) if currmod else list())): for x in set(list(COMMANDS.keys()) + (list(currmod.COMMANDS.keys()) if currmod else list())):
@ -51,7 +53,7 @@ def on_privmsg(cli, rawnick, chan, msg, notice = False):
if botconfig.DEBUG_MODE: if botconfig.DEBUG_MODE:
raise raise
else: else:
logging.error(traceback.format_exc()) log(traceback.format_exc())
cli.msg(chan, "An error has occurred and has been logged.") cli.msg(chan, "An error has occurred and has been logged.")
def __unhandled__(cli, prefix, cmd, *args): def __unhandled__(cli, prefix, cmd, *args):
@ -68,12 +70,10 @@ def __unhandled__(cli, prefix, cmd, *args):
if botconfig.DEBUG_MODE: if botconfig.DEBUG_MODE:
raise e raise e
else: else:
logging.error(traceback.format_exc()) log(traceback.format_exc())
cli.msg(botconfig.CHANNEL, "An error has occurred and has been logged.") cli.msg(botconfig.CHANNEL, "An error has occurred and has been logged.")
else: elif botconfig.VERBOSE_MODE or botconfig.DEBUG_MODE:
logging.debug('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8') log('Unhandled command {0}({1})'.format(cmd, [arg.decode('utf_8') for arg in args if isinstance(arg, bytes)]), write=False)
for arg in args
if isinstance(arg, bytes)]))
COMMANDS = {} COMMANDS = {}
@ -155,8 +155,6 @@ def connect_callback(cli):
@hook("ping") @hook("ping")
def on_ping(cli, prefix, server): def on_ping(cli, prefix, server):
cli.send('PONG', server) cli.send('PONG', server)
if botconfig.DEBUG_MODE: if botconfig.DEBUG_MODE:
@cmd("module", admin_only = True) @cmd("module", admin_only = True)

View File

@ -37,6 +37,9 @@ import math
import random import random
import subprocess import subprocess
import signal import signal
from tools import logger
debuglog = logger("debug.log", write=False, display=False) # will be True if in debug mode
BOLD = "\u0002" BOLD = "\u0002"
@ -278,11 +281,6 @@ def mass_mode(cli, md):
def pm(cli, target, message): # message either privmsg or notice, depending on user settings def pm(cli, target, message): # message either privmsg or notice, depending on user settings
if is_fake_nick(target) and botconfig.DEBUG_MODE: if is_fake_nick(target) and botconfig.DEBUG_MODE:
print("[{0}] Would send message to fake nick {1}: {2}".format(
time.strftime("%d/%b/%Y %H:%M:%S"),
target,
message), file=sys.stderr)
return return
if is_user_notice(target): if is_user_notice(target):
@ -291,21 +289,6 @@ def pm(cli, target, message): # message either privmsg or notice, depending on
cli.msg(target, message) cli.msg(target, message)
def log_cmd(raw_nick, command, ptext, text):
(nick, _, user, host) = parse_nick(raw_nick)
msg = "[{0}] {1} ({2}@{3}) {4}".format(
time.strftime("%Y-%m-%d %H:%M:%S%z"), nick, user, host, command)
if ptext:
msg += " " + ptext
if text:
msg += ": " + text
print(msg)
def reset_settings(): def reset_settings():
for attr in list(var.ORIGINAL_SETTINGS.keys()): for attr in list(var.ORIGINAL_SETTINGS.keys()):
setattr(var, attr, var.ORIGINAL_SETTINGS[attr]) setattr(var, attr, var.ORIGINAL_SETTINGS[attr])
@ -3991,6 +3974,7 @@ def kill(cli, nick, chan, rest):
var.LOGGER.logBare(nick, "SELECT", victim) var.LOGGER.logBare(nick, "SELECT", victim)
if var.ANGRY_WOLVES and role in wolfroles: if var.ANGRY_WOLVES and role in wolfroles:
pm(cli, nick, "You are angry tonight and may kill a second target. Use kill <nick1> and <nick2> to select multiple targets.") pm(cli, nick, "You are angry tonight and may kill a second target. Use kill <nick1> and <nick2> to select multiple targets.")
debuglog(nick, role, "kill", victim, var.get_role(victim), victim2, var.get_role(victim2) if victim2 else "")
chk_nightdone(cli) chk_nightdone(cli)
@cmd("guard", "protect", "save", chan=False, pm=True, game=False, playing=True, roles=("bodyguard", "guardian angel")) @cmd("guard", "protect", "save", chan=False, pm=True, game=False, playing=True, roles=("bodyguard", "guardian angel"))
@ -4032,6 +4016,7 @@ def guard(cli, nick, chan, rest):
pm(cli, nick, "You are protecting \u0002{0}\u0002 tonight. Farewell!".format(var.GUARDED[nick])) pm(cli, nick, "You are protecting \u0002{0}\u0002 tonight. Farewell!".format(var.GUARDED[nick]))
pm(cli, var.GUARDED[nick], "You can sleep well tonight, for you are being protected.") pm(cli, var.GUARDED[nick], "You can sleep well tonight, for you are being protected.")
var.LOGGER.logBare(var.GUARDED[nick], "GUARDED", nick) var.LOGGER.logBare(var.GUARDED[nick], "GUARDED", nick)
debuglog(nick, role, "guard", victim, var.get_role(victim))
chk_nightdone(cli) chk_nightdone(cli)
@ -4092,6 +4077,7 @@ def observe(cli, nick, chan, rest):
pm(cli, nick, ("After casting your ritual, you determine that \u0002{0}\u0002 " + pm(cli, nick, ("After casting your ritual, you determine that \u0002{0}\u0002 " +
"does not have paranormal senses.").format(victim)) "does not have paranormal senses.").format(victim))
var.LOGGER.logBare(victim, "OBSERVED", nick) var.LOGGER.logBare(victim, "OBSERVED", nick)
debuglog(nick, role, "observe", victim, vrole)
chk_nightdone(cli) chk_nightdone(cli)
@cmd("id", chan=False, pm=True, game=True, playing=True, roles=("detective",)) @cmd("id", chan=False, pm=True, game=True, playing=True, roles=("detective",))
@ -4120,12 +4106,14 @@ def investigate(cli, nick, chan, rest):
vrole = var.FINAL_ROLES[victim] vrole = var.FINAL_ROLES[victim]
pm(cli, nick, ("The results of your investigation have returned. \u0002{0}\u0002"+ pm(cli, nick, ("The results of your investigation have returned. \u0002{0}\u0002"+
" is a... \u0002{1}\u0002!").format(victim, vrole)) " is a... \u0002{1}\u0002!").format(victim, vrole))
debuglog(nick, var.get_role(nick), "id", victim, vrole)
var.LOGGER.logBare(victim, "INVESTIGATED", nick) var.LOGGER.logBare(victim, "INVESTIGATED", nick)
if random.random() < var.DETECTIVE_REVEALED_CHANCE: # a 2/5 chance (should be changeable in settings) if random.random() < var.DETECTIVE_REVEALED_CHANCE: # a 2/5 chance (should be changeable in settings)
# The detective's identity is compromised! # The detective's identity is compromised!
for badguy in var.list_players(var.WOLFCHAT_ROLES): for badguy in var.list_players(var.WOLFCHAT_ROLES):
pm(cli, badguy, ("Someone accidentally drops a paper. The paper reveals "+ pm(cli, badguy, ("Someone accidentally drops a paper. The paper reveals "+
"that \u0002{0}\u0002 is the detective!").format(nick)) "that \u0002{0}\u0002 is the detective!").format(nick))
debuglog(nick, "paperdrop", " ".join(var.list_players(var.WOLFCHAT_ROLES)))
var.LOGGER.logBare(nick, "PAPERDROP") var.LOGGER.logBare(nick, "PAPERDROP")
@cmd("visit", chan=False, pm=True, game=True, playing=True, roles=("harlot",)) @cmd("visit", chan=False, pm=True, game=True, playing=True, roles=("harlot",))
@ -4158,6 +4146,7 @@ def hvisit(cli, nick, chan, rest):
pm(cli, victim, ("You are spending the night with \u0002{0}"+ pm(cli, victim, ("You are spending the night with \u0002{0}"+
"\u0002. Have a good time!").format(nick)) "\u0002. Have a good time!").format(nick))
var.LOGGER.logBare(var.HVISITED[nick], "VISITED", nick) var.LOGGER.logBare(var.HVISITED[nick], "VISITED", nick)
debuglog(nick, var.get_role(nick), "visited", victim, var.get_role(victim))
chk_nightdone(cli) chk_nightdone(cli)
def is_fake_nick(who): def is_fake_nick(who):
@ -4216,6 +4205,8 @@ def see(cli, nick, chan, rest):
"a \u0002{1}\u0002 aura!").format(victim, aura)) "a \u0002{1}\u0002 aura!").format(victim, aura))
var.SEEN.append(nick) var.SEEN.append(nick)
var.LOGGER.logBare(victim, "SEEN", nick) var.LOGGER.logBare(victim, "SEEN", nick)
vrole = var.get_role(victim)
debuglog(nick, role, "see", victim, victimrole, vrole if vrole != "amnesiac" else var.FINAL_ROLES[victim])
chk_nightdone(cli) chk_nightdone(cli)
@cmd("give", chan=False, pm=True, game=True, playing=True, roles=var.TOTEM_ORDER+("doctor",)) @cmd("give", chan=False, pm=True, game=True, playing=True, roles=var.TOTEM_ORDER+("doctor",))
@ -4299,6 +4290,7 @@ def totem(cli, nick, chan, rest):
var.LASTGIVEN[nick] = victim var.LASTGIVEN[nick] = victim
var.SHAMANS.append(nick) var.SHAMANS.append(nick)
var.LOGGER.logBare(victim, "GIVEN TOTEM", nick) var.LOGGER.logBare(victim, "GIVEN TOTEM", nick)
debuglog(nick, var.get_role(nick), "totem", victim, totem)
chk_nightdone(cli) chk_nightdone(cli)
@cmd("immunize", "immunise", chan=False, pm=True, game=True, playing=True, roles=("doctor",)) @cmd("immunize", "immunise", chan=False, pm=True, game=True, playing=True, roles=("doctor",))
@ -4342,6 +4334,7 @@ def immunize(cli, nick, chan, rest):
pm(cli, victim, ("You feel a sharp prick in the back of your arm and temporarily black out. " + pm(cli, victim, ("You feel a sharp prick in the back of your arm and temporarily black out. " +
"When you come to, you notice an empty syringe lying on the ground. {0}").format(lycan_message)) "When you come to, you notice an empty syringe lying on the ground. {0}").format(lycan_message))
var.DOCTORS[nick] -= 1 var.DOCTORS[nick] -= 1
debuglog(nick, var.get_role(nick), "immunize", victim, "lycan" if victim in var.CURED_LYCANS else var.get_role(victim))
def get_bitten_message(nick): def get_bitten_message(nick):
time_left = var.BITTEN[nick] time_left = var.BITTEN[nick]
@ -4381,13 +4374,13 @@ def bite_cmd(cli, nick, chan, rest):
victim = get_victim(cli, nick, re.split(" +",rest)[0], False) victim = get_victim(cli, nick, re.split(" +",rest)[0], False)
vrole = var.get_role(victim)
if var.ANGRY_WOLVES: if var.ANGRY_WOLVES:
if not victim: if not victim:
pm(cli, nick, "Please choose who to bite by specifying their nick.") pm(cli, nick, "Please choose who to bite by specifying their nick.")
return return
vrole = var.get_role(victim)
if vrole in var.WOLFCHAT_ROLES: if vrole in var.WOLFCHAT_ROLES:
pm(cli, nick, "You may not bite other wolves.") pm(cli, nick, "You may not bite other wolves.")
return return
@ -4403,6 +4396,7 @@ def bite_cmd(cli, nick, chan, rest):
pm(cli, nick, "You have chosen to bite \u0002{0}\u0002. If that player is not selected to be killed, you will bite one of the wolf targets at random instead.".format(victim)) pm(cli, nick, "You have chosen to bite \u0002{0}\u0002. If that player is not selected to be killed, you will bite one of the wolf targets at random instead.".format(victim))
else: else:
pm(cli, nick, "You have chosen to bite tonight. Whomever the wolves select to be killed tonight will be bitten instead.") pm(cli, nick, "You have chosen to bite tonight. Whomever the wolves select to be killed tonight will be bitten instead.")
debuglog(nick, var.get_role(nick), "bite", victim, vrole)
@cmd("pass", chan=False, pm=True, game=True, playing=True, roles=("hunter",)) @cmd("pass", chan=False, pm=True, game=True, playing=True, roles=("hunter",))
def pass_cmd(cli, nick, chan, rest): def pass_cmd(cli, nick, chan, rest):
@ -4421,6 +4415,7 @@ def pass_cmd(cli, nick, chan, rest):
if nick not in var.PASSED: # Prevents multiple entries if nick not in var.PASSED: # Prevents multiple entries
var.PASSED.append(nick) var.PASSED.append(nick)
#var.LOGGER.logBare(nick, "PASS", nick) #var.LOGGER.logBare(nick, "PASS", nick)
debuglog(nick, var.get_role(nick), "pass")
chk_nightdone(cli) chk_nightdone(cli)
@cmd("choose", "match", chan=False, pm=True, game=True, playing=True, roles=("matchmaker",)) @cmd("choose", "match", chan=False, pm=True, game=True, playing=True, roles=("matchmaker",))
@ -4486,6 +4481,7 @@ def choose(cli, nick, chan, rest):
pm(cli, victim2, "You are \u0002in love\u0002 with {0}.".format(victim)) pm(cli, victim2, "You are \u0002in love\u0002 with {0}.".format(victim))
var.LOGGER.logBare(victim, "LOVERS", victim2) var.LOGGER.logBare(victim, "LOVERS", victim2)
debuglog(nick, var.get_role(nick), "match", victim, var.get_role(victim), victim2, var.get_role(victim2))
chk_nightdone(cli) chk_nightdone(cli)
@cmd("target", chan=False, pm=True, game=True, playing=True, roles=("assassin",)) @cmd("target", chan=False, pm=True, game=True, playing=True, roles=("assassin",))
@ -4513,6 +4509,7 @@ def target(cli, nick, chan, rest):
pm(cli, nick, "You have selected \u0002{0}\u0002 as your target.".format(victim)) pm(cli, nick, "You have selected \u0002{0}\u0002 as your target.".format(victim))
var.LOGGER.logBare(nick, "TARGETED", victim) var.LOGGER.logBare(nick, "TARGETED", victim)
debuglog(nick, var.get_template(nick), victim, var.get_role(victim))
chk_nightdone(cli) chk_nightdone(cli)
@cmd("hex", chan=False, pm=True, game=True, playing=True, roles=("hag",)) @cmd("hex", chan=False, pm=True, game=True, playing=True, roles=("hag",))
@ -4552,6 +4549,7 @@ def hex(cli, nick, chan, rest):
pm(cli, nick, "You have cast a hex on \u0002{0}\u0002.".format(victim)) pm(cli, nick, "You have cast a hex on \u0002{0}\u0002.".format(victim))
var.LOGGER.logBare(nick, "HEXED", victim) var.LOGGER.logBare(nick, "HEXED", victim)
debuglog(nick, var.get_role(nick), "hex", victim, var.get_role(victim))
chk_nightdone(cli) chk_nightdone(cli)
@cmd("clone", chan=False, pm=True, game=True, playing=True, roles=("clone",)) @cmd("clone", chan=False, pm=True, game=True, playing=True, roles=("clone",))
@ -4578,6 +4576,7 @@ def clone(cli, nick, chan, rest):
pm(cli, nick, "You have chosen to clone \u0002{0}\u0002.".format(victim)) pm(cli, nick, "You have chosen to clone \u0002{0}\u0002.".format(victim))
var.LOGGER.logBare(nick, "CLONED", victim) var.LOGGER.logBare(nick, "CLONED", victim)
debuglog(nick, var.get_role(nick), "clone", victim, var.get_role(victim))
chk_nightdone(cli) chk_nightdone(cli)
@hook("featurelist") # For multiple targets with PRIVMSG @hook("featurelist") # For multiple targets with PRIVMSG
@ -4785,6 +4784,7 @@ def transition_night(cli):
for wolf in var.list_players(var.WOLFCHAT_ROLES): for wolf in var.list_players(var.WOLFCHAT_ROLES):
if wolf != chump: if wolf != chump:
pm(cli, wolf, "\u0002{0}\u0002 is now a \u0002wolf\u0002!".format(chump)) pm(cli, wolf, "\u0002{0}\u0002 is now a \u0002wolf\u0002!".format(chump))
debuglog(chump, chumprole, "turned wolf")
# convert amnesiac and kill village elder if necessary # convert amnesiac and kill village elder if necessary
if var.NIGHT_COUNT == var.AMNESIAC_NIGHTS: if var.NIGHT_COUNT == var.AMNESIAC_NIGHTS:
@ -4803,11 +4803,13 @@ def transition_night(cli):
if amnrole in var.WOLFCHAT_ROLES: if amnrole in var.WOLFCHAT_ROLES:
for wolf in var.list_players(var.WOLFCHAT_ROLES): for wolf in var.list_players(var.WOLFCHAT_ROLES):
pm(cli, wolf, "\u0002{0}\u0002 is now a \u0002{1}\u0002!".format(amn, showrole)) pm(cli, wolf, "\u0002{0}\u0002 is now a \u0002{1}\u0002!".format(amn, showrole))
debuglog(amn, amnrole, "remember", showrole)
numwolves = len(var.list_players(var.WOLF_ROLES)) numwolves = len(var.list_players(var.WOLF_ROLES))
if var.NIGHT_COUNT >= numwolves + 1: if var.NIGHT_COUNT >= numwolves + 1:
for elder in var.ROLES["village elder"]: for elder in var.ROLES["village elder"]:
var.DYING.append(elder) var.DYING.append(elder)
debuglog(elder, "elder death")
# game ended from bitten / amnesiac turning, narcolepsy totem expiring, or other weirdness # game ended from bitten / amnesiac turning, narcolepsy totem expiring, or other weirdness
if chk_win(cli): if chk_win(cli):
@ -4866,6 +4868,7 @@ def transition_night(cli):
an = 'n' if cursed == '' and role[0] in ('a', 'e', 'i', 'o', 'u') else '' an = 'n' if cursed == '' and role[0] in ('a', 'e', 'i', 'o', 'u') else ''
pm(cli, wolf, "You are a{0} \02{1}{2}\02.".format(an, cursed, role)) # !simple pm(cli, wolf, "You are a{0} \02{1}{2}\02.".format(an, cursed, role)) # !simple
debuglog(wolf, cursed + " " + role if cursed else role)
pl = ps[:] pl = ps[:]
random.shuffle(pl) random.shuffle(pl)
pl.remove(wolf) # remove self from list pl.remove(wolf) # remove self from list
@ -4919,6 +4922,7 @@ def transition_night(cli):
else: else:
pm(cli, seer, "You are {0} \02{1}\02.".format(a, role)) # !simple pm(cli, seer, "You are {0} \02{1}\02.".format(a, role)) # !simple
pm(cli, seer, "Players: " + ", ".join(pl)) pm(cli, seer, "Players: " + ", ".join(pl))
debuglog(seer, role)
for harlot in var.ROLES["harlot"]: for harlot in var.ROLES["harlot"]:
pl = ps[:] pl = ps[:]
@ -4932,6 +4936,7 @@ def transition_night(cli):
else: else:
pm(cli, harlot, "You are a \02harlot\02.") # !simple pm(cli, harlot, "You are a \02harlot\02.") # !simple
pm(cli, harlot, "Players: " + ", ".join(pl)) pm(cli, harlot, "Players: " + ", ".join(pl))
debuglog(harlot, "harlot")
# the messages for angel and guardian angel are different enough to merit individual loops # the messages for angel and guardian angel are different enough to merit individual loops
for g_angel in var.ROLES["bodyguard"]: for g_angel in var.ROLES["bodyguard"]:
@ -4951,6 +4956,7 @@ def transition_night(cli):
else: else:
pm(cli, g_angel, "You are a \02bodyguard\02.") # !simple pm(cli, g_angel, "You are a \02bodyguard\02.") # !simple
pm(cli, g_angel, "Players: " + ", ".join(pl)) pm(cli, g_angel, "Players: " + ", ".join(pl))
debuglog(g_angel, "bodyguard")
for gangel in var.ROLES["guardian angel"]: for gangel in var.ROLES["guardian angel"]:
pl = ps[:] pl = ps[:]
@ -4969,6 +4975,7 @@ def transition_night(cli):
else: else:
pm(cli, gangel, "You are a \02guardian angel\02.") # !simple pm(cli, gangel, "You are a \02guardian angel\02.") # !simple
pm(cli, gangel, "Players: " + ", ".join(pl)) pm(cli, gangel, "Players: " + ", ".join(pl))
debuglog(gangel, "guardian angel")
for dttv in var.ROLES["detective"]: for dttv in var.ROLES["detective"]:
pl = ps[:] pl = ps[:]
@ -4988,12 +4995,14 @@ def transition_night(cli):
else: else:
pm(cli, dttv, "You are a \02detective\02.") # !simple pm(cli, dttv, "You are a \02detective\02.") # !simple
pm(cli, dttv, "Players: " + ", ".join(pl)) pm(cli, dttv, "Players: " + ", ".join(pl))
debuglog(dttv, "detective")
for drunk in var.ROLES["village drunk"]: for drunk in var.ROLES["village drunk"]:
if drunk in var.PLAYERS and not is_user_simple(drunk): if drunk in var.PLAYERS and not is_user_simple(drunk):
pm(cli, drunk, "You have been drinking too much! You are the \u0002village drunk\u0002.") pm(cli, drunk, "You have been drinking too much! You are the \u0002village drunk\u0002.")
else: else:
pm(cli, drunk, "You are the \u0002village drunk\u0002.") pm(cli, drunk, "You are the \u0002village drunk\u0002.")
debuglog(drunk, "village drunk")
max_totems = {} max_totems = {}
for sham in var.TOTEM_ORDER: for sham in var.TOTEM_ORDER:
@ -5055,9 +5064,10 @@ def transition_night(cli):
pm(cli, shaman, tmsg) pm(cli, shaman, tmsg)
else: else:
pm(cli, shaman, "You are a \u0002{0}\u0002.".format(role)) pm(cli, shaman, "You are a \u0002{0}\u0002.".format(role))
if shaman in var.ROLES["shaman"]: if role != "crazed shaman":
pm(cli, shaman, "You have the \u0002{0}\u0002 totem.".format(var.TOTEMS[shaman])) pm(cli, shaman, "You have the \u0002{0}\u0002 totem.".format(var.TOTEMS[shaman]))
pm(cli, shaman, "Players: " + ", ".join(pl)) pm(cli, shaman, "Players: " + ", ".join(pl))
debuglog(shaman, role, var.TOTEMS[shaman])
for hunter in var.ROLES["hunter"]: for hunter in var.ROLES["hunter"]:
if hunter in var.HUNTERS: if hunter in var.HUNTERS:
@ -5072,6 +5082,7 @@ def transition_night(cli):
else: else:
pm(cli, hunter, "You are a \u0002hunter\u0002.") pm(cli, hunter, "You are a \u0002hunter\u0002.")
pm(cli, hunter, "Players: " + ", ".join(pl)) pm(cli, hunter, "Players: " + ", ".join(pl))
debuglog(hunter, "hunter")
for ms in var.ROLES["mad scientist"]: for ms in var.ROLES["mad scientist"]:
@ -5105,6 +5116,7 @@ def transition_night(cli):
"will kill {0} if they are still alive.".format(targets))) "will kill {0} if they are still alive.".format(targets)))
else: else:
pm(cli, ms, "You are the \u0002mad scientist\u0002. Targets: {0}".format(targets)) pm(cli, ms, "You are the \u0002mad scientist\u0002. Targets: {0}".format(targets))
debuglog(ms, "mad scientist", target1, target2)
for doctor in var.ROLES["doctor"]: for doctor in var.ROLES["doctor"]:
if var.DOCTORS[doctor] > 0: # has immunizations remaining if var.DOCTORS[doctor] > 0: # has immunizations remaining
@ -5118,6 +5130,7 @@ def transition_night(cli):
else: else:
pm(cli, doctor, "You are a \u0002doctor\u0002.") pm(cli, doctor, "You are a \u0002doctor\u0002.")
pm(cli, doctor, 'You have \u0002{0}\u0002 immunization{1}.'.format(var.DOCTORS[doctor], 's' if var.DOCTORS[doctor] > 1 else '')) pm(cli, doctor, 'You have \u0002{0}\u0002 immunization{1}.'.format(var.DOCTORS[doctor], 's' if var.DOCTORS[doctor] > 1 else ''))
debuglog(doctor, "doctor")
for fool in var.ROLES["fool"]: for fool in var.ROLES["fool"]:
if fool in var.PLAYERS and not is_user_simple(fool): if fool in var.PLAYERS and not is_user_simple(fool):
@ -5126,6 +5139,7 @@ def transition_night(cli):
'otherwise win this game.')) 'otherwise win this game.'))
else: else:
pm(cli, fool, "You are a \u0002fool\u0002.") pm(cli, fool, "You are a \u0002fool\u0002.")
debuglog(fool, "fool")
for jester in var.ROLES["jester"]: for jester in var.ROLES["jester"]:
if jester in var.PLAYERS and not is_user_simple(jester): if jester in var.PLAYERS and not is_user_simple(jester):
@ -5133,6 +5147,7 @@ def transition_night(cli):
'if you are lynched during the day. You cannot otherwise win this game.')) 'if you are lynched during the day. You cannot otherwise win this game.'))
else: else:
pm(cli, jester, "You are a \u0002jester\u0002.") pm(cli, jester, "You are a \u0002jester\u0002.")
debuglog(jester, "jester")
for monster in var.ROLES["monster"]: for monster in var.ROLES["monster"]:
if monster in var.PLAYERS and not is_user_simple(monster): if monster in var.PLAYERS and not is_user_simple(monster):
@ -5141,6 +5156,7 @@ def transition_night(cli):
'normal winners.')) 'normal winners.'))
else: else:
pm(cli, monster, "You are a \u0002monster\u0002.") pm(cli, monster, "You are a \u0002monster\u0002.")
debuglog(monster, "monster")
for lycan in var.ROLES["lycan"]: for lycan in var.ROLES["lycan"]:
if lycan in var.PLAYERS and not is_user_simple(lycan): if lycan in var.PLAYERS and not is_user_simple(lycan):
@ -5149,6 +5165,7 @@ def transition_night(cli):
'during the night.')) 'during the night.'))
else: else:
pm(cli, lycan, "You are a \u0002lycan\u0002.") pm(cli, lycan, "You are a \u0002lycan\u0002.")
debuglog(lycan, "lycan")
for v_ghost, who in var.VENGEFUL_GHOSTS.items(): for v_ghost, who in var.VENGEFUL_GHOSTS.items():
wolves = var.list_players(var.WOLFTEAM_ROLES) wolves = var.list_players(var.WOLFTEAM_ROLES)
@ -5169,6 +5186,7 @@ def transition_night(cli):
else: else:
pm(cli, v_ghost, "You are a \u0002vengeful ghost\u0002.") pm(cli, v_ghost, "You are a \u0002vengeful ghost\u0002.")
pm(cli, v_ghost, who.capitalize() + ": " + ", ".join(pl)) pm(cli, v_ghost, who.capitalize() + ": " + ", ".join(pl))
debuglog(v_ghost, "vengeful ghost", who)
for ass in var.ROLES["assassin"]: for ass in var.ROLES["assassin"]:
if ass in var.TARGETED and var.TARGETED[ass] != None: if ass in var.TARGETED and var.TARGETED[ass] != None:
@ -5192,6 +5210,7 @@ def transition_night(cli):
else: else:
pm(cli, ass, "You are an \u0002assassin\u0002.") pm(cli, ass, "You are an \u0002assassin\u0002.")
pm(cli, ass, "Players: " + ", ".join(pl)) pm(cli, ass, "Players: " + ", ".join(pl))
debuglog(ass, "assassin")
if var.FIRST_NIGHT: if var.FIRST_NIGHT:
for mm in var.ROLES["matchmaker"]: for mm in var.ROLES["matchmaker"]:
@ -5205,6 +5224,7 @@ def transition_night(cli):
else: else:
pm(cli, mm, "You are a \u0002matchmaker\u0002.") pm(cli, mm, "You are a \u0002matchmaker\u0002.")
pm(cli, mm, "Players: " + ", ".join(pl)) pm(cli, mm, "Players: " + ", ".join(pl))
debuglog(mm, "matchmaker")
for clone in var.ROLES["clone"]: for clone in var.ROLES["clone"]:
pl = ps[:] pl = ps[:]
@ -5217,6 +5237,7 @@ def transition_night(cli):
else: else:
pm(cli, clone, "You are a \u0002clone\u0002") pm(cli, clone, "You are a \u0002clone\u0002")
pm(cli, clone, "Players: "+", ".join(pl)) pm(cli, clone, "Players: "+", ".join(pl))
debuglog(clone, "clone")
for minion in var.ROLES["minion"]: for minion in var.ROLES["minion"]:
wolves = var.list_players(var.WOLF_ROLES) wolves = var.list_players(var.WOLF_ROLES)
@ -5226,6 +5247,7 @@ def transition_night(cli):
else: else:
pm(cli, minion, "You are a \u0002minion\u0002.") pm(cli, minion, "You are a \u0002minion\u0002.")
pm(cli, minion, "Wolves: " + ", ".join(wolves)) pm(cli, minion, "Wolves: " + ", ".join(wolves))
debuglog(minion, "minion", " ".join(wolves))
villagers = copy.copy(var.ROLES["villager"]) villagers = copy.copy(var.ROLES["villager"])
villagers += var.ROLES["time lord"] + var.ROLES["village elder"] villagers += var.ROLES["time lord"] + var.ROLES["village elder"]
@ -5236,6 +5258,7 @@ def transition_night(cli):
pm(cli, villager, "You are a \u0002villager\u0002. It is your job to lynch all of the wolves.") pm(cli, villager, "You are a \u0002villager\u0002. It is your job to lynch all of the wolves.")
else: else:
pm(cli, villager, "You are a \u0002villager\u0002.") pm(cli, villager, "You are a \u0002villager\u0002.")
debuglog(villager, "villager")
cultists = copy.copy(var.ROLES["cultist"]) cultists = copy.copy(var.ROLES["cultist"])
if var.DEFAULT_ROLE == "cultist": if var.DEFAULT_ROLE == "cultist":
@ -5245,6 +5268,7 @@ def transition_night(cli):
pm(cli, cultist, "You are a \u0002cultist\u0002. It is your job to help the wolves kill all of the villagers.") pm(cli, cultist, "You are a \u0002cultist\u0002. It is your job to help the wolves kill all of the villagers.")
else: else:
pm(cli, cultist, "You are a \u0002cultist\u0002.") pm(cli, cultist, "You are a \u0002cultist\u0002.")
debuglog(cultist, "cultist")
for g in var.GUNNERS.keys(): for g in var.GUNNERS.keys():
if g not in ps: if g not in ps:
@ -5278,6 +5302,7 @@ def transition_night(cli):
continue continue
pm(cli, g, gun_msg) pm(cli, g, gun_msg)
debuglog(g, "gunner", var.GUNNERS[g])
dmsg = (daydur_msg + "It is now nighttime. All players "+ dmsg = (daydur_msg + "It is now nighttime. All players "+
"check for PMs from me for instructions.") "check for PMs from me for instructions.")
@ -5288,6 +5313,7 @@ def transition_night(cli):
cli.msg(chan, dmsg) cli.msg(chan, dmsg)
var.LOGGER.logMessage(dmsg.replace("\02", "")) var.LOGGER.logMessage(dmsg.replace("\02", ""))
var.LOGGER.logBare("NIGHT", "BEGIN") var.LOGGER.logBare("NIGHT", "BEGIN")
debuglog("begin night")
@ -6113,7 +6139,7 @@ def on_invite(cli, nick, something, chan):
return # No questions return # No questions
if is_admin(parse_nick(nick)[0]): if is_admin(parse_nick(nick)[0]):
cli.join(chan) # Allows the bot to be present in any channel cli.join(chan) # Allows the bot to be present in any channel
log_cmd(nick, "invite", "", chan) debuglog(nick, "invite", chan, display=True)
else: else:
pm(parse_nick(nick)[0], "You are not an admin.") pm(parse_nick(nick)[0], "You are not an admin.")
@ -6134,7 +6160,6 @@ def fpart(cli, rnick, chan, rest):
if chan == botconfig.CHANNEL: if chan == botconfig.CHANNEL:
cli.notice(nick, "No, that won't be allowed.") cli.notice(nick, "No, that won't be allowed.")
return return
log_cmd(rnick, "fpart", "", chan)
cli.part(chan) cli.part(chan)
@cmd("admins", "ops", pm=True) @cmd("admins", "ops", pm=True)
@ -6621,10 +6646,8 @@ def fpull(cli, nick, chan, rest):
else: else:
pm(cli, nick, "Process %s exited with %s %d" % (args, cause, ret)) pm(cli, nick, "Process %s exited with %s %d" % (args, cause, ret))
@cmd("fsend", admin_only=True, raw_nick=True, pm=True) @cmd("fsend", admin_only=True, pm=True)
def fsend(cli, raw_nick, chan, rest): def fsend(cli, nick, chan, rest):
log_cmd(raw_nick, "fsend", "", rest)
cli.send(rest) cli.send(rest)
def _say(cli, raw_nick, rest, command, action=False): def _say(cli, raw_nick, rest, command, action=False):
@ -6652,8 +6675,6 @@ def _say(cli, raw_nick, rest, command, action=False):
return return
log_cmd(raw_nick, command, target, message)
if action: if action:
message = "\x01ACTION {0}\x01".format(message) message = "\x01ACTION {0}\x01".format(message)

View File

@ -14,7 +14,6 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
import logging
import socket import socket
import time import time
import threading import threading
@ -111,6 +110,7 @@ class IRCClient(object):
self.sasl_auth = False self.sasl_auth = False
self.use_ssl = False self.use_ssl = False
self.lock = threading.RLock() self.lock = threading.RLock()
self.stream_handler = lambda output, level=None: print(output)
self.tokenbucket = TokenBucket(23, 1.73) self.tokenbucket = TokenBucket(23, 1.73)
@ -153,7 +153,7 @@ class IRCClient(object):
for arg in args]), i)) for arg in args]), i))
msg = bytes(" ", "utf_8").join(bargs) msg = bytes(" ", "utf_8").join(bargs)
logging.info('---> send {0}'.format(str(msg)[1:])) self.stream_handler('---> send {0}'.format(str(msg)[1:]))
while not self.tokenbucket.consume(1): while not self.tokenbucket.consume(1):
time.sleep(0.3) time.sleep(0.3)
@ -170,7 +170,7 @@ class IRCClient(object):
""" """
try: try:
logging.info('connecting to {0}:{1}'.format(self.host, self.port)) self.stream_handler('connecting to {0}:{1}'.format(self.host, self.port))
retries = 0 retries = 0
while True: while True:
try: try:
@ -178,7 +178,7 @@ class IRCClient(object):
break break
except socket.error as e: except socket.error as e:
retries += 1 retries += 1
logging.warning('Error: {0}'.format(e)) self.stream_handler('Error: {0}'.format(e), level="warning")
if retries > 3: if retries > 3:
break break
if not self.blocking: if not self.blocking:
@ -227,8 +227,8 @@ class IRCClient(object):
enc = "latin1" enc = "latin1"
fargs = [arg.decode(enc) for arg in args if isinstance(arg,bytes)] fargs = [arg.decode(enc) for arg in args if isinstance(arg,bytes)]
logging.debug("processCommand ({2}){0}({1})".format(command, self.stream_handler("processCommand ({2}){0}({1})".format(command,
fargs, prefix)) fargs, prefix), level="debug")
try: try:
largs = list(args) largs = list(args)
if prefix is not None: if prefix is not None:
@ -245,7 +245,7 @@ class IRCClient(object):
yield True yield True
finally: finally:
if self.socket: if self.socket:
logging.info('closing socket') self.stream_handler('closing socket')
self.socket.close() self.socket.close()
yield False yield False
def msg(self, user, msg): def msg(self, user, msg):

View File

@ -0,0 +1,27 @@
import botconfig
import time
def logger(file, write=True, display=True):
def log(*output, write=write, display=display):
output = " ".join([str(x) for x in output])
if botconfig.DEBUG_MODE:
write = True
if botconfig.DEBUG_MODE or botconfig.VERBOSE_MODE:
display = True
timestamp = time.strftime("[%Y-%m-%d] (%H:%M:%S) %z ").upper()
if display:
print(timestamp + output)
if write and file is not None:
with open(file, "a") as f:
f.seek(0, 2)
f.write(timestamp + output + "\n")
return log
stream_handler = logger(None)
def stream(output, level="normal"):
if botconfig.VERBOSE_MODE or botconfig.DEBUG_MODE:
stream_handler(output)
elif level == "warning":
stream_handler(output)

View File

@ -12,6 +12,9 @@ from oyoyo.parse import parse_nick
import fnmatch import fnmatch
import botconfig import botconfig
import settings.wolfgame as var import settings.wolfgame as var
from tools import logger
adminlog = logger(None, write=False)
def generate(fdict, permissions=True, **kwargs): def generate(fdict, permissions=True, **kwargs):
"""Generates a decorator generator. Always use this""" """Generates a decorator generator. Always use this"""
@ -20,6 +23,7 @@ def generate(fdict, permissions=True, **kwargs):
def dec(f): def dec(f):
def innerf(*args): def innerf(*args):
largs = list(args) largs = list(args)
rawnick = largs[1]
if not permissions: if not permissions:
return f(*largs) return f(*largs)
if len(largs) > 1 and largs[1]: if len(largs) > 1 and largs[1]:
@ -88,6 +92,7 @@ def generate(fdict, permissions=True, **kwargs):
if fnmatch.fnmatch(acc.lower(), pattern.lower()): if fnmatch.fnmatch(acc.lower(), pattern.lower()):
for cmdname in s: for cmdname in s:
if cmdname in var.ALLOW_ACCOUNTS[pattern]: if cmdname in var.ALLOW_ACCOUNTS[pattern]:
adminlog(rawnick, s[0], largs[2], largs[3])
return f(*largs) return f(*largs)
if not var.ACCOUNTS_ONLY and cloak: if not var.ACCOUNTS_ONLY and cloak:
for pattern in var.DENY.keys(): for pattern in var.DENY.keys():
@ -100,15 +105,18 @@ def generate(fdict, permissions=True, **kwargs):
if fnmatch.fnmatch(cloak.lower(), pattern.lower()): if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
for cmdname in s: for cmdname in s:
if cmdname in var.ALLOW[pattern]: if cmdname in var.ALLOW[pattern]:
adminlog(rawnick, s[0], largs[2], largs[3])
return f(*largs) # no questions return f(*largs) # no questions
if owner_only: if owner_only:
if var.is_owner(nick): if var.is_owner(nick):
adminlog(rawnick, s[0], largs[2], largs[3])
return f(*largs) return f(*largs)
else: else:
largs[0].notice(nick, "You are not the owner.") largs[0].notice(nick, "You are not the owner.")
return return
if admin_only: if admin_only:
if var.is_admin(nick): if var.is_admin(nick):
adminlog(rawnick, s[0], largs[2], largs[3])
return f(*largs) return f(*largs)
else: else:
largs[0].notice(nick, "You are not an admin.") largs[0].notice(nick, "You are not an admin.")

View File

@ -18,16 +18,12 @@
# THE SOFTWARE. # THE SOFTWARE.
from oyoyo.client import IRCClient from oyoyo.client import IRCClient
import logging
import botconfig import botconfig
import time import time
import traceback import traceback
import modules.common import modules.common
import sys import sys
import tools
class UTCFormatter(logging.Formatter):
converter = time.gmtime
def main(): def main():
@ -35,23 +31,6 @@ def main():
print('Python 3.2 or newer is required to run the bot.') print('Python 3.2 or newer is required to run the bot.')
sys.exit(1) sys.exit(1)
if botconfig.DEBUG_MODE:
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()
else:
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler("errors.log")
fh.setLevel(logging.WARNING)
logger.addHandler(fh)
if botconfig.VERBOSE_MODE:
hdlr = logging.StreamHandler(sys.stdout)
hdlr.setLevel(logging.DEBUG)
logger.addHandler(hdlr)
formatter = UTCFormatter('[%(asctime)s] %(message)s', '%d/%b/%Y %H:%M:%S')
for handler in logger.handlers:
handler.setFormatter(formatter)
cli = IRCClient( cli = IRCClient(
{"privmsg": modules.common.on_privmsg, {"privmsg": modules.common.on_privmsg,
"notice": lambda a, b, c, d: modules.common.on_privmsg(a, b, c, d, True), "notice": lambda a, b, c, d: modules.common.on_privmsg(a, b, c, d, True),
@ -65,7 +44,8 @@ def main():
real_name=botconfig.REALNAME, real_name=botconfig.REALNAME,
sasl_auth=botconfig.SASL_AUTHENTICATION, sasl_auth=botconfig.SASL_AUTHENTICATION,
use_ssl=botconfig.USE_SSL, use_ssl=botconfig.USE_SSL,
connect_cb=modules.common.connect_callback connect_cb=modules.common.connect_callback,
stream_handler=tools.stream,
) )
cli.mainLoop() cli.mainLoop()
@ -74,4 +54,4 @@ if __name__ == "__main__":
try: try:
main() main()
except Exception: except Exception:
logging.error(traceback.format_exc()) tools.logger("errors.log")(traceback.format_exc())