# Package - Logger
##### Written by [Joe Tilsed](https://linkedin.com/in/joetilsed)
###### Created: 24/11/2025


# Overview
This package provides a structured logging system with JSON-formatted logs for Python applications. It supports scoped logging, categories, and structured messages, making it easier to handle complex logging scenarios in Python applications. The logger can output logs in JSON format, which is well-suited for down-stream log aggregation tools.


# Source Code
The source code for this package can be found: [https://bitbucket.org/joetilsed/jt_logger/src](https://bitbucket.org/joetilsed/jt_logger/src)


# Getting Started
The structured logger is designed to handle logs in a consistent JSON format with features like scopes and categories for better context management.

## Install
```shell
pip install logger -i https://pkgs.dev.azure.com/bpsaasplatform/_packaging/Global-pypi/pypi/simple/
```

## Basic Example
```python
from logger import log

log.info("Application started")
```


# Features
## Basic Logging
The logger supports standard log levels such as `debug`, `info`, `warning`, `error`, and `critical`. Each log entry is output as a JSON object, which contains information such as timestamp, log level, message, and other metadata.

## Logging with Scopes
You can define scopes for your logs, which provide additional context. These scopes can be pushed and popped as you enter or leave different logical sections of your code. Each log entry within a scope includes that scope's information.

## Structured Logs with Extra Fields
Logs can contain additional structured information through the extra argument. This helps to provide detailed context for log entries in a structured manner.

## Category-based Logging
The logger allows you to categorize your logs by setting a category name. This is helpful when you need to separate logs by functional area or concern.


# Examples
## Basic Log Example
```python
from logger import log

log.info("Info message")
```
Example output:
```json
{
  "Timestamp": "2024-09-04T19:00:00.000Z",
  "EventId": 0,
  "LogLevel": "INFO",
  "Category": "Program",
  "Message": "Info message",
  "State": {
    "Message": "Info message",
    "{OriginalFormat}": "Info message"
  },
  "Scopes": []
}
```

## Scoped Log Example
Using scopes, you can add contextual information to the logs:
```python
from logger import log

log.push_scope("SpanId:1e0c3d2ebcf9e1b7, TraceId:1af7651916cd43dd8448eb211c80319c, ParentId:0000000000000000")
log.info("User login started")
log.pop_scope()

log.info("User login finished")
```

Example output:
```json
{
  "Timestamp": "2024-09-04T19:00:00.000Z",
  "EventId": 0,
  "LogLevel": "INFO",
  "Category": "Program",
  "Message": "User login started",
  "State": {
    "Message": "User login started",
    "{OriginalFormat}": "User login started"
  },
  "Scopes": [
    {
      "Message": "SpanId:1e0c3d2ebcf9e1b7, TraceId:1af7651916cd43dd8448eb211c80319c, ParentId:0000000000000000",
      "SpanId": "1e0c3d2ebcf9e1b7",
      "TraceId": "1af7651916cd43dd8448eb211c80319c",
      "ParentId": "0000000000000000"
    }
  ]
}
```
```json
{
  "Timestamp": "2024-09-04T19:00:00.001Z",
  "EventId": 0,
  "LogLevel": "INFO",
  "Category": "Program",
  "Message": "User login finished",
  "State": {
    "Message": "User login finished",
    "{OriginalFormat}": "User login finished"
  },
  "Scopes": []
}
```

## Category Log Example
Categorizing logs is useful when you want to differentiate log entries by module or functionality.
```python
from logger import log

log.set_category("Authentication")
log.info("Login attempt for user 123")

log.set_category("DataProcessing")
log.info("Started data processing task")
```

Example output:
```json
{
  "Timestamp": "2024-09-04T19:00:00.000Z",
  "EventId": 0,
  "LogLevel": "INFO",
  "Category": "Authentication",
  "Message": "Login attempt for user 123",
  "State": {
    "Message": "Login attempt for user 123",
    "{OriginalFormat}": "Login attempt for user 123"
  },
  "Scopes": []
}
```
```json
{
  "Timestamp": "2024-09-04T19:00:00.001Z",
  "EventId": 0,
  "LogLevel": "INFO",
  "Category": "DataProcessing",
  "Message": "Started data processing task",
  "State": {
    "Message": "Started data processing task",
    "{OriginalFormat}": "Started data processing task"
  },
  "Scopes": []
}
```

## Error Handling Log Example
Log exceptions or errors along with structured context:
```python
from logger import log

try:
    1 / 0  # This will raise an exception
except ZeroDivisionError as e:
    log.error("An error occurred during calculation: {error}", event_id=1001, error=str(e))
```

Example output:
```json
{
  "Timestamp": "2024-09-04T19:00:00.000Z",
  "EventId": 0,
  "LogLevel": "ERROR",
  "Category": "Program",
  "Message": "An error occurred during calculation: division by zero",
  "State": {
    "Message": "An error occurred during calculation: division by zero",
    "{OriginalFormat}": "An error occurred during calculation: {error}",
    "error": "division by zero"
  },
  "Scopes": []
}
```


# Customization
## Logger Name
You can customize the logger name using the environment variable `LOG_NAME` or programmatically when setting up the logger:
```python
from logger import setup_logger

custom_logger = setup_logger(name="CustomLogger")
custom_logger.info("This is a custom logger")
```

## Log Level
The log level can be set via the environment variable `LOG_LEVEL` or passed to the setup_logger function:
```python
from logger import setup_logger

debug_logger = setup_logger(level="DEBUG")
debug_logger.debug("This is a debug log")
```


# Conclusion
This structured logger package is a powerful tool for managing complex logging needs in your Python application. With support for JSON-formatted logs, scopes, and categories, it helps in building a more organized, readable, and structured logging system.

If you have any issues or suggestions, feel free to open a pull request or reach out to Joe Tilsed.

<br />

###### # That's all folks....
