U UniCore Community Public content rendered for search, speed, and sharing

Story

How to use UniCoreFW AuditLogger ?

Kenny Ngo (IIPTechian) Sep 21, 2026 0 comments

UniCoreFW AuditLogger

AuditLogger provides structured, thread-safe audit logging for security-sensitive application events. It writes audit records as UTF-8 JSON Lines and supports both secure file logging and integration with Python's standard logging framework.

Installation

Install UniCoreFW from PyPI:

pip install unicorefw

Import AuditLogger from the security module:

from unicorefw.security import AuditLogger

Quick Start

The recommended pattern uses AuditLogger as a context manager:

from unicorefw.security import AuditLogger

with AuditLogger(log_file="security.jsonl") as audit:
    audit.log(
        "USER_LOGIN",
        {
            "user_id": "42",
            "result": "success",
        },
    )

The context manager closes the internally managed log handler when execution leaves the with block.


Audit Record Format

Each call to log() produces a JSON object containing:

  • timestamp — UTC timestamp in ISO 8601 format
  • event_type — application-defined event identifier
  • details — event-specific data
  • message — human-readable representation of the event

Example:

{
  "timestamp": "2026-09-21T16:30:00.123456+00:00",
  "event_type": "USER_LOGIN",
  "details": {
    "user_id": "42",
    "result": "success"
  },
  "message": "USER_LOGIN: {'user_id': '42', 'result': 'success'}"
}

The file uses JSON Lines format, so each audit event occupies one line. The implementation serializes non-JSON-native values with their string representation rather than rejecting the event.


Logging Events

The primary API is:

audit.log(event_type, details)

Successful Login

audit.log(
    "LOGIN_SUCCESS",
    {
        "user_id": "user-1001",
        "ip_address": "192.0.2.10",
    },
)

Failed Login

audit.log(
    "LOGIN_FAILED",
    {
        "username": "kenny",
        "reason": "invalid_credentials",
    },
)

Access Denied

audit.log(
    "ACCESS_DENIED",
    {
        "user_id": "user-1001",
        "resource": "/admin/users",
        "action": "delete",
    },
)

Configuration Change

audit.log(
    "CONFIG_UPDATED",
    {
        "user_id": "admin-7",
        "component": "rate_limiter",
        "setting": "max_calls",
        "old_value": 100,
        "new_value": 200,
    },
)

Use stable event names so log collectors and SIEM systems can filter events without parsing free-form messages.


Manual Lifecycle Management

You can manage the logger without a context manager:

from unicorefw.security import AuditLogger

audit = AuditLogger("security.jsonl")

try:
    audit.log(
        "SERVICE_STARTED",
        {
            "service": "payments-api",
        },
    )
finally:
    audit.close()

close() removes and closes the file handler owned by the AuditLogger instance. Calling it again is safe because the method returns when no owned handler remains.


Using an Existing Python Logger

AuditLogger can send events through an existing logging.Logger instead of writing directly to its own file:

import logging

from unicorefw.security import AuditLogger

logger = logging.getLogger("application.audit")
logger.setLevel(logging.INFO)

handler = logging.StreamHandler()
logger.addHandler(handler)

audit = AuditLogger(logger=logger)

audit.log(
    "USER_CREATED",
    {
        "user_id": "user-2001",
        "created_by": "admin-7",
    },
)

When logger= is supplied, the supplied logger owns routing and handler management. log_file is not used.

UniCoreFW also places the structured event in the standard logging record:

record.audit_event

Internally, the call is equivalent to logging the serialized JSON message with:

extra={"audit_event": event}

This makes integration with custom formatters and centralized logging pipelines possible.


Secure File Handling

When AuditLogger manages its own file, UniCoreFW applies several protections.

Owner-Only Permissions

On platforms supporting fchmod, the audit file receives:

0600

This grants read and write access to the file owner while denying group and other users.

Append-Only File Access

The handler opens the destination with append semantics:

O_APPEND | O_CREAT | O_WRONLY

Existing audit records therefore remain in place when new records are written.

Symbolic-Link Protection

When the operating system provides O_NOFOLLOW, UniCoreFW enables it to prevent the audit destination from resolving through a symbolic link.

Regular Files Only

