[Kimchi-devel] [PATCH] [Wok 3/7] Log AsyncTask start, success and failure

Lucio Correia luciojhc at linux.vnet.ibm.com
Fri Aug 19 19:37:38 UTC 2016


* Change AsyncTask constructor to receive a dict task_info
instead of adding more parameters
* Handle WokException separately in order to add it in
translatable form to user log

Signed-off-by: Lucio Correia <luciojhc at linux.vnet.ibm.com>
---
 src/wok/asynctask.py | 71 ++++++++++++++++++++++++++++++++++++++++++----------
 src/wok/i18n.py      |  3 +++
 src/wok/reqlogger.py | 20 +++++++++++++--
 3 files changed, 79 insertions(+), 15 deletions(-)

diff --git a/src/wok/asynctask.py b/src/wok/asynctask.py
index 82a91ec..5d32f5e 100644
--- a/src/wok/asynctask.py
+++ b/src/wok/asynctask.py
@@ -24,25 +24,45 @@ import threading
 import traceback
 
 
-from wok.exception import OperationFailed
-from wok.utils import get_next_task_id
+from wok.exception import OperationFailed, WokException
+from wok.reqlogger import RequestRecord
+from wok.reqlogger import TASK_FAILED, TASK_STARTED, TASK_SUCCESS
+from wok.utils import get_next_task_id, get_plugin_from_uri
+
+
+METHOD_TASK = 'TASK'
+MSG_FAILED = 'WOKASYNC0003L'
+MSG_STARTED = 'WOKASYNC0001L'
+MSG_SUCCESS = 'WOKASYNC0002L'
 
 
 def add_task(target_uri, fn, objstore, opaque=None):
     id = get_next_task_id()
-    AsyncTask(id, target_uri, fn, objstore, opaque)
+    task_info = {
+        'id': id,
+        'target_uri': target_uri,
+        'fn': fn,
+        'objstore': objstore,
+        'plugin': get_plugin_from_uri(target_uri),
+        'user': '',
+        'ip': '',
+    }
+    AsyncTask(task_info, opaque)
     return id
 
 
 class AsyncTask(object):
-    def __init__(self, id, target_uri, fn, objstore, opaque=None):
-        if objstore is None:
+    def __init__(self, task_info, opaque=None):
+        if task_info['objstore'] is None:
             raise OperationFailed("WOKASYNC0001E")
 
-        self.id = str(id)
-        self.target_uri = target_uri
-        self.fn = fn
-        self.objstore = objstore
+        # task info
+        self.id = str(task_info['id'])
+        self.target_uri = task_info['target_uri']
+        self.fn = task_info['fn']
+        self.task_info = task_info
+
+        # task context
         self.status = 'running'
         self.message = 'OK'
         self._save_helper()
@@ -52,9 +72,29 @@ class AsyncTask(object):
         self.thread.setDaemon(True)
         self.thread.start()
 
-    def _status_cb(self, message, success=None):
+        # log async task start
+        self._log(MSG_STARTED, TASK_STARTED)
+
+    def _log(self, msgCode, status, exception=None):
+        RequestRecord(
+            self.task_info,
+            exception,
+            app=self.task_info['plugin'],
+            msgCode=msgCode,
+            req=METHOD_TASK,
+            status=status,
+            user=self.task_info['user'],
+            ip=self.task_info['ip']
+        ).log()
+
+    def _status_cb(self, message, success=None, exception=None):
         if success is not None:
-            self.status = 'finished' if success else 'failed'
+            if success:
+                self.status = 'finished'
+                self._log(MSG_SUCCESS, TASK_SUCCESS)
+            else:
+                self.status = 'failed'
+                self._log(MSG_FAILED, TASK_FAILED, exception)
 
         if message.strip():
             self.message = message
@@ -65,7 +105,8 @@ class AsyncTask(object):
         for attr in ('id', 'target_uri', 'message', 'status'):
             obj[attr] = getattr(self, attr)
         try:
