Metadata-Version: 2.4
Name: toolslog
Version: 0.1.3
Summary: Opinionated Python logging config for local dev and Cloud Run/Functions
Author: MH
License-Expression: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# toolslog

Opinionated Python logging configuration. One import configures everything.

- **Locally**: human-readable plain text to stdout
- **Cloud Run / Cloud Functions**: structured JSON with `severity` field (auto-detected)
- **Zero dependencies** — stdlib only

## Install

```bash
pip install toolslog
```

## Quick start

```python
from toolslog import get_logger
logger = get_logger(__file__)

logger.debug("verbose detail")         # hidden by default (level=INFO)
logger.info("normal flow")
logger.warning("potential issue")
logger.error("something failed")
logger.critical("system-level failure")
```

Output (local):
```
2026-02-26 15:03:17 | INFO | main | run:5 | normal flow
2026-02-26 15:03:17 | WARNING | main | run:6 | potential issue
2026-02-26 15:03:17 | ERROR | main | run:7 | something failed
2026-02-26 15:03:17 | CRITICAL | main | run:8 | system-level failure
```

Output (Cloud Run — auto-detected):
```json
{"severity": "INFO", "message": "normal flow", "logger": "main", ...}
```

## Log level control

Default level is **INFO**. Override via `LOG_LEVEL` environment variable.

```bash
# everything DEBUG (all modules):
LOG_LEVEL=DEBUG python main.py

# check / set / unset in current shell session:
echo $LOG_LEVEL
export LOG_LEVEL=DEBUG
unset LOG_LEVEL
```

Per-module overrides (in your script):

```python
import logging

# only this script to DEBUG (imported modules stay at INFO):
logger.setLevel(logging.DEBUG)

# only a specific library to DEBUG:
logging.getLogger("toolsbq").setLevel(logging.DEBUG)

# silence a noisy library:
logging.getLogger("toolsbq").setLevel(logging.WARNING)

# suppress urllib3 connection/retry warnings:
logging.getLogger("urllib3").setLevel(logging.WARNING)

# suppress google-auth / google-api / discovery noise:
logging.getLogger("google").setLevel(logging.WARNING)
logging.getLogger("googleapiclient.discovery_cache").setLevel(logging.ERROR)
```

## Searching logs

```bash
# errors and tracebacks:
grep -E "(\| ERROR \||\| CRITICAL \||Traceback|Error:|Exception:)" app.log

# warnings and above:
grep -E "\| (WARNING|ERROR|CRITICAL) \|" app.log

# specific module:
grep "| toolsbq |" app.log

# specific function (line number varies, so use a pattern):
grep "| fetch_data:" app.log
```

## For libraries (toolsbq, toolssecret, etc.)

Libraries should **not** import toolslog. Just use the stdlib:

```python
import logging
logger = logging.getLogger(__name__)
```

The calling application (which imports toolslog) configures the root logger.
Libraries automatically inherit that configuration.

## How it works

On import, toolslog:

1. Detects environment (GCP vs local) via env vars (`K_SERVICE`, `FUNCTION_TARGET`, etc.)
2. Clears any existing root logger handlers (e.g. from `functions_framework`)
3. Adds a single handler with the appropriate formatter
4. Sets the root level from `LOG_LEVEL` env var (default: `INFO`)

This runs once — Python caches the import, so multiple `from toolslog import get_logger`
calls across modules are safe.

## Note

This package is opinionated — it takes over the root logger. Use it in your own
entry-point scripts, not in libraries you publish for others.
