glogformat


Nameglogformat JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummaryA Python logging formatter implementing Google's glog format with microsecond precision and terminal color support.
upload_time2025-10-18 01:23:14
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords glog logging formatter python terminal colors
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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

```bash
pip install glogformat
```

## Quick Demo

Try the included demo application to see glogformat in action:

```bash
# 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

```python
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](demo_app_screenshot.png)

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)

```python
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)

```python
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)

```python
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:

```text
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!

```python
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:

```text
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:

```python
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.

```bash
# 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):
```text
[Colors shown in terminal with ANSI codes]
I20250117 14:32:15.123456 12345 67890 main.py:10] Starting!
```

**File output** (plain text):
```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:**

```python
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

```python
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

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

### Environment Variables

Control logging via environment variables:

```bash
# Set log level
export LOG_LEVEL=DEBUG

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

### Disable Child Logger Propagation

```python
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

```text
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.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "glogformat",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "glog, logging, formatter, python, terminal, colors",
    "author": null,
    "author_email": "Aleksandar Veselinovic <aleksa@users.noreply.github.com>",
    "download_url": "https://files.pythonhosted.org/packages/85/e5/6614ffeac486c8c7a44e8b76ad94818c86bbd8bec44873cf62da686cb04e/glogformat-0.1.0.tar.gz",
    "platform": null,
    "description": "# glogformat\n\nA Python logging formatter implementing Google's glog format with\nmicrosecond precision and terminal color support.\n\n## Features\n\n- **glog-compatible format**: Matches Google's glog format\n- **Microsecond precision**: Timestamps include microseconds for precise timing\n- **Automatic color detection**: Colors in terminal (TTY), plain text when\n  redirected to files (no ANSI escape sequences in logs!)\n- **UTC or local time**: Configurable timezone for timestamps\n- **File logging**: Optional rotating file handler with error handling\n- **Thread-safe**: Proper locking for multi-threaded applications (including\n  GIL-free Python 3.13+)\n- **Robust**: Handles edge cases like missing stderr or invalid timestamps\n\n## Installation\n\n```bash\npip install glogformat\n```\n\n## Quick Demo\n\nTry the included demo application to see glogformat in action:\n\n```bash\n# Clone or download the demo\ncurl -O https://raw.githubusercontent.com/aleksa/glogformat/main/demo_app.py\n\n# Run it (colored output in terminal)\npython demo_app.py\n\n# Or redirect to see plain text (no ANSI codes)\npython demo_app.py > output.log\ncat output.log\n```\n\n## Quick Start\n\n```python\nimport argparse\nimport logging\n\nfrom glogformat import setup_stderr_logging\n\n# Set up logging before any other imports\nsetup_stderr_logging(logging.DEBUG)\nlog = logging.getLogger(__name__)\n\n\ndef parse_arguments() -> argparse.Namespace:\n    \"\"\"Parse command line arguments.\"\"\"\n    parser = argparse.ArgumentParser(\n        description=\"Example application using glogformat\"\n    )\n    parser.add_argument(\n        \"--version\",\n        action=\"version\",\n        version=\"%(prog)s 1.0.0\",\n        help=\"Show program's version number and exit.\",\n    )\n    return parser.parse_args()\n\n\ndef main() -> None:\n    \"\"\"Main function.\"\"\"\n    args = parse_arguments()\n\n    # Nice logging in glog format with color!\n    log.info(\"Starting!\")\n    log.debug(\"I'll divide by 0.\")\n\n    log.warning(\"Don't do it!\")\n    try:\n        result = 1 // 0\n    except ZeroDivisionError:\n        log.exception(\"You tried to divide by 0!\", exc_info=True)\n        log.critical(\"Exiting soon!\")\n\n    log.info(\"Done!\")\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\nOutput (with colors in terminal):\n\n![Demo output with colors](demo_app_screenshot.png)\n\nFormat: `L<YYYYMMDD HH:MM:SS.uuuuuu> <PID> <TID> <filename>:<line>] <message>`\n\n- **L**: Log level (D=DEBUG, I=INFO, W=WARNING, E=ERROR, C=CRITICAL)\n- **YYYYMMDD**: Date\n- **HH:MM:SS.uuuuuu**: Time with microseconds\n- **PID**: Process ID\n- **TID**: Thread ID\n- **filename:line**: Source location\n\n## Multi-Module Applications\n\nFor applications with multiple files and modules, set up logging **once** at\nyour application's entry point, then use `logging.getLogger(__name__)` in\neach module.\n\n### Project Structure\n\n```\nmyapp/\n\u251c\u2500\u2500 main.py          # Entry point with logging setup\n\u251c\u2500\u2500 database.py      # Database module\n\u2514\u2500\u2500 api.py          # API module\n```\n\n### main.py (Entry Point)\n\n```python\nimport logging\n\nfrom glogformat import setup_stderr_logging\n\nfrom myapp import api\nfrom myapp import database\n\n# Set up logging ONCE at application startup\nsetup_stderr_logging(logging.INFO)\nlog = logging.getLogger(__name__)\n\n\ndef main() -> None:\n    \"\"\"Main application entry point.\"\"\"\n    log.info(\"Application starting\")\n\n    database.connect()\n    api.start_server()\n\n    log.info(\"Application ready\")\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\n### database.py (Module)\n\n```python\nimport logging\n\n# Get logger for this module - inherits glog format from root\nlog = logging.getLogger(__name__)\n\n\ndef connect() -> None:\n    \"\"\"Connect to database.\"\"\"\n    log.info(\"Connecting to database\")\n    log.debug(\"Using connection pool size: 10\")\n    log.info(\"Database connected successfully\")\n```\n\n### api.py (Module)\n\n```python\nimport logging\n\n# Get logger for this module - inherits glog format from root\nlog = logging.getLogger(__name__)\n\n\ndef start_server() -> None:\n    \"\"\"Start API server.\"\"\"\n    log.info(\"Starting API server on port 8080\")\n    log.debug(\"Loading middleware\")\n    log.info(\"API server started\")\n```\n\n### Output\n\nAll modules automatically use the glog format:\n\n```text\nI20250117 14:32:15.123456 12345 67890 main.py:15] Application starting\nI20250117 14:32:15.123489 12345 67890 database.py:10] Connecting to database\nD20250117 14:32:15.123512 12345 67890 database.py:11] Using connection pool size: 10\nI20250117 14:32:15.123535 12345 67890 database.py:12] Database connected successfully\nI20250117 14:32:15.123567 12345 67890 api.py:10] Starting API server on port 8080\nD20250117 14:32:15.123589 12345 67890 api.py:11] Loading middleware\nI20250117 14:32:15.123612 12345 67890 api.py:12] API server started\nI20250117 14:32:15.123634 12345 67890 main.py:20] Application ready\n```\n\n### Key Points\n\n1. **Setup once**: Call `setup_stderr_logging()` only at your application's\n   entry point\n2. **Use `__name__`**: Each module should use `logging.getLogger(__name__)`\n   to get its logger\n3. **Automatic propagation**: All loggers inherit the glog format from the\n   root logger\n4. **Module identification**: The filename in the log output shows which\n   module logged the message\n\n### Third-Party Libraries\n\nThird-party libraries automatically inherit the glog format through Python's\nlogging propagation. No special configuration needed!\n\n```python\nimport logging\nimport requests  # Uses urllib3 internally\n\nfrom glogformat import setup_stderr_logging\n\nsetup_stderr_logging(logging.DEBUG)\nlog = logging.getLogger(__name__)\n\n# All logs (including from requests/urllib3) use glog format\nlog.info(\"Making HTTP request\")\nresponse = requests.get(\"https://api.example.com/data\")\nlog.info(\"Request complete\")\n```\n\nOutput shows both your logs and third-party logs in glog format:\n\n```text\nI20250117 14:32:15.123456 12345 67890 main.py:10] Making HTTP request\nD20250117 14:32:15.123489 12345 67890 connectionpool.py:815] Starting new HTTPS connection\nD20250117 14:32:15.234567 12345 67890 connectionpool.py:945] https://api.example.com:443 \"GET /data HTTP/1.1\" 200 1234\nI20250117 14:32:15.234890 12345 67890 main.py:12] Request complete\n```\n\n**Silencing Noisy Libraries**\n\nIf third-party libraries log too much, you can silence them while keeping your own logs:\n\n```python\nfrom glogformat import disable_child_propagation\nfrom glogformat import setup_stderr_logging\n\nsetup_stderr_logging(logging.INFO)\n\n# Silence noisy third-party loggers (completely suppresses their output)\ndisable_child_propagation(\"urllib3.connectionpool\")\ndisable_child_propagation(\"asyncio\")\n\n# Your logs still appear in glog format, but urllib3/asyncio logs are hidden\n```\n\n## Advanced Usage\n\n### Automatic Color Detection\n\nColors are automatically enabled for TTY (terminal) output and disabled when\nredirected to files. This prevents ANSI escape sequences from polluting your\nlog files.\n\n```bash\n# Terminal output - colorized\npython myapp.py\n\n# File redirection - plain text, no ANSI codes\npython myapp.py > output.log\npython myapp.py 2>&1 | tee output.log\n```\n\n**Terminal output** (colorized):\n```text\n[Colors shown in terminal with ANSI codes]\nI20250117 14:32:15.123456 12345 67890 main.py:10] Starting!\n```\n\n**File output** (plain text):\n```text\nI20250117 14:32:15.123456 12345 67890 main.py:10] Starting!\n```\n\nThe file contains clean, readable text without any `\\x1b[36m` or `\\x1b[0m`\nsequences.\n\n**Force color on/off:**\n\n```python\nfrom glogformat import setup_stderr_logging\n\n# Disable colors (even in terminal)\nsetup_stderr_logging(logging.INFO, color=False)\n\n# Override with environment variable\n# LOG_COLOR=0 python myapp.py    # Force off\n# LOG_COLOR=1 python myapp.py    # Force on\n```\n\n### File Logging with Rotation\n\n```python\nfrom glogformat import setup_stderr_logging\nimport logging\n\n# Log to both stderr and rotating file\nsetup_stderr_logging(\n    logging.DEBUG,\n    color=True,\n    log_file=\"app.log\",\n    max_bytes=10_000_000,  # 10MB\n    backup_count=5\n)\n```\n\n### UTC Timestamps\n\n```python\n# Use UTC timestamps for distributed systems\nsetup_stderr_logging(logging.INFO, use_utc=True)\n```\n\n### Environment Variables\n\nControl logging via environment variables:\n\n```bash\n# Set log level\nexport LOG_LEVEL=DEBUG\n\n# Control color output\nexport LOG_COLOR=1  # or 0 to disable\n```\n\n### Disable Child Logger Propagation\n\n```python\nfrom glogformat import setup_stderr_logging, disable_child_propagation\nimport logging\n\nsetup_stderr_logging(logging.INFO)\n\n# Disable noisy child logger\ndisable_child_propagation(\"urllib3.connectionpool\")\n```\n\n## Format Specification\n\n```text\nL<YYYYMMDD HH:MM:SS.uuuuuu> <PID> <TID> <filename>:<line>] <message>\n```\n\nWhere:\n\n- `L`: Log level (D=DEBUG, I=INFO, W=WARNING, E=ERROR, C=CRITICAL)\n- `YYYYMMDD`: Date\n- `HH:MM:SS.uuuuuu`: Time with microseconds\n- `PID`: Process ID\n- `TID`: Thread ID (no padding, supports large IDs)\n- `filename:line`: Source location\n- `message`: Log message\n\n## Requirements\n\n- Python 3.10+\n- Linux or macOS (Windows untested)\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Author\n\nMaintained by Aleksa.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A Python logging formatter implementing Google's glog format with microsecond precision and terminal color support.",
    "version": "0.1.0",
    "project_urls": {
        "Documentation": "https://github.com/aleksa/glogformat",
        "Homepage": "https://github.com/aleksa/glogformat"
    },
    "split_keywords": [
        "glog",
        " logging",
        " formatter",
        " python",
        " terminal",
        " colors"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "62fd4c4aaebe9bcfa6f536c8cc0c3e0ddf91a0366da7b073f7b5b1b35d30678b",
                "md5": "9574f070c70eef015cb9e2999f181eb8",
                "sha256": "2fd0a9e1d15b85cd55266eaf5d3e7d585a8d05b6cfd20105d5255779f91746a4"
            },
            "downloads": -1,
            "filename": "glogformat-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9574f070c70eef015cb9e2999f181eb8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 10191,
            "upload_time": "2025-10-18T01:23:13",
            "upload_time_iso_8601": "2025-10-18T01:23:13.424819Z",
            "url": "https://files.pythonhosted.org/packages/62/fd/4c4aaebe9bcfa6f536c8cc0c3e0ddf91a0366da7b073f7b5b1b35d30678b/glogformat-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "85e56614ffeac486c8c7a44e8b76ad94818c86bbd8bec44873cf62da686cb04e",
                "md5": "c7e222e7d3c7385f2b7483e63e969810",
                "sha256": "6edc9f2acde267926aaeac1f9be23d61ddf88a662f42479b43de8518e791f4f4"
            },
            "downloads": -1,
            "filename": "glogformat-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "c7e222e7d3c7385f2b7483e63e969810",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 18344,
            "upload_time": "2025-10-18T01:23:14",
            "upload_time_iso_8601": "2025-10-18T01:23:14.778229Z",
            "url": "https://files.pythonhosted.org/packages/85/e5/6614ffeac486c8c7a44e8b76ad94818c86bbd8bec44873cf62da686cb04e/glogformat-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-18 01:23:14",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "aleksa",
    "github_project": "glogformat",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "glogformat"
}
        
Elapsed time: 1.05384s