xref: /aosp_15_r20/external/autotest/utils/frozen_chromite/lib/cros_logging.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# -*- coding: utf-8 -*-
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Logging module to be used by all scripts.
7
8cros_logging is a wrapper around logging with additional support for NOTICE
9level. This is to be used instead of the default logging module. The new
10logging level can only be used from here.
11
12The log levels should be used as follows:
13
14DEBUG: Enabled on the CLI with --debug. This is the noisiest logging level.
15Often, as the name suggests, it may contain debugging information you wouldn't
16otherwise need.
17
18INFO: Enabled on the CLI with --verbose. Logging at this level should contain
19relatively fine-grained info about the steps the process is performing, but
20should be light on details (which should be in debug).
21
22NOTICE: The default log level. It should relay a high level overview of what
23the process is doing. It should NOT be a noisy output.
24
25WARNING: Unexpected scenarios that are well handled and do not interrupt the
26process, things like retrying an operation or missing optional information
27needed to complete a portion of a process.
28
29ERROR: Problems that are fatal to a specific operation or script, e.g.
30unable to read a file or invalid arguments.
31
32CRITICAL/FATAL: Rarely needed. These should reflect an extraordinary error that
33might require the shutdown of an application or lead to data loss.
34
35WARNING, ERROR, CRITICAL/FATAL: These levels are always included in the above
36levels as one would expect. Limiting the output of a script to just these log
37levels is rarely desirable, but the --log-level argument can be used to do so.
38"""
39
40from __future__ import print_function
41
42import sys
43# pylint: disable=unused-wildcard-import, wildcard-import
44from logging import *
45# pylint: enable=unused-wildcard-import, wildcard-import
46
47# Have to import shutdown explicitly from logging because it is not included
48# in logging's __all__.
49# pylint: disable=unused-import
50from logging import shutdown
51# pylint: enable=unused-import
52
53# Import as private to avoid polluting module namespace.
54from autotest_lib.utils.frozen_chromite.lib import buildbot_annotations as _annotations
55
56
57# Remove deprecated APIs to force use of new ones.
58del WARN
59del warn
60
61
62# Notice Level.
63NOTICE = 25
64addLevelName(NOTICE, 'NOTICE')
65
66
67# Notice implementation.
68def notice(message, *args, **kwargs):
69  """Log 'msg % args' with severity 'NOTICE'."""
70  log(NOTICE, message, *args, **kwargs)
71
72
73# Only buildbot aware entry-points need to spew buildbot specific logs. Require
74# user action for the special log lines.
75_buildbot_markers_enabled = False
76def EnableBuildbotMarkers():
77  # pylint: disable=global-statement
78  global _buildbot_markers_enabled
79  _buildbot_markers_enabled = True
80
81
82def _PrintForBuildbot(handle, annotation_class, *args):
83  """Log a line for buildbot.
84
85  This function dumps a line to log recognizable by buildbot if
86  EnableBuildbotMarkers has been called. Otherwise, it dumps the same line in a
87  human friendly way that buildbot ignores.
88
89  Args:
90    handle: The pipe to dump the log to. If None, log to sys.stderr.
91    annotation_class: Annotation subclass for the type of buildbot log.
92    buildbot_tag: A tag specifying the type of buildbot log.
93    *args: The rest of the str arguments to be dumped to the log.
94  """
95  if handle is None:
96    handle = sys.stderr
97  if annotation_class == _annotations.SetEmailNotifyProperty:
98    annotation = annotation_class(*args)
99  else:
100    # Cast each argument, because we end up getting all sorts of objects from
101    # callers.
102    str_args = [str(x) for x in args]
103    annotation = annotation_class(*str_args)
104  if _buildbot_markers_enabled:
105    line = str(annotation)
106  else:
107    line = annotation.human_friendly
108  handle.write('\n' + line + '\n')
109
110
111def PrintBuildbotLink(text, url, handle=None):
112  """Prints out a link to buildbot."""
113  _PrintForBuildbot(handle, _annotations.StepLink, text, url)
114
115
116def PrintKitchenSetBuildProperty(name, data, handle=None):
117  """Prints out a request to set a build property to a JSON value."""
118  _PrintForBuildbot(handle, _annotations.SetBuildProperty, name, data)
119
120
121def PrintKitchenSetEmailNotifyProperty(name, data, handle=None):
122  """Prints out a request to set an email_notify build property."""
123  _PrintForBuildbot(handle, _annotations.SetEmailNotifyProperty, name, data)
124
125
126def PrintBuildbotStepText(text, handle=None):
127  """Prints out stage text to buildbot."""
128  _PrintForBuildbot(handle, _annotations.StepText, text)
129
130
131def PrintBuildbotStepWarnings(handle=None):
132  """Marks a stage as having warnings."""
133  PrintBuildbotStepText('[FAILED BUT FORGIVEN]', handle=handle)
134  # Warnings not supported by LUCI, so working around until re-added.
135  _PrintForBuildbot(handle, _annotations.StepWarnings)
136
137
138def PrintBuildbotStepFailure(handle=None):
139  """Marks a stage as having failures."""
140  _PrintForBuildbot(handle, _annotations.StepFailure)
141
142
143def PrintBuildbotStepName(name, handle=None):
144  """Marks a step name for buildbot to display."""
145  _PrintForBuildbot(handle, _annotations.BuildStep, name)
146