You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by mx...@apache.org on 2017/04/26 13:41:38 UTC

incubator-ariatosca git commit: fixed and reworked alot

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-146-Support-colorful-execution-logging 81bd26a7f -> e3b25d7ad


fixed and reworked alot


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/e3b25d7a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/e3b25d7a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/e3b25d7a

Branch: refs/heads/ARIA-146-Support-colorful-execution-logging
Commit: e3b25d7ade6291293a8483e703cf00315d179797
Parents: 81bd26a
Author: max-orlov <ma...@gigaspaces.com>
Authored: Wed Apr 26 16:41:32 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Wed Apr 26 16:41:32 2017 +0300

----------------------------------------------------------------------
 aria/cli/color.py                    |  52 ++++++---
 aria/cli/config/config.py            |  13 +++
 aria/cli/config/config_template.yaml |  10 +-
 aria/cli/core/aria.py                |   6 +-
 aria/cli/execution_logging.py        | 170 +++++++++++++++++++-----------
 aria/cli/helptexts.py                |   1 +
 6 files changed, 170 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/e3b25d7a/aria/cli/color.py
----------------------------------------------------------------------
diff --git a/aria/cli/color.py b/aria/cli/color.py
index 49675de..99d584f 100644
--- a/aria/cli/color.py
+++ b/aria/cli/color.py
@@ -15,6 +15,7 @@
 from StringIO import StringIO
 
 import colorama
+import re
 
 colorama.init()
 
@@ -25,6 +26,39 @@ def _get_colors(color_type):
             yield (name.lower(), getattr(color_type, name))
 
 
+class StylizedString(object):
+        def __init__(self, str_, schema=None):
+            self._str = str_
+            self._schema = schema
+
+        def __repr__(self):
+            if self._schema:
+                return '{schema}{str}{reset}'.format(
+                    schema=self._schema, str=str(self._str), reset=Color.Style.RESET_ALL)
+            return self._str
+
+        def __add__(self, other):
+            return str(self) + other
+
+        def __radd__(self, other):
+            return other + str(self)
+
+        def color(self, schema):
+            self._schema = schema
+
+        def replace(self, old, new, **kwargs):
+            self._str = self._str.replace(str(old), str(new), **kwargs)
+
+        def format(self, *args, **kwargs):
+            self._str = self._str.format(*args, **kwargs)
+
+        def highlight(self, original_value, schema, original_schema, pattern=None):
+            if pattern is None:
+                return
+            for match in set(re.findall(re.compile(pattern), str(original_value))):
+                self.replace(match, schema + match + Color.Style.RESET_ALL + original_schema)
+
+
 class Color(object):
     Fore = colorama.Fore
     Back = colorama.Back
@@ -37,17 +71,16 @@ class Color(object):
     }
 
     class Schema(object):
-        def __init__(self, **kwargs):
+        def __init__(self, fore=None, back=None, style=None):
             """
             It is possible to provide fore, back and style arguments. each could be either
             the color is lower case letter, or the actual color from colorama.
 
             """
-            assert all(arg in Color._colors for arg in kwargs)
-            self._kwargs = kwargs
+            self._kwargs = dict(fore=fore, back=back, style=style)
             self._str = StringIO()
             for type_, colors in Color._colors.items():
-                value = kwargs.pop(type_, None)
+                value = self._kwargs.get(type_, None)
                 # the former case is if the value is a string, the latter is in case of an object.
                 self._str.write(colors.get(value) or value)
 
@@ -61,12 +94,5 @@ class Color(object):
             return str(other) + str(self)
 
     @classmethod
-    def stylize(cls, str_to_stylize, schema):
-        return schema + str(str_to_stylize) + cls.Style.RESET_ALL
-
-    @classmethod
-    def markup(cls, str_to_stylize, matches, schema):
-        for group_index in xrange(len(matches.regs)):
-            match = matches.group(group_index)
-            str_to_stylize = str_to_stylize.replace(match, schema + match + cls.Back.RESET)
-        return str_to_stylize
+    def stylize(cls, *args, **kwargs):
+        return StylizedString(*args, **kwargs)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/e3b25d7a/aria/cli/config/config.py
----------------------------------------------------------------------
diff --git a/aria/cli/config/config.py b/aria/cli/config/config.py
index 99f46ca..01e757c 100644
--- a/aria/cli/config/config.py
+++ b/aria/cli/config/config.py
@@ -71,3 +71,16 @@ class CliConfig(object):
         @property
         def loggers(self):
             return self._logging.get('loggers', {})
