TeamspeakStats/tsstats/log.py

93 lines
3.1 KiB
Python
Raw Normal View History

import logging
import re
from datetime import datetime
from glob import glob
from tsstats.client import Client, Clients
re_log_entry = re.compile('(?P<timestamp>\d{4}-\d\d-\d\d\ \d\d:\d\d:\d\d.\d+)'
'\|\ *(?P<level>\w+)\ *\|\ *(?P<component>\w+)\ *'
'\|\ *(?P<sid>\d+)\ *\|\ *(?P<message>.*)')
re_dis_connect = re.compile(r"'(.*)'\(id:(\d*)\)")
re_disconnect_invoker = re.compile(
r'invokername=(.*)\ invokeruid=(.*)\ reasonmsg'
)
log_timestamp_format = '%Y-%m-%d %H:%M:%S.%f'
logger = logging.getLogger('tsstats')
def parse_logs(log_glob, ident_map=None):
'''
parse logs specified by globbing pattern `log_glob`
:param log_glob: path to log-files (supports globbing)
:param ident_map: :ref:`IdentMap`
:type log_glob: str
:type ident_map: dict
:return: parsed clients
:rtype: tsstats.client.Clients
'''
clients = Clients(ident_map)
for log_file in sorted(log_file for log_file in glob(log_glob)):
clients = parse_log(log_file, ident_map, clients)
return clients
def parse_log(log_path, ident_map=None, clients=None):
'''
parse log-file at `log_path`
:param log_path: path to log-file
:param ident_map: :ref:`IdentMap`
:param clients: clients-object to add parsing-results to
:type log_path: str
:type ident_map: dict
:type clients: tsstats.client.Clients
:return: parsed clients
:rtype: tsstats.client.Clients
'''
if not clients:
clients = Clients(ident_map)
log_file = open(log_path)
# process lines
logger.debug('Started parsing of %s', log_file.name)
for line in log_file:
match = re_log_entry.match(line)
if not match:
logger.debug('No match: "%s"', line)
continue
match = match.groupdict()
stripped_time = datetime.strptime(match['timestamp'],
log_timestamp_format)
logdatetime = int((stripped_time - datetime(1970, 1, 1))
.total_seconds())
message = match['message']
if message.startswith('client'):
nick, clid = re_dis_connect.findall(message)[0]
client = clients.setdefault(clid, Client(clid, nick))
client.nick = nick # set nick to display changes
if message.startswith('client connected'):
client.connect(logdatetime)
elif message.startswith('client disconnected'):
client.disconnect(logdatetime)
if 'invokeruid' in message:
re_disconnect_data = re_disconnect_invoker.findall(
message)
invokernick, invokeruid = re_disconnect_data[0]
invoker = clients.setdefault(invokeruid,
Client(invokeruid))
invoker.nick = invokernick
if 'bantime' in message:
invoker.ban(client)
else:
invoker.kick(client)
logger.debug('Finished parsing of %s', log_file.name)
return clients