• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The Abseil Authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Module to convert log levels between Abseil Python, C++, and Python standard.
16
17This converter has to convert (best effort) between three different
18logging level schemes:
19
20  * **cpp**: The C++ logging level scheme used in Abseil C++.
21  * **absl**: The absl.logging level scheme used in Abseil Python.
22  * **standard**: The python standard library logging level scheme.
23
24Here is a handy ascii chart for easy mental mapping::
25
26    LEVEL    | cpp |  absl  | standard |
27    ---------+-----+--------+----------+
28    DEBUG    |  0  |    1   |    10    |
29    INFO     |  0  |    0   |    20    |
30    WARNING  |  1  |   -1   |    30    |
31    ERROR    |  2  |   -2   |    40    |
32    CRITICAL |  3  |   -3   |    50    |
33    FATAL    |  3  |   -3   |    50    |
34
35Note: standard logging ``CRITICAL`` is mapped to absl/cpp ``FATAL``.
36However, only ``CRITICAL`` logs from the absl logger (or absl.logging.fatal)
37will terminate the program. ``CRITICAL`` logs from non-absl loggers are treated
38as error logs with a message prefix ``"CRITICAL - "``.
39
40Converting from standard to absl or cpp is a lossy conversion.
41Converting back to standard will lose granularity.  For this reason,
42users should always try to convert to standard, the richest
43representation, before manipulating the levels, and then only to cpp
44or absl if those level schemes are absolutely necessary.
45"""
46
47import logging
48
49STANDARD_CRITICAL = logging.CRITICAL
50STANDARD_ERROR = logging.ERROR
51STANDARD_WARNING = logging.WARNING
52STANDARD_INFO = logging.INFO
53STANDARD_DEBUG = logging.DEBUG
54
55# These levels are also used to define the constants
56# FATAL, ERROR, WARNING, INFO, and DEBUG in the
57# absl.logging module.
58ABSL_FATAL = -3
59ABSL_ERROR = -2
60ABSL_WARNING = -1
61ABSL_WARN = -1  # Deprecated name.
62ABSL_INFO = 0
63ABSL_DEBUG = 1
64
65ABSL_LEVELS = {ABSL_FATAL: 'FATAL',
66               ABSL_ERROR: 'ERROR',
67               ABSL_WARNING: 'WARNING',
68               ABSL_INFO: 'INFO',
69               ABSL_DEBUG: 'DEBUG'}
70
71# Inverts the ABSL_LEVELS dictionary
72ABSL_NAMES = {'FATAL': ABSL_FATAL,
73              'ERROR': ABSL_ERROR,
74              'WARNING': ABSL_WARNING,
75              'WARN': ABSL_WARNING,  # Deprecated name.
76              'INFO': ABSL_INFO,
77              'DEBUG': ABSL_DEBUG}
78
79ABSL_TO_STANDARD = {ABSL_FATAL: STANDARD_CRITICAL,
80                    ABSL_ERROR: STANDARD_ERROR,
81                    ABSL_WARNING: STANDARD_WARNING,
82                    ABSL_INFO: STANDARD_INFO,
83                    ABSL_DEBUG: STANDARD_DEBUG}
84
85# Inverts the ABSL_TO_STANDARD
86STANDARD_TO_ABSL = dict((v, k) for (k, v) in ABSL_TO_STANDARD.items())
87
88
89def get_initial_for_level(level):
90  """Gets the initial that should start the log line for the given level.
91
92  It returns:
93
94  * ``'I'`` when: ``level < STANDARD_WARNING``.
95  * ``'W'`` when: ``STANDARD_WARNING <= level < STANDARD_ERROR``.
96  * ``'E'`` when: ``STANDARD_ERROR <= level < STANDARD_CRITICAL``.
97  * ``'F'`` when: ``level >= STANDARD_CRITICAL``.
98
99  Args:
100    level: int, a Python standard logging level.
101
102  Returns:
103    The first initial as it would be logged by the C++ logging module.
104  """
105  if level < STANDARD_WARNING:
106    return 'I'
107  elif level < STANDARD_ERROR:
108    return 'W'
109  elif level < STANDARD_CRITICAL:
110    return 'E'
111  else:
112    return 'F'
113
114
115def absl_to_cpp(level):
116  """Converts an absl log level to a cpp log level.
117
118  Args:
119    level: int, an absl.logging level.
120
121  Raises:
122    TypeError: Raised when level is not an integer.
123
124  Returns:
125    The corresponding integer level for use in Abseil C++.
126  """
127  if not isinstance(level, int):
128    raise TypeError('Expect an int level, found {}'.format(type(level)))
129  if level >= 0:
130    # C++ log levels must be >= 0
131    return 0
132  else:
133    return -level
134
135
136def absl_to_standard(level):
137  """Converts an integer level from the absl value to the standard value.
138
139  Args:
140    level: int, an absl.logging level.
141
142  Raises:
143    TypeError: Raised when level is not an integer.
144
145  Returns:
146    The corresponding integer level for use in standard logging.
147  """
148  if not isinstance(level, int):
149    raise TypeError('Expect an int level, found {}'.format(type(level)))
150  if level < ABSL_FATAL:
151    level = ABSL_FATAL
152  if level <= ABSL_DEBUG:
153    return ABSL_TO_STANDARD[level]
154  # Maps to vlog levels.
155  return STANDARD_DEBUG - level + 1
156
157
158def string_to_standard(level):
159  """Converts a string level to standard logging level value.
160
161  Args:
162    level: str, case-insensitive ``'debug'``, ``'info'``, ``'warning'``,
163        ``'error'``, ``'fatal'``.
164
165  Returns:
166    The corresponding integer level for use in standard logging.
167  """
168  return absl_to_standard(ABSL_NAMES.get(level.upper()))
169
170
171def standard_to_absl(level):
172  """Converts an integer level from the standard value to the absl value.
173
174  Args:
175    level: int, a Python standard logging level.
176
177  Raises:
178    TypeError: Raised when level is not an integer.
179
180  Returns:
181    The corresponding integer level for use in absl logging.
182  """
183  if not isinstance(level, int):
184    raise TypeError('Expect an int level, found {}'.format(type(level)))
185  if level < 0:
186    level = 0
187  if level < STANDARD_DEBUG:
188    # Maps to vlog levels.
189    return STANDARD_DEBUG - level + 1
190  elif level < STANDARD_INFO:
191    return ABSL_DEBUG
192  elif level < STANDARD_WARNING:
193    return ABSL_INFO
194  elif level < STANDARD_ERROR:
195    return ABSL_WARNING
196  elif level < STANDARD_CRITICAL:
197    return ABSL_ERROR
198  else:
199    return ABSL_FATAL
200
201
202def standard_to_cpp(level):
203  """Converts an integer level from the standard value to the cpp value.
204
205  Args:
206    level: int, a Python standard logging level.
207
208  Raises:
209    TypeError: Raised when level is not an integer.
210
211  Returns:
212    The corresponding integer level for use in cpp logging.
213  """
214  return absl_to_cpp(standard_to_absl(level))
215