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