Skip to content

November Five's logging framework for Python

Notifications You must be signed in to change notification settings

novemberfiveco/skidder-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Skidder

Skidder will drag your logs to where they need to go. A small, uniform and extensible logging library, implemented across major technologies.

Installation

pip install git+https://github.com/novemberfiveco/skidder-python@3.0.0

or using poetry

poetry add git+https://github.com/novemberfiveco/skidder-python@3.0.0

Usage

Setup

Configure logging using the configure_logging() function once at the beginning of your program. You can pass a value for the component field as required by N5's standards.

from skidder import configure_logging

configure_logging(component='my-backend-service')

# note that we configure logging outside the AWS Lambda handler function
def handler(event, context):
    ...
 

Logging events

Now that the logger is configured, just use the get_logger() function from structlog to get the correctly configured logger anywhere inside your project.

from structlog import get_logger

log = get_logger()

log.debug("This is a debug log")
log.info("This is an info log")
log.warn("This is a warn log")
log.error("This is an error log")
log.critical("This is a critical log")

When running this program locally, you receive pretty formatted log output:

2021-07-12T18:04:48.248064Z [info     ] This is an info log                             component=foo environment=None source=application type=event

However, in an actual environment, you should set the ENV environment variable, which will enable JSON logging:

{"component": "foo", "environment": "dev", "level": "info", "message": "This is an info log", "source": "application", "timestamp": "2021-07-12T18:07:08.674527Z", "type": "event"}

Logging exceptions

You can pass an exception parameter to include a stacktrace in the log event:

try:
    raise Exception
except Exception as e:
    log.error("API call to external service X failed due to timeout", exception=e)

Including additional fields

You can also pass extra parameters to populate the data field with additional structured information:

log.info("Synchronizing product catalog to store", store_id='store-123')

Setting a request ID on your log events

Whenever possible, you should set the requestId field on log events to link them to a specific request for easy investigation.

You can manually set or unset:

from structlog import bind_request_id, unbind_request_id

log.info("This log event is not part of a request")

def handler(event, context):
    bind_request_id("my-request-123")
    log.info("This log event is part of my-request-123")
    unbind_request_id()

For convenience, there is also a decorator that automatically (un)binds a request ID whenever your function is called. By default, a new UUID is generated.

from structlog import request_context_logging

log.info("This log event is not part of a request")

@request_context_logging
def handler(event, context):
    log.info("This log event is part of a request")

You can also pass a function that provides the request ID (for example you might want to get it from an HTTP request header to continue a request spanning multiple distributed services):

from structlog import request_context_logging

log.info("This log event is not part of a request")

def request_id_from_header(event, context):
    return event["headers"]["X-Trace-ID"]

@request_context_logging(request_id_provider=request_id_from_header)
def handler(event, context):
    log.info("This log event is part of a request")

Adding a LUMIGO_LOG prefix to error logs

When you want to have your error logs get noticed by Lumigo, they need a LUMIGO_LOG prefix. This can be enabled by enabling the corresponding flag:

from skidder import configure_logging

configure_logging(component='my-backend-service', enable_lumigo_prefix=True)
 

Changelog

  • 3.1.1
    • removed Lumigo prefix from warning logs
  • 3.1.0
    • added Lumigo prefix to error logs
  • 3.0.0
    • rename repo to Skidder
  • 2.0.2
    • set minimum python version to 3.7
  • 2.0.1
    • Added check for IS_LOCAL env variable to check local development env
  • 2.0.0
    • Pin structlog dependency (because using private function that is not part of public structlog API and can change without notice)
    • Set minimum logging level to DEBUG when in dev environment
    • Log uncaught exceptions
    • Intercept & process STDLIB logging
    • Populate type field dynamically
    • Populate source field dynamically
    • Refactor into functions
    • Allow binding request ID field
    • Allow binding component field
    • Disable JSON logging & enable pretty logging when executing locally
    • Nest extra fields under the 'data' key
  • 1.0.0
    • basic setup according to N5 standard.