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