summaryrefslogtreecommitdiffstats
path: root/azure/aria/aria-extension-cloudify/src/aria/aria/cli/execution_logging.py
diff options
context:
space:
mode:
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/cli/execution_logging.py')
-rw-r--r--azure/aria/aria-extension-cloudify/src/aria/aria/cli/execution_logging.py243
1 files changed, 243 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/cli/execution_logging.py b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/execution_logging.py
new file mode 100644
index 0000000..915038b
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/src/aria/aria/cli/execution_logging.py
@@ -0,0 +1,243 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Formatting for ``executions`` sub-commands.
+"""
+
+import os
+import re
+from StringIO import StringIO
+from functools import partial
+
+from . import (
+ logger,
+ color
+)
+from .env import env
+
+
+FIELD_TYPE = 'field_type'
+LEVEL = 'level'
+TIMESTAMP = 'timestamp'
+MESSAGE = 'message'
+IMPLEMENTATION = 'implementation'
+INPUTS = 'inputs'
+TRACEBACK = 'traceback'
+MARKER = 'marker'
+
+FINAL_STATES = 'final_states'
+SUCCESS_STATE = 'succeeded'
+CANCEL_STATE = 'canceled'
+FAIL_STATE = 'failed'
+
+_EXECUTION_PATTERN = "\'.*\' workflow execution {0}".format
+# In order to be able to format a string into this regex pattern, we need to provide support
+# in adding this string into double curly brackets. This is an issue with python format, so we add
+# this via format itself.
+_FIELD_TYPE_PATTERN = partial('.*({starting}{0}{closing}).*'.format, starting='{', closing='.*?}')
+
+_PATTERNS = {
+ FINAL_STATES: {
+ SUCCESS_STATE: re.compile(_EXECUTION_PATTERN(SUCCESS_STATE)),
+ CANCEL_STATE: re.compile(_EXECUTION_PATTERN(CANCEL_STATE)),
+ FAIL_STATE: re.compile(_EXECUTION_PATTERN(FAIL_STATE)),
+ },
+ FIELD_TYPE: {
+ IMPLEMENTATION: re.compile(_FIELD_TYPE_PATTERN(IMPLEMENTATION)),
+ LEVEL: re.compile(_FIELD_TYPE_PATTERN(LEVEL)),
+ MESSAGE: re.compile(_FIELD_TYPE_PATTERN(MESSAGE)),
+ INPUTS: re.compile(_FIELD_TYPE_PATTERN(INPUTS)),
+ TIMESTAMP: re.compile(_FIELD_TYPE_PATTERN(TIMESTAMP))
+ }
+}
+
+_FINAL_STATES = {
+ SUCCESS_STATE: color.Colors.Fore.GREEN,
+ CANCEL_STATE: color.Colors.Fore.YELLOW,
+ FAIL_STATE: color.Colors.Fore.RED
+}
+
+_DEFAULT_COLORS = {
+ LEVEL: {
+ 'default': {'fore': 'lightmagenta_ex'},
+ 'error': {'fore': 'red', 'style': 'bright'},
+ },
+ TIMESTAMP: {
+ 'default': {'fore': 'lightmagenta_ex'},
+ 'error': {'fore': 'red', 'style': 'bright'},
+ },
+ MESSAGE: {
+ 'default': {'fore': 'lightblue_ex'},
+ 'error': {'fore': 'red', 'style': 'bright'},
+ },
+ IMPLEMENTATION:{
+ 'default': {'fore': 'lightblack_ex'},
+ 'error': {'fore': 'red', 'style': 'bright'},
+ },
+ INPUTS: {
+ 'default': {'fore': 'blue'},
+ 'error': {'fore': 'red', 'style': 'bright'},
+ },
+ TRACEBACK: {'default': {'fore': 'red'}},
+
+ MARKER: 'lightyellow_ex'
+}
+
+_DEFAULT_FORMATS = {
+ logger.NO_VERBOSE: '{message}',
+ logger.LOW_VERBOSE: '{timestamp:%H:%M:%S} | {level[0]} | {message}',
+ logger.MEDIUM_VERBOSE: '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {message}',
+ logger.HIGH_VERBOSE:
+ '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {inputs} | {message}'
+}
+
+
+def stylize_log(item, mark_pattern):
+
+ # implementation
+ if item.task:
+ # operation task
+ implementation = item.task.function
+ inputs = dict(arg.unwrapped for arg in item.task.arguments.itervalues())
+ else:
+ # execution task
+ implementation = item.execution.workflow_name
+ inputs = dict(inp.unwrapped for inp in item.execution.inputs.itervalues())
+
+ stylized_str = color.StringStylizer(_get_format())
+ _populate_level(stylized_str, item)
+ _populate_timestamp(stylized_str, item)
+ _populate_message(stylized_str, item, mark_pattern)
+ _populate_inputs(stylized_str, inputs, item, mark_pattern)
+ _populate_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)
+ msg.writelines(_color_traceback('\t' + '|' + line, item, mark_pattern)
+ for line in item.traceback.splitlines(True))
+
+ return msg.getvalue()
+
+
+def log(item, mark_pattern=None, *args, **kwargs):
+ leveled_log = getattr(env.logging.logger, item.level.lower())
+ return leveled_log(stylize_log(item, mark_pattern), *args, **kwargs)
+
+
+def log_list(iterator, mark_pattern=None):
+ any_logs = False
+ for item in iterator:
+ log(item, mark_pattern)
+ any_logs = True
+ return any_logs
+
+
+def _get_format():
+ return (env.config.logging.execution.formats.get(env.logging.verbosity_level) or
+ _DEFAULT_FORMATS.get(env.logging.verbosity_level))
+
+
+def _get_styles(field_type):
+ return env.config.logging.execution.colors[field_type]
+
+
+def _is_color_enabled():
+ # If styling is enabled and the current log_item isn't final string
+ return env.config.logging.execution.colors_enabled
+
+
+def _get_marker_schema():
+ return color.ColorSpec(back=_get_styles(MARKER))
+
+
+def _populate_implementation(str_, implementation, log_item, mark_pattern=None):
+ _stylize(str_, implementation, log_item, IMPLEMENTATION, mark_pattern)
+
+
+def _populate_inputs(str_, inputs, log_item, mark_pattern=None):
+ _stylize(str_, inputs, log_item, INPUTS, mark_pattern)
+
+
+def _populate_timestamp(str_, log_item):
+ _stylize(str_, log_item.created_at, log_item, TIMESTAMP)
+
+
+def _populate_message(str_, log_item, mark_pattern=None):
+ _stylize(str_, log_item.msg, log_item, MESSAGE, mark_pattern)
+
+
+def _populate_level(str_, log_item):
+ _stylize(str_, log_item.level[0], log_item, LEVEL)
+
+
+def _stylize(stylized_str, msg, log_item, msg_type, mark_pattern=None):
+ match = re.match(_PATTERNS[FIELD_TYPE][msg_type], stylized_str._str)
+ if not match:
+ return
+ matched_substr = match.group(1)
+
+ substring = color.StringStylizer(matched_substr)
+
+ # handle format
+ substring.format(**{msg_type: msg})
+
+ if _is_color_enabled():
+ # handle color
+ substring.color(_resolve_schema(msg_type, log_item))
+ if not _is_end_execution_log(log_item):
+ # handle highlighting
+ substring.highlight(mark_pattern, _get_marker_schema())
+
+ stylized_str.replace(matched_substr, substring)
+
+
+def _color_traceback(traceback, log_item, mark_pattern):
+ if _is_color_enabled():
+ stylized_string = color.StringStylizer(traceback, _resolve_schema(TRACEBACK, log_item))
+ stylized_string.highlight(mark_pattern, _get_marker_schema())
+ return stylized_string
+ return traceback
+
+
+def _is_end_execution_log(log_item):
+ return not log_item.task and bool(_end_execution_schema(log_item))
+
+
+def _end_execution_schema(log_item):
+ for state, pattern in _PATTERNS[FINAL_STATES].items():
+ if re.match(pattern, log_item.msg):
+ return _FINAL_STATES[state]
+
+
+def _resolve_schema(msg_type, log_item):
+ if _is_end_execution_log(log_item):
+ return _end_execution_schema(log_item)
+ else:
+ return color.ColorSpec(
+ **(
+ # retrieve the schema from the user config according to the level
+ _get_styles(msg_type).get(log_item.level.lower()) or
+ # retrieve the default schema from the user config
+ _get_styles(msg_type).get('default') or
+ # retrieve the schema from the aria default config according to the level
+ _DEFAULT_COLORS[msg_type].get(log_item.level.lower()) or
+ # retrieve the default schema from the aria default config
+ _DEFAULT_COLORS[msg_type].get('default')
+ )
+ )