e-volv-logs
e-volv Log Manager SDK for Python — batched log shipping, trace context and
error capture against the e-volv 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 (e-volv 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
e-volv 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.
Feature flags (e-volv Launch)
Evaluate e-volv Launch flags locally, in-process, on the same key as telemetry — through the OpenFeature provider or directly:
pip install e-volv-openfeature # OpenFeature provider
# or just e-volv-logs — flags are built in
from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from e_volv_logs import init
from evolve_openfeature import EvolveProvider
client = init(key="evk_…", url="https://your-host/api/public/v1/logs")
api.set_provider(EvolveProvider(client.flags))
details = api.get_client().get_boolean_details(
"checkout.new",
False,
EvaluationContext(targeting_key="u_1", attributes={"plan": "pro"}),
)
Directly on the client:
from e_volv_logs import FlagsOptions, init
client = init(key="evk_…", url="…", flags=FlagsOptions())
client.flags.bool("checkout.new", False, {"targetingKey": "u_1", "plan": "pro"})
client.flags.string("banner.copy", "Hello")
client.flags.number("limits.maxItems", 10)
client.flags.json("theme.config", {})
client.flags.detail("checkout.new", False, ctx) # Evaluation(value, variant, reason)
client.flags.ready(timeout=5.0) # the only call that waits
client.flags.on_change(lambda keys: ...)
client.flags.last_updated_at # epoch seconds, None before the first payload
client.flags.verify() # install check against GET /ping
Flag options (Python spellings of the Launch contract, §4):
FlagsOptions field |
Default | Meaning |
|---|---|---|
enabled |
True |
start the flags client |
mode |
"stream" |
stream | poll | offline |
poll_interval_seconds |
30 |
poll period; minimum 15 |
cache |
temp dir | last-known-payload dir; False disables |
bootstrap |
none | a bundled ruleset served before the first fetch |
exposures_enabled |
True |
record exposures |
exposures_sample_rate |
1.0 |
probability an evaluation is recorded |
exposures_dedupe_window_seconds |
60 |
suppress repeats of the same subject/variant |
exposures_send_attributes |
False |
send context attributes with exposures |
private_attributes |
[] |
attribute names never sent anywhere |
Guarantees (the e-volv Launch SDK contract):
- Evaluation is synchronous, never raises, never performs I/O — every call answers from the last-held ruleset or your default.
- Wrong type → your default with reason
TYPE_MISMATCH. - Absent flag → your default with reason
FLAG_NOT_FOUND. - The control plane unreachable → last held value; a cold start serves a valid cache file instantly while fetching in the background.
- Server keys never send
Originorx-evolve-app-id; requests carryUser-Agent: e-volv-logs-py/<version>. - Flag evaluation is byte-for-byte identical to every other e-volv SDK: the
Python kernel is a port held to
packages/flags-kernel/fixture.json.
Development
cd packages/logs-py
uv sync
uv run pytest tests/ -q
Metadata
Release files for e-volv-logs 0.2.2
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.2.2.tar.gz | 30.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| e_volv_logs-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.0 kB
Release files / e_volv_logs-0.2.2.tar.gz
| Download URL | e_volv_logs-0.2.2.tar.gz |
|---|---|
| Size | 30.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac83135a9999d27041f267654cc48f3c55383544ddf3be03d82f10bfc0ded729
|
|
BLAKE2b-256 checksum How to use checksums |
ac70975c85eee3cfd073e64a482412a497f3be071a75095876d08a6fcb4503fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / e_volv_logs-0.2.2-py3-none-any.whl
| Download URL | e_volv_logs-0.2.2-py3-none-any.whl |
|---|---|
| Size | 40.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7d1847a68bcad2520218a72f4576c3dd7a2ce05d37c8274ea720d02e2e4a24ba
|
|
BLAKE2b-256 checksum How to use checksums |
184aafc406151085ba94e413e77c579a34a0b5324324167261af7d61bb363190
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|