Skip to content

Commit

Permalink
Merge pull request #133 from axiomhq/arne/structlog
Browse files Browse the repository at this point in the history
Structlog support
  • Loading branch information
darach authored Sep 12, 2024
2 parents 2c4a5ee + 161b3c5 commit 37625ec
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 6 deletions.
31 changes: 26 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,11 @@ from datetime import datetime,timedelta

client = axiom_py.Client()

time = datetime.utcnow() - timedelta(hours=1)
time_formatted = rfc3339.format(time)

client.ingest_events(
dataset="my-dataset",
events=[
{"foo": "bar", "_time": time_formatted},
{"bar": "baz", "_time": time_formatted},
{"foo": "bar"},
{"bar": "baz"},
])
client.query(r"['my-dataset'] | where foo == 'bar' | limit 100")
```
Expand All @@ -96,6 +93,30 @@ def setup_logger():

For a full example, see [`examples/logger.py`](examples/logger.py).

If you use [structlog](https://github.com/hynek/structlog), you can set up the
`AxiomProcessor` like this:

```python
from axiom_py import Client
from axiom_py.structlog import AxiomProcessor


def setup_logger():
client = Client()

structlog.configure(
processors=[
# ...
structlog.processors.add_log_level,
structlog.processors.TimeStamper(fmt="iso", key="_time"),
AxiomProcessor(client, "my-dataset"),
# ...
]
)
```

For a full example, see [`examples/structlog.py`](examples/structlog.py).

## Contributing

This project uses [uv](https://docs.astral.sh/uv) for dependency management
Expand Down
File renamed without changes.
File renamed without changes.
26 changes: 26 additions & 0 deletions examples/structlog_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from axiom_py import Client
from axiom_py.structlog import AxiomProcessor
import structlog


def main():
client = Client()

structlog.configure(
processors=[
structlog.contextvars.merge_contextvars,
structlog.processors.add_log_level,
structlog.processors.StackInfoRenderer(),
structlog.dev.set_exc_info,
structlog.processors.TimeStamper(fmt="iso", key="_time"),
AxiomProcessor(client, "my-dataset"),
structlog.dev.ConsoleRenderer(),
]
)

log = structlog.get_logger()
log.info("hello", who="world")


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion src/axiom_py/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class AxiomHandler(Handler):

client: Client
dataset: str
logcache: list
buffer: list
interval: int
last_run: float

Expand Down
42 changes: 42 additions & 0 deletions src/axiom_py/structlog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Structlog contains the AxiomProcessor for structlog."""

from typing import List
import time
import atexit

from .client import Client


class AxiomProcessor:
"""A processor for sending structlogs to Axiom."""

client: Client
dataset: str
buffer: List[object]
interval: int
last_run: float

def __init__(self, client: Client, dataset: str, interval=1):
self.client = client
self.dataset = dataset
self.buffer = []
self.last_run = time.monotonic()
self.interval = interval

atexit.register(self._flush)

def _flush(self):
self.last_run = time.monotonic()
if len(self.buffer) == 0:
return
self.client.ingest_events(self.dataset, self.buffer)
self.buffer = []

def __call__(self, logger: object, method_name: str, event_dict: object):
self.buffer.append(event_dict.copy())
if (
len(self.buffer) >= 1000
or time.monotonic() - self.last_run > self.interval
):
self.flush()
return event_dict

0 comments on commit 37625ec

Please sign in to comment.