+
+        @property
+        def styling_enabled(self):
+            return self.styles.get('enabled', False)
+
+        @property
+        def styles(self):
+            return self._logging.get('execution', {}).get('styles', {})
+
+        @property
+        def formats(self):
+            return self._logging.get('execution', {}).get('formats', {})
+

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/e3b25d7a/aria/cli/config/config_template.yaml
----------------------------------------------------------------------
diff --git a/aria/cli/config/config_template.yaml b/aria/cli/config/config_template.yaml
index b8bad3b..85b72d1 100644
--- a/aria/cli/config/config_template.yaml
+++ b/aria/cli/config/config_template.yaml
@@ -10,15 +10,15 @@ logging:
     # main logger of the cli. provides basic descriptions for executed operations.
     aria.cli.main: info
 
-  execution_logging:
-    formatting:
+  execution:
+    formats:
       # According to verbosity level 0 - no verbose. 3 - high verbose
       0: '{message}'
       1: '{timestamp:%H:%M:%S} | {level[0]} | {message}'
       2: '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {message}'
       3: '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {inputs} | {message}'
 
-    styling:
+    styles:
       enabled: true
 
       level:
@@ -45,7 +45,3 @@ logging:
         error: {'fore': 'red'}
 
       marker: 'lightyellow_ex'
-      final_states:
-          success: {'fore': 'green'}
-          cancel: {'fore': 'yellow'}
-          fail: {'fore': 'red'}

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/e3b25d7a/aria/cli/core/aria.py
----------------------------------------------------------------------
diff --git a/aria/cli/core/aria.py b/aria/cli/core/aria.py
index 6436c3e..ed6afa1 100644
--- a/aria/cli/core/aria.py
+++ b/aria/cli/core/aria.py
@@ -426,13 +426,13 @@ class Options(object):
             help=helptexts.SERVICE_ID)
 
     @staticmethod
-    def mark_pattern(default=None):
+    def mark_pattern():
         return click.option(
             '-m',
             '--mark-pattern',
-            help='pattern this',
+            help=helptexts.MARK_PATTERN,
             type=str,
-            default=default
+            required=False
         )
 
 options = Options()

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/e3b25d7a/aria/cli/execution_logging.py
----------------------------------------------------------------------
diff --git a/aria/cli/execution_logging.py b/aria/cli/execution_logging.py
index 66c7d9c..022eeeb 100644
--- a/aria/cli/execution_logging.py
+++ b/aria/cli/execution_logging.py
@@ -22,6 +22,7 @@ from .color import Color
 from .env import env
 
 
+FIELD_TYPE = 'field_type'
 LEVEL = 'level'
 TIMESTAMP = 'timestamp'
 MESSAGE = 'message'
@@ -47,77 +48,122 @@ _IMPLEMENTATION_PATTERN = '.*({implementation.*?}).*'
 _INPUTS_PATTERN = '.*({inputs.*?}).*'
 
 _PATTERNS = {
-    SUCCESS_STATE: re.compile(_SUCCESSFUL_EXECUTION_PATTERN),
-    CANCEL_STATE: re.compile(_CANCELED_EXECUTION_PATTERN),
-    FAIL_STATE: re.compile(_FAILED_EXECUTION_PATTERN),
-
-    IMPLEMENTATION: re.compile(_IMPLEMENTATION_PATTERN),
-    LEVEL: re.compile(_LEVEL_PATTERN),
-    MESSAGE: re.compile(_MESSAGE_PATTERN),
-    INPUTS: re.compile(_INPUTS_PATTERN),
-    TIMESTAMP: re.compile(_TIMESTAMP_PATTERN)
+    FINAL_STATES: {
+        SUCCESS_STATE: re.compile(_SUCCESSFUL_EXECUTION_PATTERN),
+        CANCEL_STATE: re.compile(_CANCELED_EXECUTION_PATTERN),
+        FAIL_STATE: re.compile(_FAILED_EXECUTION_PATTERN),
+    },
+    FIELD_TYPE: {
+        IMPLEMENTATION: re.compile(_IMPLEMENTATION_PATTERN),
+        LEVEL: re.compile(_LEVEL_PATTERN),
+        MESSAGE: re.compile(_MESSAGE_PATTERN),
+        INPUTS: re.compile(_INPUTS_PATTERN),
+        TIMESTAMP: re.compile(_TIMESTAMP_PATTERN)
+    }
 }
 
