From da5683ede260ff35c27d57fd08e42fdd514c3db8 Mon Sep 17 00:00:00 2001
From: Thor77 <xXThor77Xx@gmail.com>
Date: Tue, 24 May 2016 22:30:16 +0200
Subject: [PATCH] add tsstats.log.re_log_entry for log-line-matching

* don't evaluate invalid log-lines leading to unexpected results
* don't abort parsing just because of an invalid character at the beginning/end
* add debug-output if line doesn't match
---
 docs/source/conf.py |  4 ++--
 setup.py            |  2 +-
 tsstats/log.py      | 27 +++++++++++++++++----------
 3 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/docs/source/conf.py b/docs/source/conf.py
index efeb561..11b5efc 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -54,9 +54,9 @@ author = 'Thor77'
 # built documents.
 #
 # The short X.Y version.
-version = '0.4'
+version = '0.5'
 # The full version, including alpha/beta/rc tags.
-release = '0.4.1'
+release = '0.5.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/setup.py b/setup.py
index d4bfb5b..acb94b2 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup
 
 setup(
     name='tsstats',
-    version='0.4.1',
+    version='0.5.0',
     author='Thor77',
     author_email='thor77@thor77.org',
     description='A simple Teamspeak stats-generator',
diff --git a/tsstats/log.py b/tsstats/log.py
index f9a7a87..6ef6597 100644
--- a/tsstats/log.py
+++ b/tsstats/log.py
@@ -5,6 +5,9 @@ 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'
@@ -28,28 +31,32 @@ def parse_log(log_path, ident_map=None, clients=None):
     # process lines
     logger.debug('Started parsing of %s', log_file.name)
     for line in log_file:
-        parts = line.split('|')
+        match = re_log_entry.match(line)
+        if not match:
+            logger.debug('No match: "%s"', line)
+            continue
+        match = match.groupdict()
         log_format = '%Y-%m-%d %H:%M:%S.%f'
-        stripped_time = datetime.strptime(parts[0], log_format)
+        stripped_time = datetime.strptime(match['timestamp'], log_format)
         logdatetime = int((stripped_time - datetime(1970, 1, 1))
                           .total_seconds())
-        data = '|'.join(parts[4:]).strip()
-        if data.startswith('client'):
-            nick, clid = re_dis_connect.findall(data)[0]
+        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 data.startswith('client connected'):
+            if message.startswith('client connected'):
                 client.connect(logdatetime)
-            elif data.startswith('client disconnected'):
+            elif message.startswith('client disconnected'):
                 client.disconnect(logdatetime)
-                if 'invokeruid' in data:
+                if 'invokeruid' in message:
                     re_disconnect_data = re_disconnect_invoker.findall(
-                        data)
+                        message)
                     invokernick, invokeruid = re_disconnect_data[0]
                     invoker = clients.setdefault(invokeruid,
                                                  Client(invokeruid))
                     invoker.nick = invokernick
-                    if 'bantime' in data:
+                    if 'bantime' in message:
                         invoker.ban(client)
                     else:
                         invoker.kick(client)