Skip to main content

gocept.logging

https://github.com/gocept/gocept.logging/workflows/tests/badge.svg https://coveralls.io/repos/github/gocept/gocept.logging/badge.svg

This package provides infrastructure for semi-structured log messages.

This means appending easily parseable information after the free-text log message to facilitate analysis of the logs later on. The logging module of the Python standard library already has support for this, via the extra parameter. gocept.logging provides a Formatter that extracts these extra values, formats them as key=value pairs and appends them to the message:

>>> import gocept.logging
>>> import logging
>>> import sys

>>> handler = logging.StreamHandler(sys.stdout)
>>> handler.setFormatter(gocept.logging.SyslogKeyValueFormatter())
>>> log = logging.getLogger('example')
>>> log.addHandler(handler)
>>> log.warning('Hello, world!', extra={'foo': 'bar'})
Aug 24 12:10:08 localhost example: Hello, world! foo=bar

This package is tested to be compatible with Python version 2.7 and 3.3.

Advanced usage

If you have extra values that you always want to pass to your log messages (e.g things like the current user, session id, …) you can wrap your logger with an LoggerAdapter that prefills these values. gocept.logging provides one that allows both stacking adapters and overriding the prefilled values:

>>> from gocept.logging.adapter import StaticDefaults
>>> import logging

>>> log = logging.getLogger('advanced')
>>> log = StaticDefaults(log, {'foo': 'bar', 'qux': 'baz'})
>>> log = StaticDefaults(log, {'blam': 'splat'})
>>> log.warning('Hello, world!', extra={'foo': 'override'})
    # yields {'foo': 'override', 'qux': 'baz', 'blam': 'splat'}

Testing support

To help inspecting the extra values, gocept.logging comes with a specialized handler for testing:

>>> import gocept.logging
>>> import logging

>>> log = logging.getLogger('testing')
>>> handler = gocept.logging.TestingHandler()
>>> log.addHandler(handler)
>>> log.warning('Hello, world!', extra={'foo': 'bar'})
>>> handler.messages[0].extra['foo']
'bar'

The TestingHandler records each log message as a namedtuple of type gocept.logging.testing.LogMessage so you an easily access all parts of the message.

Example configuration

Creating semi-structured log messages is the first half of the issue, while analysing them is the second half. We use logstash for that purpose.

The recommended setup is:

application -> syslogd on localhost -> logstash on central host (via UDP syslog input)

For development you might want to leave out the middle man and configure the application to send log messags via syslog protocol directly to logstash.

Setup with ini file

If you have a paste.ini for your application, you might use something like this:

[loggers]
keys = root

[handlers]
keys = console, syslog

[formatters]
keys = generic, keyvalue

[logger_root]
level = INFO
handlers = console, syslog

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s %(name)s: %(message)s

[handler_syslog]
class = logging.handlers.SysLogHandler
args = ()
formatter = keyvalue

[formatter_keyvalue]
class = gocept.logging.SyslogKeyValueFormatter

Setup with ZConfig

If you have a Zope application, you might use something like this:

<eventlog>
  <logfile>
    formatter zope.exceptions.log.Formatter
    format %(asctime)s %(levelname)-5.5s %(name)s: %(message)s
    path STDOUT
  </logfile>
  <syslog>
    formatter gocept.logging.SyslogKeyValueFormatter
  </syslog>
</eventlog>

syslogd configuration

rsyslog:

$EscapeControlCharactersOnReceive off
$MaxMessageSize 64k
user.* @localhost:5140

The first two lines are to support tracebacks, which are multiline and might take up some space. The last line tells rsyslogd to forward all messages of the user facility (which is what stdlib logging uses by default) via syslog UDP protocol to localhost port 5140 (where logstash might be listening).

logstash configuration

input {
        tcp {
                host => "localhost"
                port => 5140
                type => syslog
        }
        udp {
                host => "localhost"
                port => 5140
                type => syslog
        }
}

