e-volv-logs
Evolve Log Manager SDK for Python — batched log shipping, trace context and
error capture against the Evolve ingest endpoint
(POST /api/public/v1/logs). Companion: the Node.js SDK @e-volv/logs.
Python 3.10+.
pip install e-volv-logs
Quick start
import e_volv_logs as evolve_logs
from e_volv_logs import init, log, span, trace
init(
key="evk_…", # project ingest key
url="https://your-host/api/public/v1/logs",
service="api",
environment="production",
release="1.4.2",
)
log.info("order created", {"orderId": "o_1", "total": 42.5})
log.error("payment failed", {"orderId": "o_1"})
try:
await charge()
except Exception as err:
log.exception(err, {"orderId": "o_1"}) # exception.type/message/stack
# Traces live in contextvars — they flow across await. httpx/requests
# requests made inside a trace get a W3C traceparent header automatically.
with trace():
with span("db.query", {"table": "orders"}):
await db.query("SELECT …")
await httpx.get("https://internal/svc") # traceparent injected
If key or url is missing, init() returns a no-op client and warns once.
The SDK never raises into user code.
Batching, retries, drops
- Flushes at 200 events, 2 s (age of the oldest buffered event), or a
512 KB payload — whichever comes first. Bodies are gzipped
(
Content-Encoding: gzip). - 429 retries with exponential backoff (0.5 s doubling, capped at 10 s), up to 3 attempts. 413 halves the batch and retries.
- When the pending buffer exceeds 2× batch size, the oldest events are
dropped; losses are visible on
client.dropped. atexitflushes whatever is pending.
Options
init(key=, url=, service=, environment=, release=, redact_keys=[...], sample_rate=1.0, capture_excepthook=True) — redact_keys are merged into the
backstop regex password|secret|token|authorization|cookie|set-cookie|api[-_]?key
(case-insensitive), applied to attrs before queueing.
stdlib logging
import logging
from e_volv_logs import init, LogHandler
init(key="evk_…", url="…", service="api")
logging.getLogger("myapp").addHandler(LogHandler())
Levels map to OTel severities (DEBUG→5, INFO→9, WARNING→13, ERROR→17,
CRITICAL→21). extra={...} on the log call becomes event attrs; exc_info
becomes exception.* fields. sys.excepthook capture is on by default.
FastAPI / Starlette
from e_volv_logs.integrations.fastapi import EvolveLogsMiddleware
app.add_middleware(EvolveLogsMiddleware) # one root span per request
The middleware continues the trace when the inbound request carries an
x-evolve-traceparent header (Evolve backend → evolve-ai propagation),
otherwise starts a fresh root trace.
LangChain and LangGraph
pip install "e-volv-logs[langchain]"
from e_volv_logs.integrations.langchain import EvolveLogsCallbackHandler
result = graph.invoke(
{"question": "…"},
config={"callbacks": [EvolveLogsCallbackHandler()]},
)
One span per LangChain run, nested by parent_run_id, all sharing one trace —
so a LangGraph node's tool calls and model calls appear inside the node on the
Evolve trace graph. Span names:
| Callback | Span name |
|---|---|
on_chain_start with langgraph_node |
graph.<node> |
on_chain_start otherwise |
chain.<name> |
on_tool_start |
tool.<name> |
on_llm_start / on_chat_model_start |
llm.<model> |
Errors end the span through _log_span_error (severity error, exception.*
attrs), exactly like span() raised inside a body.
Queue hops
A span on the consumer side joins the producer's trace only if the traceparent travels with the job:
from e_volv_logs import run_with_traceparent, span, traceparent
# producer
queue.enqueue(work, payload, trace=traceparent())
# consumer: the body runs as a new hop of the producer's trace.
with run_with_traceparent(job.trace), span("queue.work", {"queue": "work"}):
handle(job)
run_with_traceparent(header) parses a W3C traceparent; an absent or malformed
header starts a fresh trace, so a producer that sends nothing still yields a
trace of its own.
Development
cd packages/logs-py
uv sync
uv run pytest tests/ -q
Metadata
Release files for e-volv-logs 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| e_volv_logs-0.1.0.tar.gz | 135.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| e_volv_logs-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 151.8 kB
Release files / e_volv_logs-0.1.0.tar.gz
| Download URL | e_volv_logs-0.1.0.tar.gz |
|---|---|
| Size | 135.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
39ad1f8cacd47514f2b0d05629eb713ed2d46cab917cfa192097a31b77df9fb3
|
|
BLAKE2b-256 checksum How to use checksums |
f2504ce9853ccfe77feed43d77f539e6f4468d450eb596937978177160cb68bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.0
|
Release files / e_volv_logs-0.1.0-py3-none-any.whl
| Download URL | e_volv_logs-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
171e3273bdcd917153d5171a68d22f2456d3216e836555d6fc2c5c98b37343bd
|
|
BLAKE2b-256 checksum How to use checksums |
2fc885cbf0beec3d7c43f3b7143f831820ee8717c7a8f5803ea1e9d0ada6ae6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.0
|