| Name | structlog-config JSON |
| Version |
0.6.0
JSON |
| download |
| home_page | None |
| Summary | A comprehensive structlog configuration with sensible defaults for development and production environments, featuring context management, exception formatting, and path prettification. |
| upload_time | 2025-11-06 00:21:34 |
| maintainer | None |
| docs_url | None |
| author | Michael Bianco |
| requires_python | >=3.11 |
| license | None |
| keywords |
logging
structlog
json-logging
structured-logging
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# Opinionated Defaults for Structlog
Logging is really important. Getting logging to work well in python feels like black magic: there's a ton of configuration
across structlog, warnings, std loggers, fastapi + celery context, JSON logging in production, etc that requires lots of
fiddling and testing to get working. I finally got this working for me in my [project template](https://github.com/iloveitaly/python-starter-template) and extracted this out into a nice package.
Here are the main goals:
* High performance JSON logging in production
* All loggers, even plugin or system loggers, should route through the same formatter
* Structured logging everywhere
* Ability to easily set thread-local log context
* Nice log formatters for stack traces, ORM ([ActiveModel/SQLModel](https://github.com/iloveitaly/activemodel)), etc
* Ability to log level and output (i.e. file path) *by logger* for easy development debugging
* If you are using fastapi, structured logging for access logs
## Installation
```bash
pip install structlog-config
```
Or with [uv](https://docs.astral.sh/uv/):
```bash
uv add structlog-config
```
## Usage
```python
from structlog_config import configure_logger
log = configure_logger()
log.info("the log", key="value")
```
## JSON Logging for Production
JSON logging is automatically enabled in production and staging environments (`PYTHON_ENV=production` or `PYTHON_ENV=staging`):
```python
from structlog_config import configure_logger
# Automatic JSON logging in production
log = configure_logger()
log.info("User login", user_id="123", action="login")
# Output: {"action":"login","event":"User login","level":"info","timestamp":"2025-09-24T18:03:00Z","user_id":"123"}
# Force JSON logging regardless of environment
log = configure_logger(json_logger=True)
# Force console logging regardless of environment
log = configure_logger(json_logger=False)
```
JSON logs use [orjson](https://github.com/ijl/orjson) for performance, include sorted keys and ISO timestamps, and serialize exceptions cleanly. Note that `PYTHON_LOG_PATH` is ignored with JSON logging (stdout only).
## TRACE Logging Level
This package adds support for a custom `TRACE` logging level (level 5) that's even more verbose than `DEBUG`. This is useful for extremely detailed debugging scenarios.
The `TRACE` level is automatically set up when you call `configure_logger()`. You can use it like any other logging level:
```python
import logging
from structlog_config import configure_logger
log = configure_logger()
# Using structlog
log.info("This is info")
log.debug("This is debug")
log.trace("This is trace") # Most verbose
# Using stdlib logging
logging.trace("Module-level trace message")
logger = logging.getLogger(__name__)
logger.trace("Instance trace message")
```
Set the log level to TRACE using the environment variable:
```bash
LOG_LEVEL=TRACE
```
## Stdlib Log Management
By default, all stdlib loggers are:
1. Given the same global logging level, with some default adjustments for noisy loggers (looking at you, `httpx`)
2. Use a structlog formatter (you get structured logging, context, etc in any stdlib logger calls)
3. The root processor is overwritten so any child loggers created after initialization will use the same formatter
You can customize loggers by name (i.e. the name used in `logging.getLogger(__name__)`) using ENV variables.
For example, if you wanted to [mimic `OPENAI_LOG` functionality](https://github.com/openai/openai-python/blob/de7c0e2d9375d042a42e3db6c17e5af9a5701a99/src/openai/_utils/_logs.py#L16):
* `LOG_LEVEL_OPENAI=DEBUG`
* `LOG_PATH_OPENAI=tmp/openai.log`
* `LOG_LEVEL_HTTPX=DEBUG`
* `LOG_PATH_HTTPX=tmp/openai.log`
## FastAPI Access Logger
**Note:** Requires `pip install structlog-config[fastapi]` for FastAPI dependencies.
Structured, simple access log with request timing to replace the default fastapi access log. Why?
1. It's less verbose
2. Uses structured logging params instead of string interpolation
3. debug level logs any static assets
Here's how to use it:
1. [Disable fastapi's default logging.](https://github.com/iloveitaly/python-starter-template/blob/f54cb47d8d104987f2e4a668f9045a62e0d6818a/main.py#L55-L56)
2. [Add the middleware to your FastAPI app.](https://github.com/iloveitaly/python-starter-template/blob/f54cb47d8d104987f2e4a668f9045a62e0d6818a/app/routes/middleware/__init__.py#L63-L65)
## Pytest Plugin: Capture Logs on Failure
A pytest plugin that captures logs per-test and displays them only when tests fail. This keeps your test output clean while ensuring you have all the debugging information you need when something goes wrong.
### Features
- Only shows logs for failing tests (keeps output clean)
- Captures logs from all test phases (setup, call, teardown)
- Unique log file per test
- Optional persistent log storage for debugging
- Automatically handles `PYTHON_LOG_PATH` environment variable
### Usage
Enable the plugin with the `--capture-logs-on-fail` flag:
```bash
pytest --capture-logs-on-fail
```
Or enable it permanently in `pytest.ini` or `pyproject.toml`:
```toml
[tool.pytest.ini_options]
addopts = ["--capture-logs-on-fail"]
```
### Persist Logs to Directory
To keep all test logs for later inspection (useful for CI/CD debugging):
```bash
pytest --capture-logs-dir=./test-logs
```
This creates a log file for each test and disables automatic cleanup.
### How It Works
1. Sets `PYTHON_LOG_PATH` environment variable to a unique temp file for each test
2. Your application logs (via `configure_logger()`) write to this file
3. On test failure, the plugin prints the captured logs to stdout
4. Log files are cleaned up after the test session (unless `--capture-logs-dir` is used)
### Example Output
When a test fails, you'll see:
```
FAILED tests/test_user.py::test_user_login
--- Captured logs for failed test (call): tests/test_user.py::test_user_login ---
2025-11-01 18:30:00 [info] User login started user_id=123
2025-11-01 18:30:01 [error] Database connection failed timeout=5.0
```
For passing tests, no log output is shown, keeping your test output clean and focused.
## iPython
Often it's helpful to update logging level within an iPython session. You can do this and make sure all loggers pick up on it.
```
%env LOG_LEVEL=DEBUG
from structlog_config import configure_logger
configure_logger()
```
## Related Projects
* https://github.com/underyx/structlog-pretty
* https://pypi.org/project/httpx-structlog/
## References
General logging:
- https://github.com/replicate/cog/blob/2e57549e18e044982bd100e286a1929f50880383/python/cog/logging.py#L20
- https://github.com/apache/airflow/blob/4280b83977cd5a53c2b24143f3c9a6a63e298acc/task_sdk/src/airflow/sdk/log.py#L187
- https://github.com/kiwicom/structlog-sentry
- https://github.com/jeremyh/datacube-explorer/blob/b289b0cde0973a38a9d50233fe0fff00e8eb2c8e/cubedash/logs.py#L40C21-L40C42
- https://stackoverflow.com/questions/76256249/logging-in-the-open-ai-python-library/78214464#78214464
- https://github.com/openai/openai-python/blob/de7c0e2d9375d042a42e3db6c17e5af9a5701a99/src/openai/_utils/_logs.py#L16
- https://www.python-httpx.org/logging/
FastAPI access logger:
- https://github.com/iloveitaly/fastapi-logger/blob/main/fastapi_structlog/middleware/access_log.py#L70
- https://github.com/fastapiutils/fastapi-utils/blob/master/fastapi_utils/timing.py
- https://pypi.org/project/fastapi-structlog/
- https://pypi.org/project/asgi-correlation-id/
- https://gist.github.com/nymous/f138c7f06062b7c43c060bf03759c29e
- https://github.com/sharu1204/fastapi-structlog/blob/master/app/main.py
Raw data
{
"_id": null,
"home_page": null,
"name": "structlog-config",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "logging, structlog, json-logging, structured-logging",
"author": "Michael Bianco",
"author_email": "Michael Bianco <mike@mikebian.co>",
"download_url": "https://files.pythonhosted.org/packages/ea/4e/bf39c1ea6a418649862d140480a838b64d530fa06e02fed0ce5b78f0badb/structlog_config-0.6.0.tar.gz",
"platform": null,
"description": "# Opinionated Defaults for Structlog\n\nLogging is really important. Getting logging to work well in python feels like black magic: there's a ton of configuration\nacross structlog, warnings, std loggers, fastapi + celery context, JSON logging in production, etc that requires lots of\nfiddling and testing to get working. I finally got this working for me in my [project template](https://github.com/iloveitaly/python-starter-template) and extracted this out into a nice package.\n\nHere are the main goals:\n\n* High performance JSON logging in production\n* All loggers, even plugin or system loggers, should route through the same formatter\n* Structured logging everywhere\n* Ability to easily set thread-local log context\n* Nice log formatters for stack traces, ORM ([ActiveModel/SQLModel](https://github.com/iloveitaly/activemodel)), etc\n* Ability to log level and output (i.e. file path) *by logger* for easy development debugging\n* If you are using fastapi, structured logging for access logs\n\n## Installation\n\n```bash\npip install structlog-config\n```\n\nOr with [uv](https://docs.astral.sh/uv/):\n\n```bash\nuv add structlog-config\n```\n\n## Usage\n\n```python\nfrom structlog_config import configure_logger\n\nlog = configure_logger()\n\nlog.info(\"the log\", key=\"value\")\n```\n\n## JSON Logging for Production\n\nJSON logging is automatically enabled in production and staging environments (`PYTHON_ENV=production` or `PYTHON_ENV=staging`):\n\n```python\nfrom structlog_config import configure_logger\n\n# Automatic JSON logging in production\nlog = configure_logger()\nlog.info(\"User login\", user_id=\"123\", action=\"login\")\n# Output: {\"action\":\"login\",\"event\":\"User login\",\"level\":\"info\",\"timestamp\":\"2025-09-24T18:03:00Z\",\"user_id\":\"123\"}\n\n# Force JSON logging regardless of environment\nlog = configure_logger(json_logger=True)\n\n# Force console logging regardless of environment\nlog = configure_logger(json_logger=False)\n```\n\nJSON logs use [orjson](https://github.com/ijl/orjson) for performance, include sorted keys and ISO timestamps, and serialize exceptions cleanly. Note that `PYTHON_LOG_PATH` is ignored with JSON logging (stdout only).\n\n## TRACE Logging Level\n\nThis package adds support for a custom `TRACE` logging level (level 5) that's even more verbose than `DEBUG`. This is useful for extremely detailed debugging scenarios.\n\nThe `TRACE` level is automatically set up when you call `configure_logger()`. You can use it like any other logging level:\n\n```python\nimport logging\nfrom structlog_config import configure_logger\n\nlog = configure_logger()\n\n# Using structlog\nlog.info(\"This is info\")\nlog.debug(\"This is debug\") \nlog.trace(\"This is trace\") # Most verbose\n\n# Using stdlib logging\nlogging.trace(\"Module-level trace message\")\nlogger = logging.getLogger(__name__)\nlogger.trace(\"Instance trace message\")\n```\n\nSet the log level to TRACE using the environment variable:\n\n```bash\nLOG_LEVEL=TRACE\n```\n\n## Stdlib Log Management\n\nBy default, all stdlib loggers are:\n\n1. Given the same global logging level, with some default adjustments for noisy loggers (looking at you, `httpx`)\n2. Use a structlog formatter (you get structured logging, context, etc in any stdlib logger calls)\n3. The root processor is overwritten so any child loggers created after initialization will use the same formatter\n\nYou can customize loggers by name (i.e. the name used in `logging.getLogger(__name__)`) using ENV variables.\n\nFor example, if you wanted to [mimic `OPENAI_LOG` functionality](https://github.com/openai/openai-python/blob/de7c0e2d9375d042a42e3db6c17e5af9a5701a99/src/openai/_utils/_logs.py#L16):\n\n* `LOG_LEVEL_OPENAI=DEBUG`\n* `LOG_PATH_OPENAI=tmp/openai.log`\n* `LOG_LEVEL_HTTPX=DEBUG`\n* `LOG_PATH_HTTPX=tmp/openai.log`\n\n## FastAPI Access Logger\n\n**Note:** Requires `pip install structlog-config[fastapi]` for FastAPI dependencies.\n\nStructured, simple access log with request timing to replace the default fastapi access log. Why?\n\n1. It's less verbose\n2. Uses structured logging params instead of string interpolation\n3. debug level logs any static assets\n\nHere's how to use it:\n\n1. [Disable fastapi's default logging.](https://github.com/iloveitaly/python-starter-template/blob/f54cb47d8d104987f2e4a668f9045a62e0d6818a/main.py#L55-L56)\n2. [Add the middleware to your FastAPI app.](https://github.com/iloveitaly/python-starter-template/blob/f54cb47d8d104987f2e4a668f9045a62e0d6818a/app/routes/middleware/__init__.py#L63-L65)\n\n## Pytest Plugin: Capture Logs on Failure\n\nA pytest plugin that captures logs per-test and displays them only when tests fail. This keeps your test output clean while ensuring you have all the debugging information you need when something goes wrong.\n\n### Features\n\n- Only shows logs for failing tests (keeps output clean)\n- Captures logs from all test phases (setup, call, teardown)\n- Unique log file per test\n- Optional persistent log storage for debugging\n- Automatically handles `PYTHON_LOG_PATH` environment variable\n\n### Usage\n\nEnable the plugin with the `--capture-logs-on-fail` flag:\n\n```bash\npytest --capture-logs-on-fail\n```\n\nOr enable it permanently in `pytest.ini` or `pyproject.toml`:\n\n```toml\n[tool.pytest.ini_options]\naddopts = [\"--capture-logs-on-fail\"]\n```\n\n### Persist Logs to Directory\n\nTo keep all test logs for later inspection (useful for CI/CD debugging):\n\n```bash\npytest --capture-logs-dir=./test-logs\n```\n\nThis creates a log file for each test and disables automatic cleanup.\n\n### How It Works\n\n1. Sets `PYTHON_LOG_PATH` environment variable to a unique temp file for each test\n2. Your application logs (via `configure_logger()`) write to this file\n3. On test failure, the plugin prints the captured logs to stdout\n4. Log files are cleaned up after the test session (unless `--capture-logs-dir` is used)\n\n### Example Output\n\nWhen a test fails, you'll see:\n\n```\nFAILED tests/test_user.py::test_user_login\n\n--- Captured logs for failed test (call): tests/test_user.py::test_user_login ---\n2025-11-01 18:30:00 [info] User login started user_id=123\n2025-11-01 18:30:01 [error] Database connection failed timeout=5.0\n```\n\nFor passing tests, no log output is shown, keeping your test output clean and focused.\n\n## iPython\n\nOften it's helpful to update logging level within an iPython session. You can do this and make sure all loggers pick up on it.\n\n```\n%env LOG_LEVEL=DEBUG\nfrom structlog_config import configure_logger\nconfigure_logger()\n```\n\n## Related Projects\n\n* https://github.com/underyx/structlog-pretty\n* https://pypi.org/project/httpx-structlog/\n\n## References\n\nGeneral logging:\n\n- https://github.com/replicate/cog/blob/2e57549e18e044982bd100e286a1929f50880383/python/cog/logging.py#L20\n- https://github.com/apache/airflow/blob/4280b83977cd5a53c2b24143f3c9a6a63e298acc/task_sdk/src/airflow/sdk/log.py#L187\n- https://github.com/kiwicom/structlog-sentry\n- https://github.com/jeremyh/datacube-explorer/blob/b289b0cde0973a38a9d50233fe0fff00e8eb2c8e/cubedash/logs.py#L40C21-L40C42\n- https://stackoverflow.com/questions/76256249/logging-in-the-open-ai-python-library/78214464#78214464\n- https://github.com/openai/openai-python/blob/de7c0e2d9375d042a42e3db6c17e5af9a5701a99/src/openai/_utils/_logs.py#L16\n- https://www.python-httpx.org/logging/\n\nFastAPI access logger:\n\n- https://github.com/iloveitaly/fastapi-logger/blob/main/fastapi_structlog/middleware/access_log.py#L70\n- https://github.com/fastapiutils/fastapi-utils/blob/master/fastapi_utils/timing.py\n- https://pypi.org/project/fastapi-structlog/\n- https://pypi.org/project/asgi-correlation-id/\n- https://gist.github.com/nymous/f138c7f06062b7c43c060bf03759c29e\n- https://github.com/sharu1204/fastapi-structlog/blob/master/app/main.py\n",
"bugtrack_url": null,
"license": null,
"summary": "A comprehensive structlog configuration with sensible defaults for development and production environments, featuring context management, exception formatting, and path prettification.",
"version": "0.6.0",
"project_urls": {
"Repository": "https://github.com/iloveitaly/structlog-config"
},
"split_keywords": [
"logging",
" structlog",
" json-logging",
" structured-logging"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "2490b5e7b5478ae89e2f6c273ecb1b6114fc8b66def5ba0bae08e7f992adc2a3",
"md5": "08f2908215373b0f73e9c2e4db0606a6",
"sha256": "61683cbf81b2a73b459f2e3157fd0588e77c37da33e43261bce11a4d4d83078b"
},
"downloads": -1,
"filename": "structlog_config-0.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "08f2908215373b0f73e9c2e4db0606a6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 21370,
"upload_time": "2025-11-06T00:21:32",
"upload_time_iso_8601": "2025-11-06T00:21:32.829381Z",
"url": "https://files.pythonhosted.org/packages/24/90/b5e7b5478ae89e2f6c273ecb1b6114fc8b66def5ba0bae08e7f992adc2a3/structlog_config-0.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "ea4ebf39c1ea6a418649862d140480a838b64d530fa06e02fed0ce5b78f0badb",
"md5": "d6f7ab83013495bfc0d02721fd6f52f6",
"sha256": "048b8dfbef80a76f36faf98b69281de51bb90eba860c66f2d913bb5a0bde3e5a"
},
"downloads": -1,
"filename": "structlog_config-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "d6f7ab83013495bfc0d02721fd6f52f6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 16730,
"upload_time": "2025-11-06T00:21:34",
"upload_time_iso_8601": "2025-11-06T00:21:34.050529Z",
"url": "https://files.pythonhosted.org/packages/ea/4e/bf39c1ea6a418649862d140480a838b64d530fa06e02fed0ce5b78f0badb/structlog_config-0.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-06 00:21:34",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "iloveitaly",
"github_project": "structlog-config",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "structlog-config"
}