vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / cli / execution_logging.py
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
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15
16 """
17 Formatting for ``executions`` sub-commands.
18 """
19
20 import os
21 import re
22 from StringIO import StringIO
23 from functools import partial
24
25 from . import (
26     logger,
27     color
28 )
29 from .env import env
30
31
32 FIELD_TYPE = 'field_type'
33 LEVEL = 'level'
34 TIMESTAMP = 'timestamp'
35 MESSAGE = 'message'
36 IMPLEMENTATION = 'implementation'
37 INPUTS = 'inputs'
38 TRACEBACK = 'traceback'
39 MARKER = 'marker'
40
41 FINAL_STATES = 'final_states'
42 SUCCESS_STATE = 'succeeded'
43 CANCEL_STATE = 'canceled'
44 FAIL_STATE = 'failed'
45
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='.*?}')
51
52 _PATTERNS = {
53     FINAL_STATES: {
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)),
57     },
58     FIELD_TYPE: {
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))
64     }
65 }
66
67 _FINAL_STATES = {
68     SUCCESS_STATE: color.Colors.Fore.GREEN,
69     CANCEL_STATE: color.Colors.Fore.YELLOW,
70     FAIL_STATE: color.Colors.Fore.RED
71 }
72
73 _DEFAULT_COLORS = {
74     LEVEL: {
75         'default': {'fore': 'lightmagenta_ex'},
76         'error': {'fore': 'red', 'style': 'bright'},
77     },
78     TIMESTAMP: {
79         'default': {'fore': 'lightmagenta_ex'},
80         'error': {'fore': 'red', 'style': 'bright'},
81     },
82     MESSAGE: {
83         'default': {'fore': 'lightblue_ex'},
84         'error': {'fore': 'red', 'style': 'bright'},
85     },
86     IMPLEMENTATION:{
87         'default': {'fore': 'lightblack_ex'},
88         'error': {'fore': 'red', 'style': 'bright'},
89     },
90     INPUTS: {
91         'default': {'fore': 'blue'},
92         'error': {'fore': 'red', 'style': 'bright'},
93     },
94     TRACEBACK: {'default': {'fore': 'red'}},
95
96     MARKER: 'lightyellow_ex'
97 }
98
99 _DEFAULT_FORMATS = {
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}',
103     logger.HIGH_VERBOSE:
104         '{timestamp:%H:%M:%S} | {level[0]} | {implementation} | {inputs} | {message}'
105 }
106
107
108 def stylize_log(item, mark_pattern):
109
110     # implementation
111     if item.task:
112         # operation task
113         implementation = item.task.function
114         inputs = dict(arg.unwrapped for arg in item.task.arguments.itervalues())
115     else:
116         # execution task
117         implementation = item.execution.workflow_name
118         inputs = dict(inp.unwrapped for inp in item.execution.inputs.itervalues())
119
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)
126
127     msg = StringIO()
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))
134
135     return msg.getvalue()
136
137
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)
141
142
143 def log_list(iterator, mark_pattern=None):
144     any_logs = False
145     for item in iterator:
146         log(item, mark_pattern)
147         any_logs = True
148     return any_logs
149
150
151 def _get_format():
152     return (env.config.logging.execution.formats.get(env.logging.verbosity_level) or
153             _DEFAULT_FORMATS.get(env.logging.verbosity_level))
154
155
156 def _get_styles(field_type):
157     return env.config.logging.execution.colors[field_type]
158
159
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
163
164
165 def _get_marker_schema():
166     return color.ColorSpec(back=_get_styles(MARKER))
167
168
169 def _populate_implementation(str_, implementation, log_item, mark_pattern=None):
170     _stylize(str_, implementation, log_item, IMPLEMENTATION, mark_pattern)
171
172
173 def _populate_inputs(str_, inputs, log_item, mark_pattern=None):
174     _stylize(str_, inputs, log_item, INPUTS, mark_pattern)
175
176
177 def _populate_timestamp(str_, log_item):
178     _stylize(str_, log_item.created_at, log_item, TIMESTAMP)
179
180
181 def _populate_message(str_, log_item, mark_pattern=None):
182     _stylize(str_, log_item.msg, log_item, MESSAGE, mark_pattern)
183
184
185 def _populate_level(str_, log_item):
186     _stylize(str_, log_item.level[0], log_item, LEVEL)
187
188
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)
191     if not match:
192         return
193     matched_substr = match.group(1)
194
195     substring = color.StringStylizer(matched_substr)
196
197     # handle format
198     substring.format(**{msg_type: msg})
199
200     if _is_color_enabled():
201         # handle color
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())
206
207     stylized_str.replace(matched_substr, substring)
208
209
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
215     return traceback
216
217
218 def _is_end_execution_log(log_item):
219     return not log_item.task and bool(_end_execution_schema(log_item))
220
221
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]
226
227
228 def _resolve_schema(msg_type, log_item):
229     if _is_end_execution_log(log_item):
230         return _end_execution_schema(log_item)
231     else:
232         return color.ColorSpec(
233             **(
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')
242             )
243         )