Pyjo.Log - Simple logger

from Pyjo.Log import Log

# Log to STDERR
log = Log()

# Or import the module, as in Google Python Style Guide

import Pyjo.Log

# Log to STDERR
log = Pyjo.Log.new()

# Customize log file location and minimum log level
log = Pyjo.Log.new(path='/var/log/pyjo.log', level='warn')

# Log messages
log.trace('Doing stuff')
log.debug('Not sure what is happening here')
log.info('FYI: it happened again')
log.warn('This might be a problem')
log.error('Garden variety error')
log.fatal('Boom')

Pyjo.Log is a simple logger for Pyjo projects.

The end of a with block closes the file that the log opened for path.

Events

Pyjo.Log inherits all events from Pyjo.EventEmitter and can emit the following new ones.

message

log.on('message', lambda log, level, *lines: ...)

Emitted when a new message gets logged.

log.on('message', lambda log, level, *lines: print(f'{level}: ', *lines, sep=''))

JSON

With json, or the PYJO_LOG_FORMAT environment variable set to json, which the option --log-format of the commands of Pyjoyment.Commands sets, every message is a line of JSON, with the fields that log collectors, as Cloud Logging, Datadog and Elastic, recognize: time in UTC, as of RFC 3339, level, severity with the names of Cloud Logging and syslog, message, pid, and the fields of the message and its context, as Field objects. A message of several lines, as a traceback, stays one line of JSON.

{"time":"2026-10-19T08:15:42.123450Z","level":"warn","severity":"WARNING","message":"Disk is 95% full","pid":31841}

The levels trace and debug are of the severity DEBUG, info of INFO, warn of WARNING, error of ERROR and fatal of CRITICAL.

The logging module

Pyjo.Log.Handler is a logging.Handler that passes the records of the standard library’s logging to a Pyjo.Log.

import logging

logging.getLogger().addHandler(Pyjo.Log.Handler(log))
logging.getLogger().warning('Disk is %d%% full', 95)

The levels of logging are mapped to the closest level of the log: CRITICAL is fatal, ERROR is error, WARNING is warn, INFO is info, DEBUG is debug, and a level below DEBUG is trace.

See also

Pyjoyment, https://mojolicious.org.

Ported from Mojo::Log of Mojolicious 9.49.

class Pyjo.Log.Field(name: str, value: Any, text: str | None = None)[source]
field = Pyjo.Log.Field('user', 'sri')
field = Pyjo.Log.Field('request_id', 'abc123', '[abc123]')

A field of a message of JSON, as a line of a message or of a context, see JSON, which the other formats have as its text, name=value by default. A field does not replace the fields that every message of JSON has, and a value that JSON has no type for is a string.

# Log with a field
log.info('Disk is full', Pyjo.Log.Field('disk', '/dev/sda1'))
name: str
name = field.name

Name of the field.

value: Any
value = field.value

Value of the field.

class Pyjo.Log.Handler(log: Pyjo_Log, level: int = 0)[source]
handler = Pyjo.Log.Handler(log)
handler = Pyjo.Log.Handler(log, logging.INFO)

A logging.Handler that formats the records of logging and logs them with the given Pyjo.Log, at the closest level.

emit(record: LogRecord) → None[source]

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

class Pyjo.Log.Pyjo_Log(*, color: bool | None = None, format: Format | None = None, handle: IO[str] | None = <object object>, history: list[list[Any]] | None = None, json: bool | None = None, level: str = 'trace', max_history_size: int = 10, path: str | PathLike[str] | None = None, short: bool | None = None)[source]

Pyjo.Log inherits all methods from Pyjo.EventEmitter and implements the following new ones.

append(msg: str) → None[source]
log.append('[2018-11-08 14:20:13.77168] [28320] [info] I ♥ Pyjoyment\n')

Append message to handle.

capture(level: str | None = None) → _Capture[source]
with log.capture() as messages:
    ...
with log.capture('debug') as messages:
    ...