-            with self.objstore as session:
+            objstore = self.task_info['objstore']
+            with objstore as session:
                 session.store('task', self.id, obj)
         except Exception as e:
             raise OperationFailed('WOKASYNC0002E', {'err': e.message})
@@ -74,7 +115,11 @@ class AsyncTask(object):
         cherrypy.serving.request = self._cp_request
         try:
             self.fn(cb, opaque)
+        except WokException, e:
+            cherrypy.log.error_log.error("Error in async_task %s " % self.id)
+            cherrypy.log.error_log.error(traceback.format_exc())
+            cb(e.message, success=False, exception=e)
         except Exception, e:
             cherrypy.log.error_log.error("Error in async_task %s " % self.id)
             cherrypy.log.error_log.error(traceback.format_exc())
-            cb(e.message, False)
+            cb(e.message, success=False)
diff --git a/src/wok/i18n.py b/src/wok/i18n.py
index 33107ee..c271446 100644
--- a/src/wok/i18n.py
+++ b/src/wok/i18n.py
@@ -58,6 +58,9 @@ messages = {
     "WOKPROXY0001E": _("Unable to (re)start system's nginx.service. Details: '%(error)s'"),
 
     # These messages (ending with L) are for user log purposes
+    "WOKASYNC0001L": _("Started %(plugin)s task ID %(id)s: %(target_uri)s"),
+    "WOKASYNC0002L": _("Successfully completed %(plugin)s task ID %(id)s: %(target_uri)s"),
+    "WOKASYNC0003L": _("Failed to complete %(plugin)s task ID %(id)s: %(target_uri)s"),
     "WOKCOL0001L": _("Request made on collection"),
     "WOKRES0001L": _("Request made on resource"),
     "WOKROOT0001L": _("User '%(username)s' login"),
diff --git a/src/wok/reqlogger.py b/src/wok/reqlogger.py
index 9f1d2c8..c57b141 100644
--- a/src/wok/reqlogger.py
+++ b/src/wok/reqlogger.py
@@ -39,8 +39,8 @@ from wok.utils import remove_old_files
 FILTER_FIELDS = ['app', 'date', 'ip', 'req', 'status' 'user', 'time']
 LOG_DOWNLOAD_URI = "/data/logs/%s"
 LOG_DOWNLOAD_TIMEOUT = 6
-LOG_FORMAT = "[%(date)s %(time)s %(zone)s] %(req)-6s %(status)s %(app)-11s " \
-             "%(ip)-15s %(user)s: %(message)s\n"
+LOG_FORMAT = "[%(date)s %(time)s %(zone)s] %(req)-6s %(status)-4s %(app)-11s" \
+             " %(ip)-15s %(user)s: %(message)s\n"
 RECORD_TEMPLATE_DICT = {
     'date': '',
     'time': '',
@@ -62,6 +62,16 @@ UNSAFE_REQUEST_PARAMETERS = ['password', 'passwd']
 REQUEST_LOG_FILE = "wok-req.log"
 WOK_REQUEST_LOGGER = "wok_request_logger"
 
+# Task logging
+TASK_FAILED = 1002
+TASK_STARTED = 1000
+TASK_SUCCESS = 1001
+TASK_STATUSES = {
+    TASK_FAILED: 'FAIL',
+    TASK_STARTED: 'INIT',
+    TASK_SUCCESS: 'SUCC',
+}
+
 
 class RequestLogger(object):
     def __init__(self):
@@ -106,6 +116,12 @@ class RequestParser(object):
                 for record in sortedList:
                     asciiRecord = RECORD_TEMPLATE_DICT
                     asciiRecord.update(ascii_dict(record))
+
+                    # log meaning of statuses 1000, 1001, 1002 for clarity
+                    status = int(asciiRecord['status'])
+                    if status in TASK_STATUSES.keys():
+                        asciiRecord['status'] = TASK_STATUSES[status]
+
                     fd.write(LOG_FORMAT % asciiRecord)
 
                 fd.close()
-- 
1.9.1




More information about the Kimchi-devel mailing list