filter {
        grok {
                type => "syslog"
                pattern => [ "(?m)<%{POSINT:syslog_pri}>%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" ]
        }
        syslog_pri {
                type => "syslog"
        }
        date {
                type => "syslog"
                match => [ "syslog_timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
        }
        mutate {
                type => "syslog"
                exclude_tags => "_grokparsefailure"
                replace => [ "@source_host", "%{syslog_hostname}" ]
                replace => [ "@message", "%{syslog_program}: %{syslog_message}" ]
        }
        mutate {
                type => "syslog"
                remove => [ "syslog_hostname", "syslog_timestamp" ]
        }
        kv {
                exclude_tags => "_grokparsefailure"
                type => "syslog"
        }
}

output {
        elasticsearch { embedded => true }
}

Additional features

ArgumentParser

The provided gocept.logging.ArgumentParser provides you with the ability to set a logging level in you runscripts.:

from gocept.logging import ArgumentParser
parser = ArgumentParser()
# Optionally set a custom log format, defaults to ``logging.BASIC_FORMAT``
parser.LOG_FORMAT = 'LOG:%(message)s'
# add your arguments with parser.add_argument() here
options = parser.parse_args()

Use your_run_script --help to see a help message about the arguments you can pass to set logging level.

Known bugs

If you log messages as unicode, e.g. log.info(u'foo'), the SyslogHandler will (incorrectly) prepend a byte-order mark, which confuses the logstash parser, resulting in “_grokparsefailure”. This is a known bug in the Python standard library that has been fixed in Python-2.7.4.

Developing gocept.logging

Author:

gocept <mail@gocept.com>

PyPI page:

http://pypi.python.org/pypi/gocept.logging/

Issues:

report by e-mail

Source code:

https://github.com/gocept/gocept.logging

Current change log:

https://raw.githubusercontent.com/gocept/gocept.logging/master/CHANGES.rst

Change log for gocept.logging

1.0 (2023-07-18)

  • Drop support for Python 2.7, 3.3, 3.4, 3.5, 3.6.

  • Add support for Python 3.7, 3.8 3.9, 3.10, 3.11.

  • Add an alias .warn for .warning for StaticDefaults. (#1)

0.8.1 (2017-01-09)

  • Fix setup.py to use relative paths.

0.8 (2016-03-17)

  • Declare compatibility with PyPy and PyPy3.

0.7 (2015-09-29)

  • Declare Python 3.5 compatibility.

0.6 (2015-09-17)

  • Declare Python 3.4 compatibility.

  • ArgumentParser.parse_args() now stores the computed log level on the log_level attribute of the return value.

0.5 (2014-02-07)

  • Allow to change log format for the ArgumentParser

0.4 (2013-09-24)

  • Handle non-string log messages properly.

0.3 (2013-09-04)

  • Added sepcialized argparse.ArgumentParser which enables user to set the logging level by default..

0.2 (2013-08-24)

  • Add timestamp and hostname to syslog messages, this allows plugging SyslogKeyValueFormatter directly into logstash without an intermediary syslogd.

0.1 (2013-08-16)

  • initial release

Release files for gocept.logging 1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gocept.logging 1.0
File Size Uploaded
gocept.logging-1.0.tar.gz 12.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gocept.logging 1.0
File Interpreter ABI Platform
gocept.logging-1.0-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 24.5 kB

Release files / gocept.logging-1.0.tar.gz

Download URL gocept.logging-1.0.tar.gz
Size 12.9 kB
Tags Source
SHA-256 checksum
How to use checksums
b77fa80c24d981f2ba4e4852adb21825b1e5be02744ca5291a2674b8de99091f
BLAKE2b-256 checksum
How to use checksums
9714ed87355e03abb6e686d8fa719719e1e7087945bda77cfddba2e825495e02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.4

Release files / gocept.logging-1.0-py2.py3-none-any.whl

Download URL gocept.logging-1.0-py2.py3-none-any.whl
Size 11.5 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
9376bb115d0cec5e772d9516800b6b0bad429ff78b2909eaa99e96babbe8a316
BLAKE2b-256 checksum
How to use checksums
a165a49acaea764e1a8719e44011a8d4fb4fb31e21843298452deb5db3c3a10f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.4

Release history Release notifications | RSS feed

This release

1.0 This release

2 release files

0.8.1

1 release file

0.8

1 release file

0.7

1 release file

0.6

1 release file

0.5

1 release file

0.4

1 release file

0.3

1 release file

0.2

1 release file

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page