Skip to main content

A Python logging formatter implementing Google's glog format with microsecond precision and terminal color support.

Project description

glogformat

A Python logging formatter implementing Google's glog format with microsecond precision and terminal color support.

Features

  • glog-compatible format: Matches Google's glog format
  • Microsecond precision: Timestamps include microseconds for precise timing
  • Automatic color detection: Colors in terminal (TTY), plain text when redirected to files (no ANSI escape sequences in logs!)
  • UTC or local time: Configurable timezone for timestamps
  • File logging: Optional rotating file handler with error handling
  • Thread-safe: Proper locking for multi-threaded applications (including GIL-free Python 3.13+)
  • Robust: Handles edge cases like missing stderr or invalid timestamps

Installation

pip install glogformat

Quick Demo

Try the included demo application to see glogformat in action:

# Clone or download the demo
curl -O https://raw.githubusercontent.com/aleksa/glogformat/main/demo_app.py

# Run it (colored output in terminal)
python demo_app.py

# Or redirect to see plain text (no ANSI codes)
python demo_app.py > output.log
cat output.log

Quick Start

import argparse
import logging

from glogformat import setup_stderr_logging

# Set up logging before any other imports
setup_stderr_logging(logging.DEBUG)
log = logging.getLogger(__name__)


def parse_arguments() -> argparse.Namespace:
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(
        description="Example application using glogformat"
    )
    parser.add_argument(
        "--version",
        action="version",
        version="%(prog)s 1.0.0",
        help="Show program's version number and exit.",
    )
    return parser.parse_args()


def main() -> None:
    """Main function."""
    args = parse_arguments()

    # Nice logging in glog format with color!
    log.info("Starting!")
    log.debug("I'll divide by 0.")

    log.warning("Don't do it!")
    try:
        result = 1 // 0
    except ZeroDivisionError:
        log.exception("You tried to divide by 0!", exc_info=True)
        log.critical("Exiting soon!")

    log.info("Done!")


if __name__ == "__main__":
    main()

Output (with colors in terminal):

Demo output with colors

Format: L<YYYYMMDD HH:MM:SS.uuuuuu> <PID> <TID> <filename>:<line>] <message>

  • L: Log level (D=DEBUG, I=INFO, W=WARNING, E=ERROR, C=CRITICAL)
  • YYYYMMDD: Date
  • HH:MM:SS.uuuuuu: Time with microseconds
  • PID: Process ID
  • TID: Thread ID
  • filename:line: Source location

Multi-Module Applications

For applications with multiple files and modules, set up logging once at your application's entry point, then use logging.getLogger(__name__) in each module.

Project Structure

myapp/
├── main.py          # Entry point with logging setup
├── database.py      # Database module
└── api.py          # API module

main.py (Entry Point)

import logging

from glogformat import setup_stderr_logging

from myapp import api
from myapp import database

# Set up logging ONCE at application startup
setup_stderr_logging(logging.INFO)
log = logging.getLogger(__name__)


def main() -> None:
    """Main application entry point."""
    log.info("Application starting")

    database.connect()
    api.start_server()

    log.info("Application ready")


if __name__ == "__main__":
    main()

database.py (Module)

import logging

# Get logger for this module - inherits glog format from root
log = logging.getLogger(__name__)


def connect() -> None:
    """Connect to database."""
    log.info("Connecting to database")
    log.debug("Using connection pool size: 10")
    log.info("Database connected successfully")

api.py (Module)

import logging

# Get logger for this module - inherits glog format from root
log = logging.getLogger(__name__)


def start_server() -> None:
    """Start API server."""
    log.info("Starting API server on port 8080")
    log.debug("Loading middleware")
    log.info("API server started")

Output

All modules automatically use the glog format:

I20250117 14:32:15.123456 12345 67890 main.py:15] Application starting
I20250117 14:32:15.123489 12345 67890 database.py:10] Connecting to database
D20250117 14:32:15.123512 12345 67890 database.py:11] Using connection pool size: 10
I20250117 14:32:15.123535 12345 67890 database.py:12] Database connected successfully
I20250117 14:32:15.123567 12345 67890 api.py:10] Starting API server on port 8080
D20250117 14:32:15.123589 12345 67890 api.py:11] Loading middleware
I20250117 14:32:15.123612 12345 67890 api.py:12] API server started
I20250117 14:32:15.123634 12345 67890 main.py:20] Application ready

Key Points

  1. Setup once: Call setup_stderr_logging() only at your application's entry point
  2. Use __name__: Each module should use logging.getLogger(__name__) to get its logger
  3. Automatic propagation: All loggers inherit the glog format from the root logger
  4. Module identification: The filename in the log output shows which module logged the message

Third-Party Libraries

Third-party libraries automatically inherit the glog format through Python's logging propagation. No special configuration needed!

import logging
import requests  # Uses urllib3 internally

