---
title: "Use JSON logs and Loki to store them · Agent Wranglers"
url: https://agentwranglers.se/playbook/stack/operations-tools/json-logs-and-loki
updated: 2026-10-21
licence: "All rights reserved"
---

# Use JSON logs and Loki to store them

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- Level: Recommended
- Chapter: [Operations tools](https://agentwranglers.se/playbook/stack/operations-tools)
- Rule: Write one JSON object per log line to standard output, and ship the lines to Loki or another store that searches by label.
- Cost: Open source. Pino and Loki are free to run on your own servers. Managed log storage from several vendors is paid.
- How: JSON lines work with any store, so the format is the lasting choice and the store can change. Pino on npm reached 1.0 in March 2016 and has about 33 million weekly downloads. Structlog on PyPI is under MIT or Apache-2.0 and has about 25 million. Loki reached 1.0 in November 2019, is under AGPLv3, and 3.7.9 came out on 20 October 2026. Its image has over 4.8 billion pulls on Docker Hub. Loki indexes labels only, so it costs little to run next to Grafana. The fields to log are in [Log structured events](https://agentwranglers.se/playbook/operations/logs/structured-logs). Choose something else when you need full-text search over every field, and use OpenSearch.
- Check: A script reads 100 lines of production log output, and every line parses as JSON with a time, level and message. A query in the store finds a test line within 60 seconds.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
import pino from 'pino';

const log = pino({ base: { service: 'orders-api' } });
log.info({ orderId: 'ord_123', durationMs: 84 }, 'order placed');
```

### Python example

```python
import structlog

structlog.configure(processors=[structlog.processors.add_log_level,
                                structlog.processors.TimeStamper(fmt="iso"),
                                structlog.processors.JSONRenderer()])
structlog.get_logger().info("order placed", order_id="ord_123", duration_ms=84)
```

## Sources

- [Grafana Loki documentation](https://grafana.com/docs/loki/latest/)
- [Grafana licensing](https://grafana.com/licensing/)

## Related rules

- [Log structured events](https://agentwranglers.se/playbook/operations/logs/structured-logs) in Operations

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/stack/operations-tools/json-logs-and-loki">Agent Wranglers software choices playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Use Grafana for dashboards](https://agentwranglers.se/playbook/stack/operations-tools/grafana)
- Next: [Use GlitchTip for error tracking](https://agentwranglers.se/playbook/stack/operations-tools/glitchtip)
- [Operations tools](https://agentwranglers.se/playbook/stack/operations-tools)
