Skip to main content

Lib/logging/__init__.py (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Lib/logging/__init__.py

This annotation covers handlers, formatters, filters, and the logger hierarchy. See lib_logging_detail for Logger.log, level filtering, and basicConfig.

Map

LinesSymbolRole
1-100LogRecordStructured log event: name, level, msg, args, exc_info
101-250FormatterFormat a LogRecord to a string
251-400Filter, FiltererAttach callable or name-based filters to handlers/loggers
401-600HandlerBase handler: emit, handle, format, lock
601-750StreamHandlerWrite formatted record to a stream
751-900FileHandlerStreamHandler with delayed file open and mode/encoding
901-1100ManagerLogger registry: getLogger, placeholder nodes
1101-1300Logger.callHandlersWalk logger hierarchy until propagate=False
1301-1600Logger.handleApply filters, then call each handler

Reading

LogRecord

# CPython: Lib/logging/__init__.py:290 LogRecord.__init__
class LogRecord:
def __init__(self, name, level, pathname, lineno,
msg, args, exc_info, func=None, sinfo=None):
ct = time.time()
self.name = name
self.msg = msg
self.args = args
self.levelname = getLevelName(level)
self.levelno = level
self.pathname = pathname
self.lineno = lineno
self.exc_info = exc_info
self.created = ct
self.msecs = (ct - int(ct)) * 1000
self.thread = threading.get_ident()
self.process = os.getpid()

Formatter.format

# CPython: Lib/logging/__init__.py:660 Formatter.format
class Formatter:
def format(self, record):
record.message = record.getMessage()
if self.usesTime():
record.asctime = self.formatTime(record, self.datefmt)
s = self.formatMessage(record) # apply self._fmt % record.__dict__
if record.exc_info:
if not record.exc_text:
record.exc_text = self.formatException(record.exc_info)
if record.exc_text:
s = s + '\n' + record.exc_text
if record.stack_info:
s = s + '\n' + self.formatStack(record.stack_info)
return s

Handler.handle

# CPython: Lib/logging/__init__.py:930 Handler.handle
class Handler(Filterer):
def handle(self, record):
"""Filter then emit, with the handler lock held."""
rv = self.filter(record) # check all attached filters
if rv:
self.acquire()
try:
self.emit(record)
finally:
self.release()
return rv

StreamHandler.emit

# CPython: Lib/logging/__init__.py:1110 StreamHandler.emit
class StreamHandler(Handler):
def emit(self, record):
try:
msg = self.format(record)
stream = self.stream
stream.write(msg + self.terminator)
self.flush()
except RecursionError:
raise
except Exception:
self.handleError(record)

handleError by default prints to sys.stderr but swallows the exception to avoid crashing the application.

Logger.callHandlers

# CPython: Lib/logging/__init__.py:1560 Logger.callHandlers
def callHandlers(self, record):
"""Pass the record up the logger hierarchy."""
c = self
found = 0
while c:
for hdlr in c.handlers:
found += 1
if record.levelno >= hdlr.level:
hdlr.handle(record)
if not c.propagate:
c = None
else:
c = c.parent
if found == 0:
if lastResort:
if record.levelno >= lastResort.level:
lastResort.handle(record)
elif raiseExceptions and not self.manager.emittedNoHandlerWarning:
sys.stderr.write("No handlers could be found for logger"
" \"%s\"\n" % self.name)
self.manager.emittedNoHandlerWarning = True

The hierarchy walk stops when propagate=False or when the root logger is reached.

gopy notes

logging is pure Python. LogRecord.thread uses threading.get_ident() which maps to vm.GetThreadIdent(). os.getpid() returns the process ID via syscall.Getpid(). FileHandler uses open() which is gopy's built-in file object backed by os.File.