1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 Formatting for ``executions`` sub-commands.
22 from StringIO import StringIO
23 from functools import partial
32 FIELD_TYPE = 'field_type'
34 TIMESTAMP = 'timestamp'
36 IMPLEMENTATION = 'implementation'
38 TRACEBACK = 'traceback'
41 FINAL_STATES = 'final_states'
42 SUCCESS_STATE = 'succeeded'
43 CANCEL_STATE = 'canceled'
46 _EXECUTION_PATTERN = "\'.*\' workflow execution {0}".format
47 # In order to be able to format a string into this regex pattern, we need to provide support
48 # in adding this string into double curly brackets. This is an issue with python format, so we add
49 # this via format itself.
50 _FIELD_TYPE_PATTERN = partial('.*({starting}{0}{closing}).*'.format, starting='{', closing='.*?}')
54 SUCCESS_STATE: re.compile(_EXECUTION_PATTERN(SUCCESS_STATE)),
55 CANCEL_STATE: re.compile(_EXECUTION_PATTERN(CANCEL_STATE)),
56 FAIL_STATE: re.compile(_EXECUTION_PATTERN(FAIL_STATE)),
59 IMPLEMENTATION: re.compile(_FIELD_TYPE_PATTERN(IMPLEMENTATION)),
60 LEVEL: re.compile(_FIELD_TYPE_PATTERN(LEVEL)),
61 MESSAGE: re.compile(_FIELD_TYPE_PATTERN(MESSAGE)),
62 INPUTS: re.compile(_FIELD_TYPE_PATTERN(INPUTS)),
63 TIMESTAMP: re.compile(_FIELD_TYPE_PATTERN(TIMESTAMP))
68 SUCCESS_STATE: color.Colors.Fore.GREEN,
69 CANCEL_STATE: color.Colors.Fore.YELLOW,
70 FAIL_STATE: color.Colors.Fore.RED
75 'default': {'fore': 'lightmagenta_ex'},
76 'error': {'fore': 'red', 'style': 'bright'},
79 'default': {'fore': 'lightmagenta_ex'},
80 'error': {'fore': 'red', 'style': 'bright'},
83 'default': {'fore': 'lightblue_ex'},
84 'error': {'fore': 'red', 'style': 'bright'},
87 'default': {'fore': 'lightblack_ex'},
88 'error': {'fore': 'red', 'style': 'bright'},
91 'default': {'fore': 'blue'},
92 'error': {'fore': 'red', 'style': 'bright'},
94 TRACEBACK: {'default': {'fore': 'red'}},
96 MARKER: 'lightyellow_ex'
100 logger.NO_VERBOSE: '{message}',
101 logger.LOW_VERBOSE: '{timestamp:%H:%M:%S} | {level[0]} | {message}',
102 logger.MEDIUM_VERBOSE: '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {message}',
104 '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {inputs} | {message}'
108 def stylize_log(item, mark_pattern):
113 implementation = item.task.function
114 inputs = dict(arg.unwrapped for arg in item.task.arguments.itervalues())
117 implementation = item.execution.workflow_name
118 inputs = dict(inp.unwrapped for inp in item.execution.inputs.itervalues())
120 stylized_str = color.StringStylizer(_get_format())
121 _populate_level(stylized_str, item)
122 _populate_timestamp(stylized_str, item)
123 _populate_message(stylized_str, item, mark_pattern)
124 _populate_inputs(stylized_str, inputs, item, mark_pattern)
125 _populate_implementation(stylized_str, implementation, item, mark_pattern)
128 msg.write(str(stylized_str))
129 # Add the exception and the error msg.
130 if item.traceback and env.logging.verbosity_level >= logger.MEDIUM_VERBOSE:
131 msg.write(os.linesep)
132 msg.writelines(_color_traceback('\t' + '|' + line, item, mark_pattern)
133 for line in item.traceback.splitlines(True))
135 return msg.getvalue()
138 def log(item, mark_pattern=None, *args, **kwargs):
139 leveled_log = getattr(env.logging.logger, item.level.lower())
140 return leveled_log(stylize_log(item, mark_pattern), *args, **kwargs)
143 def log_list(iterator, mark_pattern=None):
145 for item in iterator:
146 log(item, mark_pattern)
152 return (env.config.logging.execution.formats.get(env.logging.verbosity_level) or
153 _DEFAULT_FORMATS.get(env.logging.verbosity_level))
156 def _get_styles(field_type):
157 return env.config.logging.execution.colors[field_type]
160 def _is_color_enabled():
161 # If styling is enabled and the current log_item isn't final string
162 return env.config.logging.execution.colors_enabled
165 def _get_marker_schema():
166 return color.ColorSpec(back=_get_styles(MARKER))
169 def _populate_implementation(str_, implementation, log_item, mark_pattern=None):
170 _stylize(str_, implementation, log_item, IMPLEMENTATION, mark_pattern)
173 def _populate_inputs(str_, inputs, log_item, mark_pattern=None):
174 _stylize(str_, inputs, log_item, INPUTS, mark_pattern)
177 def _populate_timestamp(str_, log_item):
178 _stylize(str_, log_item.created_at, log_item, TIMESTAMP)
181 def _populate_message(str_, log_item, mark_pattern=None):
182 _stylize(str_, log_item.msg, log_item, MESSAGE, mark_pattern)
185 def _populate_level(str_, log_item):
186 _stylize(str_, log_item.level[0], log_item, LEVEL)
189 def _stylize(stylized_str, msg, log_item, msg_type, mark_pattern=None):
190 match = re.match(_PATTERNS[FIELD_TYPE][msg_type], stylized_str._str)
193 matched_substr = match.group(1)
195 substring = color.StringStylizer(matched_substr)
198 substring.format(**{msg_type: msg})
200 if _is_color_enabled():
202 substring.color(_resolve_schema(msg_type, log_item))
203 if not _is_end_execution_log(log_item):
204 # handle highlighting
205 substring.highlight(mark_pattern, _get_marker_schema())
207 stylized_str.replace(matched_substr, substring)
210 def _color_traceback(traceback, log_item, mark_pattern):
211 if _is_color_enabled():
212 stylized_string = color.StringStylizer(traceback, _resolve_schema(TRACEBACK, log_item))
213 stylized_string.highlight(mark_pattern, _get_marker_schema())
214 return stylized_string
218 def _is_end_execution_log(log_item):
219 return not log_item.task and bool(_end_execution_schema(log_item))
222 def _end_execution_schema(log_item):
223 for state, pattern in _PATTERNS[FINAL_STATES].items():
224 if re.match(pattern, log_item.msg):
225 return _FINAL_STATES[state]
228 def _resolve_schema(msg_type, log_item):
229 if _is_end_execution_log(log_item):
230 return _end_execution_schema(log_item)
232 return color.ColorSpec(
234 # retrieve the schema from the user config according to the level
235 _get_styles(msg_type).get(log_item.level.lower()) or
236 # retrieve the default schema from the user config
237 _get_styles(msg_type).get('default') or
238 # retrieve the schema from the aria default config according to the level
239 _DEFAULT_COLORS[msg_type].get(log_item.level.lower()) or
240 # retrieve the default schema from the aria default config
241 _DEFAULT_COLORS[msg_type].get('default')