gouge.parseable

Machine-readable log formatters.

  • CSVLog writes one CSV row per record.

  • XMLLog writes one <record> element per record.

  • JSONLog writes one JSON object per line (JSON Lines), including the extra attributes of the record. This is the format to use for log aggregation.

class gouge.parseable.CSVLog(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)

Bases: Formatter

CSV formatter: one row per record.

The columns correspond to the following fields:

  • created

  • filename

  • funcName

  • levelname

  • levelno

  • lineno

  • module

  • msecs

  • name

  • pathname

  • process

  • processName

  • relativeCreated

  • thread

  • threadName

  • message

  • exc_text

Parameters:
fmt=None

Passed on to logging.Formatter.

datefmt=None

Passed on to logging.Formatter.

style='%'

Passed on to logging.Formatter.

validate=True

Passed on to logging.Formatter.

defaults=None

Passed on to logging.Formatter.

With logging.config.dictConfig(), use either {"()": "gouge.parseable.CSVLog"} or {"class": "gouge.parseable.CSVLog"} as the formatter.

static basicConfig(**kwargs)

Call logging.basicConfig() with kwargs, then set a CSVLog formatter on every handler of the root logger.

Parameters:
**kwargs

Passed on to logging.basicConfig().

Return type:

None

format(record)

Format record as one CSV row.

Parameters:
record

The record to format.

Return type:

str

Returns:

The row, without a trailing line break.

class gouge.parseable.XMLLog(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)

Bases: Formatter

XML formatter: one <record> element per record.

The records have the following schema:

<record>
    <created />
    <filename />
    <funcName />
    <levelname />
    <levelno />
    <lineno />
    <module />
    <msecs />
    <name />
    <pathname />
    <process />
    <processName />
    <relativeCreated />
    <thread />
    <threadName />
    <message />
    <exc_text />
</record>
Parameters:
fmt=None

Passed on to logging.Formatter.

datefmt=None

Passed on to logging.Formatter.

style='%'

Passed on to logging.Formatter.

validate=True

Passed on to logging.Formatter.

defaults=None

Passed on to logging.Formatter.

With logging.config.dictConfig(), use either {"()": "gouge.parseable.XMLLog"} or {"class": "gouge.parseable.XMLLog"} as the formatter.

static basicConfig(**kwargs)

Call logging.basicConfig() with kwargs, then set a XMLLog formatter on every handler of the root logger.

Parameters:
**kwargs

Passed on to logging.basicConfig().

Return type:

None

format(record)

Format record as one <record> element.

Parameters:
record

The record to format.

Return type:

str

Returns:

The element as XML text.

class gouge.parseable.JSONLog(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)

Bases: Formatter

JSON Lines formatter: one JSON object per record.

Each record becomes one compact JSON object on a single line (newlines in values are escaped). Non-ASCII text is written as-is. The keys are, in this order:

  • timestamp: the creation time of the record in UTC, as ISO 8601 with milliseconds, for example 2026-10-27T13:34:48.899+00:00. UTC avoids ambiguous local times around daylight-saving changes.

  • level: the level name, for example INFO.

  • logger: the logger name.

  • message: the message with its arguments merged in.

  • every extra attribute of the record, sorted by name. Extra attributes are those passed with extra={...} to a log call or set by a filter; standard logging.LogRecord attributes and names starting with _ are left out. The OpenTelemetry IDs otelTraceID and otelSpanID become trace_id and span_id when a span is active.

  • exc_text: the plain traceback, only if the record has exception information. Like the standard formatter, it is cached on the record.

  • stack_info: the stack, only if the record has one.

The keys above always win: an extra attribute with the same name as one of them is written as extra.<name> instead (and dropped if that name is taken as well).

The output is always strict JSON and format() never raises because of an extra attribute. Values which JSON cannot represent are written as their str. This includes non-finite floats (nan, inf), which become "NaN", "Infinity" and "-Infinity", also when nested in lists or dictionaries. If a value cannot be serialised at all (a dictionary with keys which are not strings, numbers, booleans or None, or a circular reference), the str of the whole value is written instead. Extra attributes whose name is not a string are left out.

Parameters:
fmt=None

Ignored. Accepted so the formatter can be configured like any logging.Formatter.

datefmt=None

An optional strftime() format for timestamp. It is applied to the UTC time, so %z renders as +0000.

style='%'

Passed on to logging.Formatter.

validate=True

Passed on to logging.Formatter.

defaults=None

Passed on to logging.Formatter.

Example, with a correlation ID which a filter put on the records:

>>> import logging
>>> from gouge.parseable import JSONLog
>>> class CorrelationFilter(logging.Filter):
...     def filter(self, record):
...         record.correlation_id = "4bf92f35"
...         return True
>>> handler = logging.StreamHandler()
>>> handler.addFilter(CorrelationFilter())
>>> handler.setFormatter(JSONLog())
>>> logging.getLogger().addHandler(handler)
>>> logging.getLogger("app").warning(
...     "Order created", extra={"order.id": 42}
... )
{"timestamp":...,"correlation_id":"4bf92f35","order.id":42}

With logging.config.dictConfig(), use either {"()": "gouge.parseable.JSONLog"} or {"class": "gouge.parseable.JSONLog"} as the formatter.

CORE_KEYS = frozenset({'exc_text', 'level', 'logger', 'message', 'stack_info', 'timestamp'})

The keys JSONLog writes itself.

static basicConfig(**kwargs)

Call logging.basicConfig() with kwargs, then set a JSONLog formatter on every handler of the root logger.

Parameters:
**kwargs

Passed on to logging.basicConfig().

Return type:

None

formatTime(record, datefmt=None)

Return the creation time of record in UTC.

Parameters:
record

The record to format.

datefmt=None

An optional strftime() format. Without it, the time is ISO 8601 with milliseconds and UTC offset.

Return type:

str

Returns:

The formatted time.

format(record)

Format record as one line of JSON.

Parameters:
record

The record to format.

Return type:

str

Returns:

The JSON object, without a trailing newline.