+_FINAL_STATES = {
+    SUCCESS_STATE: Color.Fore.GREEN,
+    CANCEL_STATE: Color.Fore.YELLOW,
+    FAIL_STATE: Color.Fore.RED
+}
+
+_DEFAULT_STYLE = {
+    LEVEL: {
+        'info': {'fore': 'lightmagenta_ex'},
+        'debug': {'fore': 'lightmagenta_ex', 'style': 'dim'},
+        'error': {'fore': 'red', 'style': 'bright'},
+    },
+    TIMESTAMP: {
+        'info': {'fore': 'lightmagenta_ex'},
+        'debug': {'fore': 'lightmagenta_ex', 'style': 'dim'},
+        'error': {'fore': 'red', 'style': 'bright'},
+    },
+    MESSAGE: {
+        'info': {'fore': 'lightblue_ex'},
+        'debug': {'fore': 'lightblue_ex', 'style': 'dim'},
+        'error': {'fore': 'red', 'style': 'bright'},
+    },
+    IMPLEMENTATION:{
+        'info': {'fore': 'lightblack_ex'},
+        'debug': {'fore': 'lightblack_ex', 'style': 'dim'},
+        'error': {'fore': 'red', 'style': 'bright'},
+    },
+    INPUTS: {
+        'info': {'fore': 'blue'},
+        'debug': {'fore': 'blue', 'style': 'dim'},
+        'error': {'fore': 'red', 'style': 'bright'},
+    },
+    TRACEBACK: {'error': {'fore': 'red'}},
+
+    MARKER: 'lightyellow_ex'
+}
 
 class _StylizedLogs(object):
 
     def _update_implementation(self, str_, implementation, log_item, mark_pattern=None):
-        str_ = self._stylize(str_, implementation, log_item, IMPLEMENTATION)
-        return self._markup(str_, implementation, mark_pattern)
+        schema = self._stylize(str_, implementation, log_item, IMPLEMENTATION, mark_pattern)
 
     def _update_inputs(self, str_, inputs, log_item, mark_pattern=None):
-        str_ = self._stylize(str_, inputs, log_item, INPUTS)
-        return self._markup(str_, inputs, mark_pattern)
+        self._stylize(str_, inputs, log_item, INPUTS, mark_pattern)
 
     def _update_timestamp(self, str_, timestamp, log_item):
-        return self._stylize(str_, timestamp, log_item, TIMESTAMP)
+        self._stylize(str_, timestamp, log_item, TIMESTAMP)
 
-    def _update_message(self, str_, message, log_item, mark_pattern):
-        str_ = self._stylize(str_, message, log_item, MESSAGE)
-        return self._markup(str_, message, mark_pattern)
-
-    def _get_traceback(self, traceback, log_item):
-        schema = Color.Schema(**self._styles[TRACEBACK].get(log_item.level.lower(), {}))
-        return Color.stylize(traceback, schema)
+    def _update_message(self, str_, message, log_item, mark_pattern=None):
+        self._stylize(str_, message, log_item, MESSAGE, mark_pattern)
 
     def _update_level(self, str_, log_item):
-        return self._stylize(str_, log_item.level[0], log_item, LEVEL)
+        self._stylize(str_, log_item.level[0], log_item, LEVEL)
 
-    def _stylize(self, str_, msg, log_item, msg_type):
-        matched_str = self._find_pattern(_PATTERNS[msg_type], str_)
+    def _stylize(self, stylized_str, msg, log_item, msg_type, mark_pattern=None):
+        matched_str = self._find_pattern(_PATTERNS[FIELD_TYPE][msg_type], stylized_str  ._str)
         if not matched_str:
-            return str_
+            return stylized_str
 
         # if Styling was disabled
         if not self._is_styling_enabled:
-            return str_.replace(matched_str, matched_str.format(**{msg_type: msg}))
-
-        schema = Color.Schema(
-            **(self._end_execution_schema(log_item.msg) or
-               self._styles[msg_type].get(log_item.level.lower()) or
-               {})
-        )
-        colored_string = Color.stylize(matched_str, schema)
-        return str_.replace(matched_str, colored_string.format(**{msg_type: msg}))
-
-    def _markup(self, str_, original_message, mark_pattern):
-        if mark_pattern is None:
-            return str_
-        else:
-            regex_pattern = re.compile(mark_pattern)
-            matches = re.search(regex_pattern, str(original_message))
-            if not matches:
-                return str_
-            return Color.markup(str_, matches, Color.Schema(back=self._styles[MARKER]))
+            return stylized_str.replace(matched_str, matched_str.format(**{msg_type: msg}))
+
+        # If the log is not of a final workflow message, it could be configured through the
+        # config file. Thus it should be instantiated from the dict provided.
+        schema = self._resolve_schema(msg_type, log_item)
+        substring = Color.stylize(matched_str)
+        substring.color(schema or '')
+        substring.format(**{msg_type: msg})
+        substring.highlight(msg, self._marker_schema, schema, mark_pattern)
+        stylized_str.replace(matched_str, substring)
+
+    def _get_traceback(self, traceback, log_item, mark_pattern):
+        schema = Color.Schema(**self._styles[TRACEBACK].get(log_item.level.lower(), {}))
+        stylized_string = Color.stylize(traceback, schema)
+        stylized_string.highlight(traceback, self._marker_schema, schema, mark_pattern)
+        return stylized_string
 
     def _end_execution_schema(self, original_message):
         if not self.is_workflow_log:
             return