After opening the destination, UniCoreFW verifies that it is a regular file:

if not stat.S_ISREG(file_status.st_mode):
    raise SecurityError(...)

This blocks destinations such as devices or other unsupported filesystem objects.


Input Validation

event_type must contain non-empty text:

audit.log("", {})

raises InputValidationError.

An event type containing a null byte is also rejected:

audit.log("LOGIN\x00SUCCESS", {})

raises InputValidationError.


Handling Audit Write Failures

Filesystem failures from the secure file handler raise SecurityError.

from unicorefw.security import AuditLogger, SecurityError

try:
    with AuditLogger("/secure/path/audit.jsonl") as audit:
        audit.log(
            "ADMIN_ACTION",
            {
                "user_id": "admin-7",
                "action": "delete_user",
            },
        )
except SecurityError as exc:
    # Apply the application's security or availability policy.
    print(f"Audit logging failed: {exc}")

For security-sensitive systems, decide whether failure to persist an audit event should fail the associated operation, trigger an alert, or enter a degraded state.

The parent directory must already exist. AuditLogger opens the requested file directly and does not create missing directory trees. Filesystem failures are converted into SecurityError.


Security Guidelines

Do Not Log Secrets

Do not place credentials or secrets inside details.

Avoid:

audit.log(
    "LOGIN",
    {
        "username": "alice",
        "password": "super-secret-password",
        "access_token": "abc123",
    },
)

Prefer:

audit.log(
    "LOGIN",
    {
        "user_id": "user-1001",
        "result": "success",
        "authentication_method": "password",
    },
)

AuditLogger does not automatically redact sensitive values from details. Applications remain responsible for deciding which information may enter the audit trail.

Prefer Identifiers Over Payloads

Prefer:

{
    "user_id": "user-1001",
    "document_id": "doc-5832",
    "action": "delete"
}

over storing entire user records, documents, request bodies, or authentication credentials.

Use Consistent Event Names

A predictable naming scheme improves searching and alerting:

LOGIN_SUCCESS
LOGIN_FAILED
LOGOUT
ACCESS_GRANTED
ACCESS_DENIED
USER_CREATED
USER_UPDATED
USER_DELETED
CONFIG_UPDATED
RATE_LIMIT_EXCEEDED

Production Example

from unicorefw.security import AuditLogger


def delete_user(actor_id: str, target_user_id: str) -> None:
    with AuditLogger("/var/log/myapp/audit.jsonl") as audit:
        try:
            # Application operation
            remove_user(target_user_id)

            audit.log(
                "USER_DELETED",
                {
                    "actor_id": actor_id,
                    "target_user_id": target_user_id,
                    "result": "success",
                },
            )

        except Exception as exc:
            audit.log(
                "USER_DELETE_FAILED",
                {
                    "actor_id": actor_id,
                    "target_user_id": target_user_id,
                    "error_type": type(exc).__name__,
                },
            )
            raise

Notice that the failure event records the exception type rather than dumping the entire exception, request, or sensitive application state.


API Reference

Constructor

AuditLogger(
    log_file: str = "unicore_audit.log",
    logger: logging.Logger | None = None,
)
Parameter Description
log_file Destination for the internally managed secure audit file
logger Existing Python logging.Logger; when supplied, it controls event routing

log()

log(event_type: str, details: Any) -> None

Writes one structured audit event.

Parameter Description
event_type Non-empty event identifier
details Event metadata; JSON-compatible values are recommended

close()

close() -> None

Closes the internally owned file handler.

Context Manager

with AuditLogger(...) as audit:
    ...

The context manager calls close() on exit.


Recommended Pattern

For most applications:

from unicorefw.security import AuditLogger

with AuditLogger("audit.jsonl") as audit:
    audit.log(
        "RESOURCE_UPDATED",
        {
            "actor_id": "user-42",
            "resource_id": "resource-123",
            "result": "success",
        },
    )

Use the built-in file mode when you need UniCoreFW's secure local append behavior. Use logger= when your application already routes Python logging to systems such as syslog, Fluent Bit, Datadog, ELK, or another centralized logging pipeline.

Keep audit records structured, use stable event names, and exclude passwords, tokens, API keys, session data, and other secrets from details.