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"