-        for state, pattern in _PATTERNS.items():
+        for state, pattern in _PATTERNS[FINAL_STATES].items():
             if re.match(pattern, original_message):
-                return self._styles[FINAL_STATES][state]
+                return _FINAL_STATES[state]
 
-    def _find_pattern(self, pattern, field_value):
+    def _resolve_schema(self, msg_type, log_item):
+        schema = self._end_execution_schema(log_item.msg)
+
+        if schema is None:
+            typed_schema_config = self._styles[msg_type].get(log_item.level.lower())
+            user_default_schema_config = self._styles[msg_type].get('default')
+            aria_schema_config = _DEFAULT_STYLE[msg_type].get(log_item.level.lower())
+            schema = Color.Schema(**(typed_schema_config or
+                                     user_default_schema_config or
+                                     aria_schema_config))
+
+        return schema
+
+
+    @staticmethod
+    def _find_pattern(pattern, field_value):
+        # TODO: this finds the matching field type according to a pattern
         match = re.match(pattern, field_value)
         if match:
             return match.group(1)
@@ -128,15 +174,19 @@ class _StylizedLogs(object):
 
     @property
     def _format(self):
-        return env.config._config['logging']['execution_logging']['formatting'][self._verbosity_level]
+        return env.config.logging.formats[self._verbosity_level]
 
     @property
     def _styles(self):
-        return env.config._config['logging']['execution_logging']['styling']
+        return env.config.logging.styles
 
     @property
     def _is_styling_enabled(self):
-        return env.config._config['logging']['execution_logging']['styling'].get('enabled', False)
+        return env.config.logging.styling_enabled
+
+    @property
+    def _marker_schema(self):
+        return Color.Schema(back=self._styles[MARKER])
 
     def __call__(self, item, mark_pattern):
 
@@ -153,18 +203,20 @@ class _StylizedLogs(object):
             self.is_workflow_log = True
 
         # TODO: use the is_workflow_log
-        str_ = self._update_level(self._format, item)
-        str_ = self._update_timestamp(str_, item.created_at, item)
-        str_ = self._update_message(str_, item.msg, item, mark_pattern)
-        str_ = self._update_inputs(str_, inputs, item, mark_pattern)
-        str_ = self._update_implementation(str_, implementation, item, mark_pattern)
-
-        msg = StringIO(str_)
+        stylized_str = Color.stylize(self._format)
+        self._update_level(stylized_str, item)
+        self._update_timestamp(stylized_str, item.created_at, item)
+        self._update_message(stylized_str, item.msg, item, mark_pattern)
+        self._update_inputs(stylized_str, inputs, item, mark_pattern)
+        self._update_implementation(stylized_str, implementation, item, mark_pattern)
+
+        msg = StringIO()
+        msg.write(str(stylized_str))
         # Add the exception and the error msg.
         if item.traceback and env.logging.verbosity_level >= logger.MEDIUM_VERBOSE:
             msg.write(os.linesep)
-            for line in item.traceback.splitlines(True):
-                msg.write(self._get_traceback('\t' + '|' + line, item))
+            msg.writelines(self._get_traceback('\t' + '|' + line, item, mark_pattern)
+                           for line in item.traceback.splitlines(True))
 
         return msg.getvalue()
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/e3b25d7a/aria/cli/helptexts.py
----------------------------------------------------------------------
diff --git a/aria/cli/helptexts.py b/aria/cli/helptexts.py
index 1a3f6c0..8641822 100644
--- a/aria/cli/helptexts.py
+++ b/aria/cli/helptexts.py
@@ -47,3 +47,4 @@ IGNORE_AVAILABLE_NODES = "Delete the service even if it has available nodes"
 SORT_BY = "Key for sorting the list"
 DESCENDING = "Sort list in descending order [default: False]"
 JSON_OUTPUT = "Output logs in a consumable JSON format"
+MARK_PATTERN = "Mark a regex pattern in the logs"