All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
inject_traceparent(headers): injects the W3Ctraceparentheader for outbound HTTP calls (active span → scope trace context; no-op when neither is set or the header already exists). Works with any mutable headers mapping (requests,httpx, ...)
- OpenTelemetry tracing preset (
logtide_sdk.otel.configure_tracing, extra[otel]): one call configures the official OTel SDK to export spans to LogTide (/v1/otlp/traces,X-API-Key), withservice.name/deployment.environment/service.versionresource identity and a parent-basedtraces_sample_ratesampler - Active-span log correlation: entries captured inside an active OTel span automatically carry its
trace_id/span_id(resolution order: explicit → active span → scope → client context)
ClientOptions.before_send: hook called before buffering — mutate the entry or returnNoneto drop it. A raising hook never loses the entryClientOptions.sample_rate(0.0–1.0, default 1.0): per-entry sampling applied afterbefore_send
- Permanent client errors (4xx except 408/429) are no longer retried (sync and async): the batch is dropped after the first attempt instead of burning the full retry budget
- A
Retry-Afterheader on429/503responses now overrides the computed backoff delay
- Scope API (
logtide_sdk.scope, exported from the package root): per-request/per-task context built oncontextvars—push_scope(),get_current_scope(),set_tag,set_extra,set_user,set_session_id,add_breadcrumb. Scope state (tags, user, breadcrumbs, session, trace context) is merged into every captured entry; entry-level values win - Breadcrumbs: ring buffer (default 100, oldest evicted), attached as
metadata.breadcrumbs - User context (
User) attached asmetadata.user;session_idsent as a top-level field (LogEntry.session_id) - Per-request scope isolation in all middleware (Flask, Django, Starlette/FastAPI): breadcrumbs/user/tags set inside a handler stay local to that request, and handler logs inherit the request's trace context
- Trace-id resolution order in
log()now follows the spec: explicit value → scope trace context → client context/auto-generation
- DSN support:
ClientOptions(dsn="https://lp_key@host[/path]")(plusparse_dsn/DsnParseErrorexported from the package root). Explicitapi_url+api_keykeep working; a malformed DSN raises at init time ClientOptions.service: configure the service once and call log methods with just the message —client.info("user logged in"),client.error("boom", exc). The legacy(service, message)form keeps working- Every entry now carries
metadata.sdk = {"name": "logtide-python", "version": ...}(caller-providedsdkkey wins)
logtide_sdk.__version__was stale (0.9.1); version now has a single runtime source (logtide_sdk._version)
- W3C Trace Context support (
logtide_sdk.tracecontext):parse_traceparent,format_traceparent,generate_trace_id,generate_span_id,resolve_trace_id— all exported from the package root - All log methods (sync and async) accept keyword-only
trace_idandspan_id, sent as top-level fields LogEntry.span_idfield, serialized as top-levelspan_id
- Middleware (Flask, Django, Starlette/FastAPI) now resolve the inbound trace context per the W3C spec:
traceparentheader first, legacyX-Trace-IDas deprecated fallback, otherwise a new W3C trace ID is generated. The resolved trace ID is sent as the top-leveltrace_idfield instead ofmetadata["trace_id"], so trace correlation in the platform UI now works for middleware logs - Auto-generated trace IDs (
auto_trace_id,with_new_trace_id) are now 32-char lowercase-hex W3C IDs instead of UUIDs
0.9.1 - 2026-05-29
LogTideFastAPIMiddlewareimport failed becausemiddleware/fastapi.pyimportedLogTideStarletteMiddlewarefrom the wrong path (logtide_sdk.starletteinstead oflogtide_sdk.middleware.starlette) — the FastAPI middleware now imports correctly
- Import tests covering all four framework middlewares (
tests/middleware/test_imports.py)
- @apelsynca — #6
0.9.0 - 2026-05-26
LogTideProcessor— a structlog processor for forwarding structlog events to LogTide (from logtide_sdk.structlog import LogTideProcessor). It maps log levels, extracts non-reserved event fields into metadata, and serializes exceptions fromexc_info.structlogis not a hard dependency — it is only required if you use the processor- Robust JSON encoder (
logtide_json_dumps) used for both payload-size calculation and the actual request body. Metadata containing non-JSON-serializable values no longer raises at flush time — Pydantic models, dataclasses, attrs classes, sets,datetime/date/time,Decimal,UUID,bytes, IP addresses,Path, enums, generators, andpandas/numpyobjects are all handled, with circular references and unknown types degrading gracefully torepr()
- BREAKING Dropped support for Python 3.8 and 3.9 (both EOL). Minimum supported version is now Python 3.10
- Internal imports converted from relative to absolute throughout the package
- @apelsynca — #5
0.8.5 - 2026-04-06
- Use
Zsuffix for UTC timestamps instead of+00:00to match server schema requirements - Normalize caller-supplied
+00:00offsets toZinLogEntry.__post_init__ - Omit
trace_idfromto_dict()whenNone— server rejects null values
0.8.4 - 2026-03-21
AsyncLogTideClient: full async client usingaiohttpwith the same API as the sync client — supportsasync with,await client.start(), and all logging, flush, query, and stream methods as coroutines (pip install logtide-sdk[async])LogTideHandler: standardlogging.Handlerfor drop-in integration with Python's built-in logging module — forwards records to LogTide with structured exception metadata whenexc_info=Trueis usedPayloadLimitsOptions: configurable safeguards against 413 errors — per-field size cap, total entry size cap, named field exclusion, and automatic base64 removalLogTideStarletteMiddleware: standalone Starlette ASGI middleware independent of FastAPI (pip install logtide-sdk[starlette])serialize_exception()exported at top level for use in custom integrationspayload_limitsfield onClientOptions
- BREAKING API paths updated to match v1 server contract:
POST /api/logs→POST /api/v1/ingestGET /api/logs→GET /api/v1/logsGET /api/logs/trace/{id}→GET /api/v1/logs/trace/{id}GET /api/logs/stats→GET /api/v1/logs/aggregatedGET /api/logs/stream→GET /api/v1/logs/stream
- BREAKING Auth header changed from
Authorization: Bearer <key>toX-API-Key: <key> - BREAKING Error metadata key changed from
"error"to"exception"; value is now a structured object withtype,message,language,stacktrace(array of{file, function, line}frames), andraw - BREAKING
stream()no longer blocks — it runs in a background daemon thread and returns aCallable[[], None]stop function immediately - BREAKING Buffer overflow no longer raises
BufferFullError; logs are silently dropped andlogs_droppedis incremented (BufferFullErrorclass is kept for backwards-compatible catch blocks) requests.Sessionis now created once and reused across all HTTP calls for connection reuse and reduced TCP overheaddatetime.utcnow()replaced withdatetime.now(timezone.utc)throughout;LogEntry.timenow includes+00:00timezone suffix (ISO 8601 compliant)- Middleware
__init__.pynow uses per-frameworktry/exceptguards — importinglogtide_sdk.middlewareno longer fails if only a subset of frameworks are installed
- Flask, Django, and FastAPI middleware
_log_errormethods were passing rawExceptionobjects into the metadata dict instead of serializing them — exceptions are now serialized viaserialize_exception() log()triggeredflush()while holding_buffer_lock, causing a potential deadlock under concurrent access — flush is now triggered outside the lock__version__in__init__.pywas incorrectly set to"0.1.0"despite the package being at0.1.2
0.1.0 - 2026-01-13
- Initial release of LogTide Python SDK
- Automatic batching with configurable size and interval
- Retry logic with exponential backoff
- Circuit breaker pattern for fault tolerance
- Max buffer size with drop policy
- Query API for searching and filtering logs
- Live tail with Server-Sent Events (SSE)
- Trace ID context for distributed tracing
- Global metadata support
- Structured error serialization
- Internal metrics tracking
- Logging methods: debug, info, warn, error, critical
- Thread-safe operations
- Graceful shutdown with atexit hook
- Flask middleware for auto-logging HTTP requests
- Django middleware for auto-logging HTTP requests
- FastAPI middleware for auto-logging HTTP requests
- Full type hints support for Python 3.10+