Logging

The Logging extension uses python-json-logger to format all log messages as json. The default setup tries to configure all loggers (even those from installed libraries) to write logs to stdout.

If the Flask app runs in development mode, log messages are written as plain text to the console.

Additionally this module configures a new log level named AUDIT. This log level has highest possible priority to make sure that audit logs are always produced.

Use the modules flask_tern.logging.init_app() method to configure your app logging.

from flask import Flask
from flask_tern import app_logging

app = Flask(__name__)
# configure loggers as early as possible
app_logging.init_app()

From here on python logging has been set up, and normal python logging can be used as usual. Please make sure to not configure loggers on module level (import time), as this may interfer with logging setup.

Ideally __name__ is the top level package name of the application. This way the Flask app logger becomes the “root” logger for the whole package and only one logger needs to be configured to set the log level for the whole application. This setup will re-use the default flask logging handler, which writes to the wsgi servers wsgi.errors stream. This will make sure, that logs end up at the WSGI servers configured log destination. See Logging.

Customise Logging

The library supports various configuration options to customise logging.

  • LOG_LEVEL: set root logger log level. Values can be strings or constants as described in Logging Levels.

Audit Logging

Audit logging follows the Cloud Aditing Data Federation standard CADF. CADF specifies a data model to capture Initiator, Action, Target and Observer of events. A CADF message looks like this:

{
    "action": "<action name>",
    "outcome": "success | failure",
    "observer": {
        "id": "<app id / uri>",
        "addresses": {
            "name": "<app name>",
            "url": "<app url"
        }
    },
    "initiator": {
        "id": "<user id>",
        "credentials": {
            "type": "<auth method>"
        }
        "host": {
            "agent": "<user agent>",
            "ip": "<source ip>"
        }
    },
    "target": {
        "id": "<target id>",
        "<extras>": "<extra infos about target>",
        "addresses": [
            {
                "name": "<app name>",
                "url": "<requset url>"
            }
        ]
    }
}

Audit messages will be logged with logger name AUDIT and severity AUDIT for easy log parsing and audit capturing.

The module provides a few helper methods to make capturing audit messages easier. Most fields are filled out based on information from the current request, but information about the target needs to be added in the application.

@flask_tern.logging.audit_log(action: str, target: str | dict = None)

Wrap view methods to create audit logs.

Parameters:
  • action (str) – Sets the action field of the audit message

  • target (str | dict) – Either a target id or a dict with fields to put into target of audit message., optional

This method automatically sets the outcome field to success or in case the view method throws an exception to failure. Use record_audit_target() to add additional information about the target.

# noqa: DAR201 # don’t validate return

flask_tern.logging.record_audit_target(id, **kw)

Store target information in current application context.

The audit_log() decorator will pick up this information and add it to the audit log object.

The information is stored in flask.g under key audit_target.

Parameters:
  • id – identifier for target

  • kw – additional properties added to target

flask_tern.logging.audit_ignore(audit_ignore=True)

Call to disable audit log via audit_log() decorator.

This is useful in case automatic audit logging should be turned off for this request.

Parameters:

audit_ignore – Sets the request global g.audit_ignore flag to True or False

flask_tern.logging.audit_success(success=True, reason=None)

Call to set audit_outcome manually.

Parameters:
  • success – If true outcome will be “success”, else outcome will be “failure”.

  • reason – A dictionary containing “reasonType” and “reasonCode” and/or “policyType” and “policyId”

flask_tern.logging.log_audit(*args, **kwargs)

Use this method to log audit messages.

Parameters are passed on to python log function. Usually the result of create_audit_event should be passed in as the only parameter.

Parameters:
  • args – positional args passed to log function.

  • kwargs – keyword args passed to log function.

Todo

  • define vocabularies for audit log objects

  • make sure json log fields are easy to handle in ES