Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 4860D200C86 for ; Tue, 25 Apr 2017 18:24:17 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 473D7160BB3; Tue, 25 Apr 2017 16:24:17 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 39A74160BBA for ; Tue, 25 Apr 2017 18:24:16 +0200 (CEST) Received: (qmail 26948 invoked by uid 500); 25 Apr 2017 16:24:15 -0000 Mailing-List: contact dev-help@ariatosca.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ariatosca.incubator.apache.org Delivered-To: mailing list dev@ariatosca.incubator.apache.org Received: (qmail 26848 invoked by uid 99); 25 Apr 2017 16:24:14 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 25 Apr 2017 16:24:14 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id 8C5D6C31EB for ; Tue, 25 Apr 2017 16:24:14 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -100.001 X-Spam-Level: X-Spam-Status: No, score=-100.001 tagged_above=-999 required=6.31 tests=[RP_MATCHES_RCVD=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001, USER_IN_WHITELIST=-100] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id rQAlaO2AthZK for ; Tue, 25 Apr 2017 16:24:13 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with ESMTP id 310015FDBA for ; Tue, 25 Apr 2017 16:24:08 +0000 (UTC) Received: from jira-lw-us.apache.org (unknown [207.244.88.139]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 40A5FE0C0F for ; Tue, 25 Apr 2017 16:24:07 +0000 (UTC) Received: from jira-lw-us.apache.org (localhost [127.0.0.1]) by jira-lw-us.apache.org (ASF Mail Server at jira-lw-us.apache.org) with ESMTP id 126D221E15 for ; Tue, 25 Apr 2017 16:24:06 +0000 (UTC) Date: Tue, 25 Apr 2017 16:24:06 +0000 (UTC) From: "ASF GitHub Bot (JIRA)" To: dev@ariatosca.incubator.apache.org Message-ID: In-Reply-To: References: Subject: [jira] [Commented] (ARIA-146) Support colorful execution logging MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-JIRA-FingerPrint: 30527f35849b9dde25b450d4833f0394 archived-at: Tue, 25 Apr 2017 16:24:17 -0000 [ https://issues.apache.org/jira/browse/ARIA-146?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15983170#comment-15983170 ] ASF GitHub Bot commented on ARIA-146: ------------------------------------- Github user mxmrlv commented on a diff in the pull request: https://github.com/apache/incubator-ariatosca/pull/109#discussion_r113233667 --- Diff: aria/cli/execution_logging.py --- @@ -12,62 +12,208 @@ # 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. - +import os +import re from StringIO import StringIO +from contextlib import contextmanager from . import logger +from .color import Color from .env import env + +LEVEL = 'level' +TIMESTAMP = 'timestamp' +MESSAGE = 'message' +IMPLEMENTATION = 'implementation' +INPUTS = 'inputs' +TRACEBACK = 'traceback' +MARKER = 'marker' + +FINAL_STATES = 'final_states' +SUCCESS_STATE = 'success' +CANCEL_STATE = 'cancel' +FAIL_STATE = 'fail' + + +_EXECUTION_BASE_PATTERN = "\'.*\' workflow execution " +_SUCCESSFUL_EXECUTION_PATTERN = _EXECUTION_BASE_PATTERN + "succeeded" +_FAILED_EXECUTION_PATTERN = _EXECUTION_BASE_PATTERN + "failed" +_CANCELED_EXECUTION_PATTERN = _EXECUTION_BASE_PATTERN + "canceled" + DEFAULT_FORMATTING = { - logger.NO_VERBOSE: {'message': '{item.msg}'}, + logger.NO_VERBOSE: {'message': '{message}'}, logger.LOW_VERBOSE: { - 'message': '{timestamp} | {item.level[0]} | {item.msg}', - 'timestamp': '%H:%M:%S' + MESSAGE: '{timestamp} | {level} | {message}', + LEVEL: '{level[0]}', + TIMESTAMP: '%H:%M:%S', }, logger.MEDIUM_VERBOSE: { - 'message': '{timestamp} | {item.level[0]} | {implementation} | {item.msg} ', - 'timestamp': '%H:%M:%S' + MESSAGE: '{timestamp} | {level} | {implementation} | {message} ', + LEVEL: '{level[0]}', + TIMESTAMP: '%H:%M:%S' }, logger.HIGH_VERBOSE: { - 'message': '{timestamp} | {item.level[0]} | {implementation}({inputs}) | {item.msg} ', - 'timestamp': '%H:%M:%S' + MESSAGE: '{timestamp} | {level} | {implementation} | {inputs} | {message} ', + LEVEL: '{level[0]}', + TIMESTAMP: '%H:%M:%S' + }, +} + +DEFAULT_STYLING = { + LEVEL: { + 'info': Color.Fore.LIGHTMAGENTA_EX, + 'debug': Color.Schema(fore=Color.Fore.LIGHTMAGENTA_EX, style=Color.Style.DIM), + 'error': Color.Schema(fore=Color.Fore.RED, style=Color.Style.BRIGHT), }, + TIMESTAMP: { + 'info': Color.Fore.LIGHTMAGENTA_EX, + 'debug': Color.Schema(fore=Color.Fore.LIGHTMAGENTA_EX, style=Color.Style.DIM), + 'error': Color.Schema(fore=Color.Fore.RED, style=Color.Style.BRIGHT), + }, + MESSAGE: { + 'info': Color.Fore.LIGHTBLUE_EX, + 'debug': Color.Schema(fore=Color.Fore.LIGHTBLUE_EX, style=Color.Style.DIM), + 'error': Color.Schema(fore=Color.Fore.RED, style=Color.Style.BRIGHT), + }, + IMPLEMENTATION: { + 'info': Color.Fore.LIGHTBLACK_EX, + 'debug': Color.Schema(fore=Color.Fore.LIGHTBLACK_EX, style=Color.Style.DIM), + 'error': Color.Schema(fore=Color.Fore.RED, style=Color.Style.BRIGHT), + }, + INPUTS: { + 'info': Color.Fore.BLUE, + 'debug': Color.Schema(fore=Color.Fore.BLUE, style=Color.Style.DIM), + 'error': Color.Schema(fore=Color.Fore.RED, style=Color.Style.BRIGHT), + }, + TRACEBACK: {'error': Color.Fore.RED}, + + MARKER: Color.Back.LIGHTYELLOW_EX, + FINAL_STATES: { + SUCCESS_STATE: Color.Fore.GREEN, + CANCEL_STATE: Color.Fore.YELLOW, + FAIL_STATE: Color.Fore.RED, + } } +_PATTERNS = { + SUCCESS_STATE: re.compile(_SUCCESSFUL_EXECUTION_PATTERN), + CANCEL_STATE: re.compile(_CANCELED_EXECUTION_PATTERN), + FAIL_STATE: re.compile(_FAILED_EXECUTION_PATTERN) + +} + + +class _StylizedLogs(object): + + def __init__(self): + self._formats = DEFAULT_FORMATTING + self._styles = DEFAULT_STYLING + self._mark_pattern = None + + def _push(self, styles=None, formats=None, mark_pattern=None): + self._styles = styles or self._styles + self._formats = formats or self._formats + self._mark_pattern = mark_pattern + + def _implementation(self, implementation, log_item): + return self._stylize(implementation, log_item, IMPLEMENTATION) + + def _inputs(self, inputs, log_item): + return self._stylize(inputs, log_item, INPUTS) + + def _timestamp(self, timestamp, log_item): + return self._stylize(timestamp, log_item, TIMESTAMP) + + def _message(self, message, log_item): + return self._stylize(message, log_item, MESSAGE) + + def _traceback(self, traceback, log_item): + return self._stylize(traceback, log_item, TRACEBACK) + + def _level(self, log_item): + return self._stylize(log_item.level[0], log_item, LEVEL) + + def _stylize(self, msg, log_item, msg_type): + schema = (self._final_string_schema(log_item.msg) or + self._styles[msg_type].get(log_item.level.lower(), '')) + return Color.stylize(msg, schema) + + def _markup(self, str_, original_message): + if self._mark_pattern is None: + return str_ + else: + regex_pattern = re.compile(self._mark_pattern) + matches = re.search(regex_pattern, original_message) + if not matches: + return str_ + return Color.markup(str_, matches, self._styles[MARKER]) + + def _final_string_schema(self, original_message): + for state, pattern in _PATTERNS.items(): + if re.match(pattern, original_message): + return self._styles[FINAL_STATES][state] + + def __call__(self, item): + # If no formats are passed we revert to the default formats (per level) + formatting = self._formats.get(env.logging.verbosity_level, + DEFAULT_FORMATTING[env.logging.verbosity_level]) + msg = StringIO() + formatting_kwargs = dict(item=item) + + # level + formatting_kwargs['level'] = self._level(item) + + # implementation + if item.task: + # operation task + implementation = item.task.implementation + inputs = dict(i.unwrap() for i in item.task.inputs.values()) + else: + # execution task + implementation = item.execution.workflow_name + inputs = dict(i.unwrap() for i in item.execution.inputs.values()) + + formatting_kwargs['implementation'] = self._markup( + self._implementation(implementation, item), implementation) + formatting_kwargs['inputs'] = self._markup(self._inputs(inputs, item), str(inputs)) + + # timestamp + if 'timestamp' in formatting: + timestamp = item.created_at.strftime(formatting['timestamp']) + else: + timestamp = item.created_at + formatting_kwargs['timestamp'] = self._timestamp(timestamp, item) + + # message + formatting_kwargs['message'] = self._message(item.msg, item) -def _str(item, formats=None): - # If no formats are passed we revert to the default formats (per level) - formats = formats or {} - formatting = formats.get(env.logging.verbosity_level, - DEFAULT_FORMATTING[env.logging.verbosity_level]) - msg = StringIO() + # The message would be marked out if containing the provided pattern + msg.write(self._markup(formatting['message'].format(**formatting_kwargs), item.msg)) - formatting_kwargs = dict(item=item) + # 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._traceback('\t' + '|' + line, item)) - if item.task: - formatting_kwargs['implementation'] = item.task.implementation - formatting_kwargs['inputs'] = dict(i.unwrap() for i in item.task.inputs.values()) - else: - formatting_kwargs['implementation'] = item.execution.workflow_name - formatting_kwargs['inputs'] = dict(i.unwrap() for i in item.execution.inputs.values()) + return msg.getvalue() - if 'timestamp' in formatting: - formatting_kwargs['timestamp'] = item.created_at.strftime(formatting['timestamp']) - else: - formatting_kwargs['timestamp'] = item.created_at - msg.write(formatting['message'].format(**formatting_kwargs)) +_stylize_log = _StylizedLogs() - # Add the exception and the error msg. - if item.traceback and env.logging.verbosity_level >= logger.MEDIUM_VERBOSE: - for line in item.traceback.splitlines(True): - msg.write('\t' + '|' + line) - return msg.getvalue() +@contextmanager +def format(styles=None, formats=None, mark_pattern=None): --- End diff -- read styles and formats from config (if defined); mark pattern can be passed directly via `log` and `log_list` > Support colorful execution logging > ---------------------------------- > > Key: ARIA-146 > URL: https://issues.apache.org/jira/browse/ARIA-146 > Project: AriaTosca > Issue Type: Story > Reporter: Ran Ziv > Assignee: Maxim Orlov > Priority: Minor > > Add support for printing execution logs in color -- This message was sent by Atlassian JIRA (v6.3.15#6346)