from glogformat import setup_stderr_logging

setup_stderr_logging(logging.DEBUG)
log = logging.getLogger(__name__)

# All logs (including from requests/urllib3) use glog format
log.info("Making HTTP request")
response = requests.get("https://api.example.com/data")
log.info("Request complete")

Output shows both your logs and third-party logs in glog format:

I20250117 14:32:15.123456 12345 67890 main.py:10] Making HTTP request
D20250117 14:32:15.123489 12345 67890 connectionpool.py:815] Starting new HTTPS connection
D20250117 14:32:15.234567 12345 67890 connectionpool.py:945] https://api.example.com:443 "GET /data HTTP/1.1" 200 1234
I20250117 14:32:15.234890 12345 67890 main.py:12] Request complete

Silencing Noisy Libraries

If third-party libraries log too much, you can silence them while keeping your own logs:

from glogformat import disable_child_propagation
from glogformat import setup_stderr_logging

setup_stderr_logging(logging.INFO)

# Silence noisy third-party loggers (completely suppresses their output)
disable_child_propagation("urllib3.connectionpool")
disable_child_propagation("asyncio")

# Your logs still appear in glog format, but urllib3/asyncio logs are hidden

Advanced Usage

Automatic Color Detection

Colors are automatically enabled for TTY (terminal) output and disabled when redirected to files. This prevents ANSI escape sequences from polluting your log files.

# Terminal output - colorized
python myapp.py

# File redirection - plain text, no ANSI codes
python myapp.py > output.log
python myapp.py 2>&1 | tee output.log

Terminal output (colorized):

[Colors shown in terminal with ANSI codes]
I20250117 14:32:15.123456 12345 67890 main.py:10] Starting!

File output (plain text):

I20250117 14:32:15.123456 12345 67890 main.py:10] Starting!

The file contains clean, readable text without any \x1b[36m or \x1b[0m sequences.

Force color on/off:

from glogformat import setup_stderr_logging

# Disable colors (even in terminal)
setup_stderr_logging(logging.INFO, color=False)

# Override with environment variable
# LOG_COLOR=0 python myapp.py    # Force off
# LOG_COLOR=1 python myapp.py    # Force on

File Logging with Rotation

from glogformat import setup_stderr_logging
import logging

# Log to both stderr and rotating file
setup_stderr_logging(
    logging.DEBUG,
    color=True,
    log_file="app.log",
    max_bytes=10_000_000,  # 10MB
    backup_count=5
)

UTC Timestamps

# Use UTC timestamps for distributed systems
setup_stderr_logging(logging.INFO, use_utc=True)

Environment Variables

Control logging via environment variables:

# Set log level
export LOG_LEVEL=DEBUG

# Control color output
export LOG_COLOR=1  # or 0 to disable

Disable Child Logger Propagation

from glogformat import setup_stderr_logging, disable_child_propagation
import logging

setup_stderr_logging(logging.INFO)

# Disable noisy child logger
disable_child_propagation("urllib3.connectionpool")

Format Specification

L<YYYYMMDD HH:MM:SS.uuuuuu> <PID> <TID> <filename>:<line>] <message>

Where:

  • L: Log level (D=DEBUG, I=INFO, W=WARNING, E=ERROR, C=CRITICAL)
  • YYYYMMDD: Date
  • HH:MM:SS.uuuuuu: Time with microseconds
  • PID: Process ID
  • TID: Thread ID (no padding, supports large IDs)
  • filename:line: Source location
  • message: Log message

Requirements

  • Python 3.10+
  • Linux or macOS (Windows untested)

License

MIT License - see LICENSE file for details.

Author

Maintained by Aleksa.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

glogformat-0.1.0.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

glogformat-0.1.0-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file glogformat-0.1.0.tar.gz.

File metadata

  • Download URL: glogformat-0.1.0.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for glogformat-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6edc9f2acde267926aaeac1f9be23d61ddf88a662f42479b43de8518e791f4f4
MD5 c7e222e7d3c7385f2b7483e63e969810
BLAKE2b-256 85e56614ffeac486c8c7a44e8b76ad94818c86bbd8bec44873cf62da686cb04e

See more details on using hashes here.

Provenance

The following attestation bundles were made for glogformat-0.1.0.tar.gz:

Publisher: publish.yml on aleksa/glogformat

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file glogformat-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: glogformat-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for glogformat-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2fd0a9e1d15b85cd55266eaf5d3e7d585a8d05b6cfd20105d5255779f91746a4
MD5 9574f070c70eef015cb9e2999f181eb8
BLAKE2b-256 62fd4c4aaebe9bcfa6f536c8cc0c3e0ddf91a0366da7b073f7b5b1b35d30678b

See more details on using hashes here.

Provenance

The following attestation bundles were made for glogformat-0.1.0-py3-none-any.whl:

Publisher: publish.yml on aleksa/glogformat

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page