[Kimchi-devel] [PATCH] [Wok 1/5] Add User Request Logger

Lucio Correia luciojhc at linux.vnet.ibm.com
Thu Feb 25 20:47:54 UTC 2016


Signed-off-by: Lucio Correia <luciojhc at linux.vnet.ibm.com>
---
 src/wok/config.py.in |  10 ++++
 src/wok/i18n.py      |   4 +-
 src/wok/reqlogger.py | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+), 1 deletion(-)
 create mode 100644 src/wok/reqlogger.py

diff --git a/src/wok/config.py.in b/src/wok/config.py.in
index 40fbcda..afe0f08 100644
--- a/src/wok/config.py.in
+++ b/src/wok/config.py.in
@@ -60,6 +60,10 @@ FONTS_PATH = {
 SESSIONSTIMEOUT = 10    # session time out is 10 minutes
 
 
+def get_log_download_path():
+    return os.path.join(paths.state_dir, 'logs')
+
+
 def get_object_store():
     return os.path.join(paths.state_dir, 'objectstore')
 
@@ -188,6 +192,12 @@ class WokConfig(dict):
             'tools.sessions.timeout': SESSIONSTIMEOUT,
             'tools.wokauth.on': False
         },
+        '/data/logs': {
+            'tools.staticdir.on': True,
+            'tools.staticdir.dir': '%s/logs' % paths.state_dir,
+            'tools.nocache.on': False,
+            'tools.wokauth.on': True,
+        },
         '/base64/jquery.base64.js': {
             'tools.staticfile.on': True,
             'tools.staticfile.filename': '%s/base64/jquery.base64.js' %
diff --git a/src/wok/i18n.py b/src/wok/i18n.py
index 82d28d1..e6087f4 100644
--- a/src/wok/i18n.py
+++ b/src/wok/i18n.py
@@ -37,12 +37,14 @@ messages = {
     "WOKASYNC0002E": _("Unable to start task due error: %(err)s"),
     "WOKASYNC0003E": _("Timeout of %(seconds)s seconds expired while running task '%(task)s."),
 
-
     "WOKAUTH0001E": _("Authentication failed for user '%(username)s'. [Error code: %(code)s]"),
     "WOKAUTH0002E": _("You are not authorized to access Kimchi"),
     "WOKAUTH0003E": _("Specify %(item)s to login into Kimchi"),
     "WOKAUTH0005E": _("Invalid LDAP configuration: %(item)s : %(value)s"),
 
+    "WOKLOG0001E": _("Invalid filter parameter. Filter parameters allowed: %(filters)s"),
+    "WOKLOG0002E": _("Creation of log file failed: %(err)s"),
+
     "WOKOBJST0001E": _("Unable to find %(item)s in datastore"),
 
     "WOKUTILS0001E": _("Unable to reach %(url)s. Make sure it is accessible and try again."),
diff --git a/src/wok/reqlogger.py b/src/wok/reqlogger.py
new file mode 100644
index 0000000..b5b22d8
--- /dev/null
+++ b/src/wok/reqlogger.py
@@ -0,0 +1,154 @@
+#
+# Project Wok
+#
+# Copyright IBM Corp, 2016
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+#
+
+import json
+import logging
+import os.path
+
+from datetime import datetime
+from tempfile import NamedTemporaryFile
+from wok.config import get_log_download_path
+
+
+# Log search setup
+FILTER_FIELDS = ['app', 'date', 'download', 'req', 'user']
+LOG_DOWNLOAD_URI = "/data/logs/%s"
+LOG_FORMAT = "[%(date)s %(time)s] %(req)-6s %(app)-11s %(user)s: %(message)s\n"
+
+# Log handler setup
+MAX_FILE_SIZE = 3072000
+NUM_BACKUP_FILES = 1
+WOK_REQUEST_LOGGER = 'wok_request_logger'
+
+
+class RequestParser(object):
+    def __init__(self):
+        logger = logging.getLogger(WOK_REQUEST_LOGGER)
+        self.baseFile = logger.handlers[0].baseFilename
+        self.downloadDir = get_log_download_path()
+
+    def generateLogFile(self, records):
+        """
+        Generates a log-format text file with lines for each record specified.
+        Returns a download URI for the generated file.
+        """
+        try:
+            # sort records chronologically
+            sortedList = sorted(records, key=lambda k: k['date'] + k['time'])
+
+            # generate log file
+            fd = NamedTemporaryFile(mode='w', dir=self.downloadDir,
+                                    suffix='.txt', delete=False)
+
+            with fd:
+                for record in sortedList:
+                    fd.write(LOG_FORMAT % record)
+
+                fd.close()
+        except IOError as e:
+            raise OperationFailed("WOKLOG0002E", {'err': str(e)})
+
+        return LOG_DOWNLOAD_URI % os.path.basename(fd.name)
+
+    def getRecords(self):
+        records = self.getRecordsFromFile(self.baseFile)
+
+        for count in range(NUM_BACKUP_FILES):
+            filename = ".".join([self.baseFile, str(count + 1)])
+            records.extend(self.getRecordsFromFile(filename))
+
+        return records
+
+    def getRecordsFromFile(self, filename):
+        """
+        Returns a list of dict, where each dict corresponds to a request
+        record.
+        """
+        records = []
+
+        if not os.path.exists(filename):
+            return []
+
+        # read records from file
+        try:
+            with open(filename) as f:
+                line = f.readline()
+                while line != "":
+                    data = line.split(">>>")
+                    if len(data) > 1:
+                        record = json.JSONDecoder().decode(data[0])
+                        record['message'] = data[1].strip()
+                        records.append(record)
+
+                    line = f.readline()
+
+            f. close()
+        except IOError as e:
+            raise OperationFailed("WOKLOG0002E", {'err': str(e)})
+
+        return records
+
+    def getFilteredRecords(self, filter_params):
+        """
+        Returns a dict containing the filtered list of request log entries
+        (dicts), and an optional uri for downloading results in a text file.
+        """
+        uri = None
+        results = []
+        records = self.getRecords()
+
+        # ignore unrecognized filter options
+        for key in filter_params.keys():
+            if key not in FILTER_FIELDS:
+                filters = ", ".join(FILTER_FIELDS)
+                raise InvalidParameter("WOKLOG0001E", {"filters": filters})
+
+        download = filter_params.pop('download', False)
+
+        # filter records according to parameters
+        for record in records:
+            if all(key in record and record[key] == val
+                   for key, val in filter_params.iteritems()):
+                results.append(record)
+
+        # download option active: generate text file and provide donwload uri
+        if download and len(results) > 0:
+            uri = self.generateLogFile(results)
+
+        return {'uri': uri, 'records': results}
+
+
+class RequestRecord(object):
+    def __init__(self, message, **kwargs):
+        self.message = message
+        self.kwargs = kwargs
+
+        # register timestamp
+        timestamp = datetime.today()
+        self.kwargs['date'] = timestamp.strftime('%Y-%m-%d')
+        self.kwargs['time'] = timestamp.strftime('%H:%M:%S')
+
+    def __str__(self):
+        info = json.JSONEncoder().encode(self.kwargs)
+        return '%s >>> %s' % (info, self.message)
+
+    def log(self):
+        reqLogger = logging.getLogger(WOK_REQUEST_LOGGER)
+        reqLogger.info(self)
-- 
1.9.1




More information about the Kimchi-devel mailing list