Capture log messages until the end of the with block, useful for testing log messages. The messages stay in the returned object after the block.

# Test your log messages
with log.capture('trace') as messages:
    log.fatal('Something very bad happened')
    log.trace('Just some debug information')
like_ok(str(messages), r'Something very bad happened', 'logs contain fatal message')
like_ok(messages[-1], r'Just some debug information', 'trace message was last')
close() → None[source]
log.close()

Close the file that the log opened for path, as the end of a with block does, which it opens again when it is used again.

property color: bool[source]
boolean = log.color
log.color = boolean

Colorize log messages with the levels warn, error and fatal using ANSI escape sequences, defaults to the value of the PYJO_LOG_COLOR environment variable.

context(*context: Any) → Self[source]
new = log.context('[extra]', '[information]')

Construct a new child Pyjo.Log object that will include context information with every log message.

# Log with context
log = Pyjo.Log.new()
context = log.context('[17a60115]')
context.debug('This is a log message with context information')
context.info('And another')

The items of a dict are Field objects, which a message of JSON has as fields of its own, and the other formats as name=value.

# Log with the fields of a context
context = log.context({'user': 'sri'})
debug(*msgs: Any) → Self[source]
log = log.debug('You screwed up, but that is ok')
log = log.debug('All', 'cool')
log = log.debug(lambda: ...)

Emit message event and log debug message.

error(*msgs: Any) → Self[source]
log = log.error('You really screwed up this time')
log = log.error('Wow', 'seriously')
log = log.error(lambda: ...)

Emit message event and log error message.

fatal(*msgs: Any) → Self[source]
log = log.fatal('Its over...')
log = log.fatal('Bye', 'bye')
log = log.fatal(lambda: ...)

Emit message event and log fatal message.

property format: Format[source]
cb = log.format
log.format = lambda time, level, *lines: ...

A callback for formatting log messages.

log.format = lambda time, level, *lines: '[2018-11-08 14:20:13.77168] [28320] [info] I ♥ Pyjoyment\n'
property handle: IO[str] | None[source]
handle = log.handle
log.handle = io.StringIO()

Log text stream used by the default message event, defaults to opening path for appending in UTF-8 or sys.stderr.

history: list[list[Any]]
history = log.history
log.history = [[time.time(), 'debug', 'That went wrong']]

The last few logged messages.

info(*msgs: Any) → Self[source]
log = log.info('You are bad, but you prolly know already')
log = log.info('Ok', 'then')
log = log.info(lambda: ...)

Emit message event and log info message.

is_level(level: str) → bool[source]
boolean = log.is_level('debug')

Check active log level.

# True
log.set(level='debug').is_level('debug')
log.set(level='debug').is_level('info')

# False
log.set(level='info').is_level('debug')
log.set(level='fatal').is_level('warn')
property json: bool[source]
boolean = log.json
log.json = boolean

Generate log messages as lines of JSON, see JSON, defaults to true when the PYJO_LOG_FORMAT environment variable is json, and false when it is text or not set. It takes precedence over short and color.

level
level = log.level
log.level = 'debug'

Active log level, defaults to trace. Available log levels are trace, debug, info, warn, error and fatal, in that order.

max_history_size
size = log.max_history_size
log.max_history_size = 5

Maximum number of logged messages to store in history, defaults to 10.

path
path = log.path
log.path = '/var/log/pyjo.log'

Log file path used by handle.

property short: bool[source]
boolean = log.short
log.short = boolean

Generate short log messages without a timestamp but with journald log level prefix, suitable for systemd environments, defaults to the value of the PYJO_LOG_SHORT environment variable.

trace(*msgs: Any) → Self[source]
log = log.trace('Whatever')
log = log.trace('Who', 'cares')
log = log.trace(lambda: ...)

Emit message event and log trace message.

warn(*msgs: Any) → Self[source]
log = log.warn('Dont do that Dave...')
log = log.warn('No', 'really')
log = log.warn(lambda: ...)

Emit message event and log warn message.