| # Copyright 2017 The Abseil Authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # 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. |
| |
| """Module to convert log levels between Abseil Python, C++, and Python standard. |
| |
| This converter has to convert (best effort) between three different |
| logging level schemes: |
| |
| * **cpp**: The C++ logging level scheme used in Abseil C++. |
| * **absl**: The absl.logging level scheme used in Abseil Python. |
| * **standard**: The python standard library logging level scheme. |
| |
| Here is a handy ascii chart for easy mental mapping:: |
| |
| LEVEL | cpp | absl | standard | |
| ---------+-----+--------+----------+ |
| DEBUG | 0 | 1 | 10 | |
| INFO | 0 | 0 | 20 | |
| WARNING | 1 | -1 | 30 | |
| ERROR | 2 | -2 | 40 | |
| CRITICAL | 3 | -3 | 50 | |
| FATAL | 3 | -3 | 50 | |
| |
| Note: standard logging ``CRITICAL`` is mapped to absl/cpp ``FATAL``. |
| However, only ``CRITICAL`` logs from the absl logger (or absl.logging.fatal) |
| will terminate the program. ``CRITICAL`` logs from non-absl loggers are treated |
| as error logs with a message prefix ``"CRITICAL - "``. |
| |
| Converting from standard to absl or cpp is a lossy conversion. |
| Converting back to standard will lose granularity. For this reason, |
| users should always try to convert to standard, the richest |
| representation, before manipulating the levels, and then only to cpp |
| or absl if those level schemes are absolutely necessary. |
| """ |
| |
| import logging |
| |
| STANDARD_CRITICAL = logging.CRITICAL |
| STANDARD_ERROR = logging.ERROR |
| STANDARD_WARNING = logging.WARNING |
| STANDARD_INFO = logging.INFO |
| STANDARD_DEBUG = logging.DEBUG |
| |
| # These levels are also used to define the constants |
| # FATAL, ERROR, WARNING, INFO, and DEBUG in the |
| # absl.logging module. |
| ABSL_FATAL = -3 |
| ABSL_ERROR = -2 |
| ABSL_WARNING = -1 |
| ABSL_WARN = -1 # Deprecated name. |
| ABSL_INFO = 0 |
| ABSL_DEBUG = 1 |
| |
| ABSL_LEVELS = {ABSL_FATAL: 'FATAL', |
| ABSL_ERROR: 'ERROR', |
| ABSL_WARNING: 'WARNING', |
| ABSL_INFO: 'INFO', |
| ABSL_DEBUG: 'DEBUG'} |
| |
| # Inverts the ABSL_LEVELS dictionary |
| ABSL_NAMES = {'FATAL': ABSL_FATAL, |
| 'ERROR': ABSL_ERROR, |
| 'WARNING': ABSL_WARNING, |
| 'WARN': ABSL_WARNING, # Deprecated name. |
| 'INFO': ABSL_INFO, |
| 'DEBUG': ABSL_DEBUG} |
| |
| ABSL_TO_STANDARD = {ABSL_FATAL: STANDARD_CRITICAL, |
| ABSL_ERROR: STANDARD_ERROR, |
| ABSL_WARNING: STANDARD_WARNING, |
| ABSL_INFO: STANDARD_INFO, |
| ABSL_DEBUG: STANDARD_DEBUG} |
| |
| # Inverts the ABSL_TO_STANDARD |
| STANDARD_TO_ABSL = dict((v, k) for (k, v) in ABSL_TO_STANDARD.items()) |
| |
| |
| def get_initial_for_level(level): |
| """Gets the initial that should start the log line for the given level. |
| |
| It returns: |
| |
| * ``'I'`` when: ``level < STANDARD_WARNING``. |
| * ``'W'`` when: ``STANDARD_WARNING <= level < STANDARD_ERROR``. |
| * ``'E'`` when: ``STANDARD_ERROR <= level < STANDARD_CRITICAL``. |
| * ``'F'`` when: ``level >= STANDARD_CRITICAL``. |
| |
| Args: |
| level: int, a Python standard logging level. |
| |
| Returns: |
| The first initial as it would be logged by the C++ logging module. |
| """ |
| if level < STANDARD_WARNING: |
| return 'I' |
| elif level < STANDARD_ERROR: |
| return 'W' |
| elif level < STANDARD_CRITICAL: |
| return 'E' |
| else: |
| return 'F' |
| |
| |
| def absl_to_cpp(level): |
| """Converts an absl log level to a cpp log level. |
| |
| Args: |
| level: int, an absl.logging level. |
| |
| Raises: |
| TypeError: Raised when level is not an integer. |
| |
| Returns: |
| The corresponding integer level for use in Abseil C++. |
| """ |
| if not isinstance(level, int): |
| raise TypeError('Expect an int level, found {}'.format(type(level))) |
| if level >= 0: |
| # C++ log levels must be >= 0 |
| return 0 |
| else: |
| return -level |
| |
| |
| def absl_to_standard(level): |
| """Converts an integer level from the absl value to the standard value. |
| |
| Args: |
| level: int, an absl.logging level. |
| |
| Raises: |
| TypeError: Raised when level is not an integer. |
| |
| Returns: |
| The corresponding integer level for use in standard logging. |
| """ |
| if not isinstance(level, int): |
| raise TypeError('Expect an int level, found {}'.format(type(level))) |
| if level < ABSL_FATAL: |
| level = ABSL_FATAL |
| if level <= ABSL_DEBUG: |
| return ABSL_TO_STANDARD[level] |
| # Maps to vlog levels. |
| return STANDARD_DEBUG - level + 1 |
| |
| |
| def string_to_standard(level): |
| """Converts a string level to standard logging level value. |
| |
| Args: |
| level: str, case-insensitive ``'debug'``, ``'info'``, ``'warning'``, |
| ``'error'``, ``'fatal'``. |
| |
| Returns: |
| The corresponding integer level for use in standard logging. |
| """ |
| return absl_to_standard(ABSL_NAMES.get(level.upper())) |
| |
| |
| def standard_to_absl(level): |
| """Converts an integer level from the standard value to the absl value. |
| |
| Args: |
| level: int, a Python standard logging level. |
| |
| Raises: |
| TypeError: Raised when level is not an integer. |
| |
| Returns: |
| The corresponding integer level for use in absl logging. |
| """ |
| if not isinstance(level, int): |
| raise TypeError('Expect an int level, found {}'.format(type(level))) |
| if level < 0: |
| level = 0 |
| if level < STANDARD_DEBUG: |
| # Maps to vlog levels. |
| return STANDARD_DEBUG - level + 1 |
| elif level < STANDARD_INFO: |
| return ABSL_DEBUG |
| elif level < STANDARD_WARNING: |
| return ABSL_INFO |
| elif level < STANDARD_ERROR: |
| return ABSL_WARNING |
| elif level < STANDARD_CRITICAL: |
| return ABSL_ERROR |
| else: |
| return ABSL_FATAL |
| |
| |
| def standard_to_cpp(level): |
| """Converts an integer level from the standard value to the cpp value. |
| |
| Args: |
| level: int, a Python standard logging level. |
| |
| Raises: |
| TypeError: Raised when level is not an integer. |
| |
| Returns: |
| The corresponding integer level for use in cpp logging. |
| """ |
| return absl_to_cpp(standard_to_absl(level)) |