Skip to main content

LogNinja: Simple logging setup for Python

Texto alternativo

License: MIT Supported Python versions of the current PyPI release. Downloads

Simplified. Efficient. Customizable.

LogNinja is a simple logging setup to be used in Python applications.

Installation

To install LogNinja, use pip:

pip install logninja

Basic Usage

First, set up LogNinja:

from logninja import setup_logging
from logninja.configs import LogConsoleConfig

setup_logging(log_console_config=LogConsoleConfig())

This basic setup will format all your logs as JSON.

Advanced Usage

Setup

LogNinja's setup also provides advanced logging features, such as ContextVars, custom formatters, and custom log levels.

Example:

import logging

from my_custom_formatter import CustomFormatter
from my_globals_contextvar import trace_id

from logninja import setup_logging
from logninja.configs import LogConsoleConfig

setup_logging(
    contextvars=[trace_id],
    log_file_config=LogConsoleConfig(),
)

The context variables will be automatically set for all logs. This allows you to use trace logs with your custom context variables.

ASGI Middleware

If you're developing an ASGI application, you can use the LogNinjaASGIMiddleware to automatically log requests and responses:

from my_globals_contextvar import trace_id
from my_logger import logger

from logninja.asgi.middleware import LogNinjaASGIMiddleware

app = FastAPI()
app.add_middleware(
    LogNinjaASGIMiddleware,
    logger=logger,
    contextvars_by_headers=[(request_id, "X-Request-ID")],
)

This allows you to capture the contextvars from headers and, combined with the setup_logging(contextvars=[trace_id]), creates a powerful tool to capture trace IDs from the headers and use them in all logs within the ASGI request context.

Decorator

The log_execution decorator is a powerful tool provided by LogNinja to log the execution time of a function or coroutine.

Here is an example of how to use it:

from logninja import log_execution

@log_execution()
def my_function():
    # Your code here
    pass

This will automatically log the start and end of the function execution, as well as the total execution time.

The decorator can also be used with coroutines:

from logninja import log_execution


@log_execution()
async def my_coroutine():
    # Your code here
    pass

In both cases, the decorator uses the LogNinja logger by default, but you can provide your own logger if you prefer:

from my_logger import logger

from logninja import log_execution


@log_execution(logger=logger)
async def my_coroutine():
    # Your code here
    pass

When you use the log_execution decorator, it generates logs at the start and end of the function or coroutine execution. Here are examples of what these logs look like in both console and JSON formats.

Ninja Format

With ninja format, the logs are displayed as plain text. Here's an example:

['2024-05-30 18:58:28'] [DEBUG   ] 'my_function' executed in 0.0183 seconds   [logninja] decorators.py:55
['2024-05-30 18:58:28'] [DEBUG   ] 'my_function' executed in 0.0183 seconds   [logninja] decorators.py:55

Ninja JSON Format

In the JSON format, the logs are displayed as JSON objects. Here's an example:

{
  "level": "INFO",
  "logger": "logninja",
  "message": "Starting execution of function my_function",
  "params": {
    "args": [],
    "kwargs": {}
  }
}

{
  "level": "INFO",
  "logger": "logninja",
  "message": "my_function executed in 0.0020 seconds"
}

The JSON logs contain the same information as the console logs, but they also include the log level, the logger name, and any extra parameters that were passed to the function or coroutine.

Format Exceptions

All logged exceptions are automatically formatted by our NinjaJsonFormatter:

import logging

from logninja import setup_logging

setup_logging()

logger = logging.getLogger("my_logger")

try:
    1 / 0
except Exception as exc_info:
    logger.exception("Unexpected error", exc_info=exc_info)

By passing the exc_info, LogNinja automatically builds a JSON log like this:

{
  "level": "ERROR",
  "message": "Unexpected error",
  "timestamp": "2024-05-24T19:51:31.402206+00:00",
  "logger": "my_logger",
  "module": "teste",
  "function": "<module>",
  "line": 12,
  "thread_name": "MainThread",
  "exc_info": [
    {
      "exc_type": "ZeroDivisionError",
      "exc_value": "division by zero",
      "syntax_error": null,
      "is_cause": false,
      "frames": [
        {
          "filename": "path_here",
          "logger": "my_logger",
          "module": "teste",
          "function": "<module>",
          "line": 12,
          "thread_name": "MainThread",
          "exc_info": [
            {
              "exc_type": "ZeroDivisionError",
              "exc_value": "division by zero",
              "syntax_error": null,
              "is_cause": false,
              "frames": [
                {
                  "filename": "path_here",
                  "lineno": 10,
                  "name": "<module>",
                  "line": "",
                  "locals": {
                    "__name__": "__main__",
                    "__doc__": "None",
                    "__package__": "None",
                    "__loader__": "<_frozen_importlib_external.SourceFileLoader object at 0x000001FDA90251D0>",
                    "__spec__": "None",
                    "__annotations__": "{}",
                    "__builtins__": "<module 'builtins' (built-in)>",
                    "__file__": "path_here",
                    "__cached__": "None",
                    "logging": "path_here",
                    "setup_logging": "<function setup_logging at 0x000001FDA91BA7A0>",
                    "logger": "<Logger my_logger (INFO)>",
                    "exc_info": "ZeroDivisionError('division by zero')"
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Important Notice: This functionality contains code derived from the structlog project, available at https://github.com/hynek/structlog. Changes were made starting from May 24th, 2024. The original code is licensed under the MIT License or Apache-2.0. Please ensure to comply with these licenses when using LogNinja.

License

This project is licensed under the terms of the MIT license.

Metadata

Release files for logninja 0.1.18

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

Source distribution (sdist)

Source distribution for logninja 0.1.18
File Size Uploaded Provenance Actions
logninja-0.1.18.tar.gz 16.0 kB Without provenance Details for logninja-0.1.18.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for logninja 0.1.18
File Interpreter ABI Platform Actions
logninja-0.1.18-py3-none-any.whl Python 3 none any Details for logninja-0.1.18-py3-none-any.whl

Total release size: 33.3 kB

Release files / logninja-0.1.18.tar.gz

Download URL logninja-0.1.18.tar.gz
Size 16.0 kB
Tags Source
SHA-256 checksum
How to use checksums
944e256b38145c52a5c4d5a9f65f970fb7752ff6747adbecb616f41c1604d6f3
BLAKE2b-256 checksum
How to use checksums
d52362ec89d86b6932257f6ef3dab1028ff51c25d07870113c23228c131fa299
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.0.0 CPython/3.12.4

Release files / logninja-0.1.18-py3-none-any.whl

Download URL logninja-0.1.18-py3-none-any.whl
Size 17.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4258dbc2e283e09afe11d3e09ec24f0ef019b451abf24c68f7a6effa08f135f2
BLAKE2b-256 checksum
How to use checksums
40092e0cbff104c6287ecf16a2efb1e598ed9bd56b97425d5d3d117a2e47cc95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.0.0 CPython/3.12.4

Security for logninja 0.1.18

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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