{"id":48249980,"url":"https://github.com/logtide-dev/logtide-python","last_synced_at":"2026-06-11T13:00:17.313Z","repository":{"id":325656613,"uuid":"1101966851","full_name":"logtide-dev/logtide-python","owner":"logtide-dev","description":"  Official Python SDK for LogTide - Production-ready logging with automatic batching, circuit breaker, distributed","archived":false,"fork":false,"pushed_at":"2026-06-11T07:59:09.000Z","size":319,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-11T08:14:38.873Z","etag":null,"topics":["async","batching","circuit-breaker","distributed-tracing","django","fastapi","flask","log-management","logtide","middleware","observability","retry-logic","sdk"],"latest_commit_sha":null,"homepage":"https://logtide.dev/docs/sdks/python/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/logtide-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-22T15:17:16.000Z","updated_at":"2026-06-11T07:58:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/logtide-dev/logtide-python","commit_stats":null,"previous_names":["logward-dev/logward-sdk-python","logward-dev/logtide-sdk-python","logtide-dev/logtide-python"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/logtide-dev/logtide-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logtide-dev%2Flogtide-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logtide-dev%2Flogtide-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logtide-dev%2Flogtide-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logtide-dev%2Flogtide-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/logtide-dev","download_url":"https://codeload.github.com/logtide-dev/logtide-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/logtide-dev%2Flogtide-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34199516,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","batching","circuit-breaker","distributed-tracing","django","fastapi","flask","log-management","logtide","middleware","observability","retry-logic","sdk"],"created_at":"2026-04-04T20:48:42.938Z","updated_at":"2026-06-11T13:00:17.136Z","avatar_url":"https://github.com/logtide-dev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/logtide-dev/logtide/main/docs/images/logo.png\" alt=\"LogTide Logo\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eLogTide Python SDK\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.org/project/logtide-sdk/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/logtide-sdk?color=blue\" alt=\"PyPI\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.python.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Python-3.10+-blue.svg\" alt=\"Python\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/logtide-dev/logtide-python/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/logtide-dev/logtide-python\" alt=\"Release\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Official Python SDK for \u003ca href=\"https://logtide.dev\"\u003eLogTide\u003c/a\u003e — self-hosted log management with async client, logging integration, batching, retry, circuit breaker, and middleware.\n\u003c/p\u003e\n\n---\n\n## Features\n\n- **Sync \u0026 async clients** — `LogTideClient` (requests) and `AsyncLogTideClient` (aiohttp)\n- **stdlib `logging` integration** — drop-in `LogTideHandler` for existing logging setups\n- **structlog integration** — `LogTideProcessor` to forward structlog events (optional, no hard dependency)\n- **Automatic batching** with configurable size and interval\n- **Retry logic** with exponential backoff\n- **Circuit breaker** pattern for fault tolerance\n- **Payload limits** — field truncation, base64 removal, field exclusion, max entry size\n- **Max buffer size** with silent drop policy to prevent memory leaks\n- **Query API** for searching and filtering logs\n- **Live tail** with Server-Sent Events (SSE)\n- **Trace ID context** for distributed tracing\n- **Global metadata** added to all logs\n- **Structured exception serialization** with parsed stack frames\n- **Internal metrics** (logs sent, errors, latency, circuit breaker trips)\n- **Flask, Django, FastAPI \u0026 Starlette middleware** for auto-logging HTTP requests\n- **Full Python 3.10+ support** with type hints\n\n## Requirements\n\n- Python 3.10 or higher\n\n## Installation\n\n```bash\npip install logtide-sdk\n```\n\n### Optional Dependencies\n\n```bash\n# Async client (AsyncLogTideClient)\npip install logtide-sdk[async]\n\n# Flask middleware\npip install logtide-sdk[flask]\n\n# Django middleware\npip install logtide-sdk[django]\n\n# FastAPI middleware\npip install logtide-sdk[fastapi]\n\n# Starlette middleware (standalone, without FastAPI)\npip install logtide-sdk[starlette]\n\n# Install all extras\npip install logtide-sdk[async,flask,django,fastapi,starlette]\n```\n\n## Quick Start\n\n```python\nfrom logtide_sdk import LogTideClient, ClientOptions\n\nclient = LogTideClient(\n    ClientOptions(\n        api_url='http://localhost:8080',\n        api_key='lp_your_api_key_here',\n    )\n)\n\nclient.info('api-gateway', 'Server started', {'port': 3000})\nclient.error('database', 'Connection failed', Exception('Timeout'))\n\n# Graceful shutdown (also registered automatically via atexit)\nclient.close()\n```\n\n---\n\n## Configuration Options\n\n### Basic Options\n\n| Option           | Type  | Default      | Description                              |\n| ---------------- | ----- | ------------ | ---------------------------------------- |\n| `api_url`        | `str` | **required** | Base URL of your LogTide instance        |\n| `api_key`        | `str` | **required** | Project API key (starts with `lp_`)      |\n| `batch_size`     | `int` | `100`        | Logs per batch before an immediate flush |\n| `flush_interval` | `int` | `5000`       | Auto-flush interval in ms                |\n\n### Advanced Options\n\n| Option                      | Type                   | Default   | Description                                    |\n| --------------------------- | ---------------------- | --------- | ---------------------------------------------- |\n| `max_buffer_size`           | `int`                  | `10000`   | Max buffered logs; excess are silently dropped |\n| `max_retries`               | `int`                  | `3`       | Max retry attempts on send failure             |\n| `retry_delay_ms`            | `int`                  | `1000`    | Initial retry delay (doubles each attempt)     |\n| `circuit_breaker_threshold` | `int`                  | `5`       | Consecutive failures before opening circuit    |\n| `circuit_breaker_reset_ms`  | `int`                  | `30000`   | Time before testing a half-open circuit        |\n| `debug`                     | `bool`                 | `False`   | Print debug output to console                  |\n| `global_metadata`           | `dict`                 | `{}`      | Metadata merged into every log entry           |\n| `auto_trace_id`             | `bool`                 | `False`   | Auto-generate a UUID trace ID per log          |\n| `payload_limits`            | `PayloadLimitsOptions` | see below | Safeguards against oversized payloads          |\n\n### Payload Limits\n\n`PayloadLimitsOptions` prevents 413 errors from oversized entries.\n\n| Field               | Default               | Description                              |\n| ------------------- | --------------------- | ---------------------------------------- |\n| `max_field_size`    | `10 * 1024` (10 KB)   | Max length of any single string field    |\n| `max_log_size`      | `100 * 1024` (100 KB) | Max total serialized entry size          |\n| `exclude_fields`    | `[]`                  | Field names replaced with `\"[EXCLUDED]\"` |\n| `truncation_marker` | `\"...[TRUNCATED]\"`    | Appended to truncated strings            |\n\n```python\nfrom logtide_sdk import LogTideClient, ClientOptions, PayloadLimitsOptions\n\nclient = LogTideClient(\n    ClientOptions(\n        api_url='http://localhost:8080',\n        api_key='lp_your_api_key_here',\n        payload_limits=PayloadLimitsOptions(\n            max_field_size=5 * 1024,\n            exclude_fields=['password', 'token'],\n        ),\n    )\n)\n```\n\nBase64-encoded strings (data URIs or long base64 blobs) are automatically replaced with `\"[BASE64 DATA REMOVED]\"`.\n\n---\n\n## Sync Client\n\n### Logging Methods\n\n```python\nclient.debug('service', 'Debug message')\nclient.info('service', 'Info message', {'userId': 123})\nclient.warn('service', 'Warning message')\nclient.error('service', 'Error message', {'custom': 'data'})\nclient.critical('service', 'Critical message')\n```\n\n### Exception Auto-Serialization\n\nPass an `Exception` directly to `error()` or `critical()` — it is serialized automatically:\n\n```python\ntry:\n    raise RuntimeError('Database timeout')\nexcept Exception as e:\n    client.error('database', 'Query failed', e)\n```\n\nGenerated metadata:\n\n```json\n{\n  \"exception\": {\n    \"type\": \"RuntimeError\",\n    \"message\": \"Database timeout\",\n    \"language\": \"python\",\n    \"stacktrace\": [{ \"file\": \"app.py\", \"function\": \"run_query\", \"line\": 42 }],\n    \"raw\": \"Traceback (most recent call last):\\n  ...\"\n  }\n}\n```\n\n---\n\n## Async Client\n\n`AsyncLogTideClient` is the async equivalent, using `aiohttp`. Best used as an async context manager.\n\n```bash\npip install logtide-sdk[async]\n```\n\n```python\nimport asyncio\nfrom logtide_sdk import AsyncLogTideClient, ClientOptions\n\nasync def main():\n    async with AsyncLogTideClient(ClientOptions(\n        api_url='http://localhost:8080',\n        api_key='lp_your_api_key_here',\n    )) as client:\n        await client.info('my-service', 'Hello from async!')\n        await client.error('my-service', 'Something failed', Exception('oops'))\n\nasyncio.run(main())\n```\n\nManual lifecycle (without context manager):\n\n```python\nclient = AsyncLogTideClient(options)\nawait client.start()   # starts background flush loop\ntry:\n    await client.info('svc', 'message')\nfinally:\n    await client.close()\n```\n\nAll sync logging, query, stream, and metrics methods have async equivalents.\n\n---\n\n## stdlib `logging` Integration\n\n`LogTideHandler` is a standard `logging.Handler` — drop it into any existing logging setup.\n\n```python\nimport logging\nfrom logtide_sdk import LogTideClient, ClientOptions, LogTideHandler\n\nclient = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n))\n\nhandler = LogTideHandler(client=client, service='my-service')\nhandler.setLevel(logging.WARNING)\n\nlogger = logging.getLogger(__name__)\nlogger.addHandler(handler)\n\n# These are forwarded to LogTide automatically\nlogger.warning('Low disk space')\nlogger.error('Unhandled exception', exc_info=True)\n```\n\nException info is serialized with full structured stack frames when `exc_info=True` is used.\n\n---\n\n## structlog Integration\n\n`LogTideProcessor` is a [structlog](https://www.structlog.org/) processor that forwards events to\nLogTide. `structlog` is not a hard dependency — install it separately if you use this integration.\n\n```python\nimport structlog\nfrom logtide_sdk import LogTideClient, ClientOptions\nfrom logtide_sdk.structlog import LogTideProcessor\n\nclient = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n))\n\nstructlog.configure(\n    processors=[\n        structlog.processors.add_log_level,\n        LogTideProcessor(client=client, service='my-service'),\n        structlog.processors.JSONRenderer(),\n    ],\n)\n\nlog = structlog.get_logger()\nlog.info('user signed in', user_id=42, plan='pro')\nlog.error('payment failed', order_id='o_123', exc_info=True)\n```\n\nNon-reserved event fields (e.g. `user_id`, `plan`) are sent as metadata, the log level is mapped\nto LogTide's levels, and `exc_info` is serialized into structured exception metadata. Metadata\nvalues that aren't natively JSON-serializable (Pydantic models, dataclasses, sets, `datetime`,\n`UUID`, …) are handled automatically.\n\n---\n\n## Trace ID Context\n\n### Manual Trace ID\n\n```python\nclient.set_trace_id('request-123')\n\nclient.info('api', 'Request received')\nclient.info('db', 'Querying users')\nclient.info('api', 'Response sent')\n\nclient.set_trace_id(None)  # clear\n```\n\n### Scoped Trace ID (Context Manager)\n\n```python\nwith client.with_trace_id('request-456'):\n    client.info('api', 'Processing in context')\n    client.warn('cache', 'Cache miss')\n# Trace ID automatically restored after block\n```\n\n### Auto-Generated Trace ID\n\n```python\nwith client.with_new_trace_id():\n    client.info('worker', 'Background job started')\n    client.info('worker', 'Job completed')\n```\n\n---\n\n## Query API\n\n### Basic Query\n\n```python\nfrom datetime import datetime, timedelta\nfrom logtide_sdk import QueryOptions, LogLevel\n\nresult = client.query(\n    QueryOptions(\n        service='api-gateway',\n        level=LogLevel.ERROR,\n        from_time=datetime.now() - timedelta(hours=24),\n        to_time=datetime.now(),\n        limit=100,\n        offset=0,\n    )\n)\n\nprint(f\"Found {result.total} logs\")\nfor log in result.logs:\n    print(log)\n```\n\n### Full-Text Search\n\n```python\nresult = client.query(QueryOptions(q='timeout', limit=50))\n```\n\n### Get Logs by Trace ID\n\n```python\nlogs = client.get_by_trace_id('trace-123')\n```\n\n### Aggregated Statistics\n\n```python\nfrom logtide_sdk import AggregatedStatsOptions\n\nstats = client.get_aggregated_stats(\n    AggregatedStatsOptions(\n        from_time=datetime.now() - timedelta(days=7),\n        to_time=datetime.now(),\n        interval='1h',\n    )\n)\n\nfor service in stats.top_services:\n    print(f\"{service['service']}: {service['count']} logs\")\n```\n\n---\n\n## Live Streaming (SSE)\n\n`stream()` runs in a background daemon thread and returns immediately with a stop function.\n\n```python\ndef handle_log(log):\n    print(f\"[{log['time']}] {log['level']}: {log['message']}\")\n\nstop = client.stream(\n    on_log=handle_log,\n    on_error=lambda e: print(f\"Stream error: {e}\"),\n    filters={'service': 'api-gateway', 'level': 'error'},\n)\n\n# ... later, to stop:\nstop()\n```\n\nAsync streaming runs as a cancellable coroutine:\n\n```python\ntask = asyncio.create_task(client.stream(on_log=handle_log))\n# ... later:\ntask.cancel()\n```\n\n---\n\n## Metrics\n\n```python\nmetrics = client.get_metrics()\n\nprint(f\"Logs sent:              {metrics.logs_sent}\")\nprint(f\"Logs dropped:           {metrics.logs_dropped}\")\nprint(f\"Errors:                 {metrics.errors}\")\nprint(f\"Retries:                {metrics.retries}\")\nprint(f\"Avg latency:            {metrics.avg_latency_ms:.1f}ms\")\nprint(f\"Circuit breaker trips:  {metrics.circuit_breaker_trips}\")\n\nprint(client.get_circuit_breaker_state())  # CLOSED | OPEN | HALF_OPEN\n\nclient.reset_metrics()\n```\n\n---\n\n## Middleware Integration\n\n### Flask\n\n```python\nfrom flask import Flask\nfrom logtide_sdk import LogTideClient, ClientOptions\nfrom logtide_sdk.middleware import LogTideFlaskMiddleware\n\napp = Flask(__name__)\nclient = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n))\n\nLogTideFlaskMiddleware(\n    app,\n    client=client,\n    service_name='flask-api',\n    log_requests=True,\n    log_responses=True,\n    skip_paths=['/metrics'],\n)\n```\n\n### Django\n\n```python\n# settings.py\nfrom logtide_sdk import LogTideClient, ClientOptions\n\nLOGTIDE_CLIENT = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n))\nLOGTIDE_SERVICE_NAME = 'django-api'\n\nMIDDLEWARE = [\n    'logtide_sdk.middleware.LogTideDjangoMiddleware',\n    # ...\n]\n```\n\n### FastAPI\n\n```python\nfrom fastapi import FastAPI\nfrom logtide_sdk import LogTideClient, ClientOptions\nfrom logtide_sdk.middleware import LogTideFastAPIMiddleware\n\napp = FastAPI()\nclient = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n))\n\napp.add_middleware(LogTideFastAPIMiddleware, client=client, service_name='fastapi-api')\n```\n\n### Starlette (standalone)\n\n```bash\npip install logtide-sdk[starlette]\n```\n\n```python\nfrom starlette.applications import Starlette\nfrom logtide_sdk import LogTideClient, ClientOptions\nfrom logtide_sdk.middleware import LogTideStarletteMiddleware\n\napp = Starlette()\nclient = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n))\n\napp.add_middleware(LogTideStarletteMiddleware, client=client, service_name='starlette-api')\n```\n\nAll middleware auto-logs requests, responses (with duration and status code), and errors (with serialized exception metadata). Health check paths (`/health`, `/healthz`) are skipped by default.\n\n---\n\n## Examples\n\nSee the [examples/](./examples) directory for complete working examples:\n\n- **[basic.py](./examples/basic.py)** - Simple usage\n- **[advanced.py](./examples/advanced.py)** - All advanced features\n\n---\n\n## Best Practices\n\n### Use Global Metadata\n\n```python\nclient = LogTideClient(ClientOptions(\n    api_url='http://localhost:8080',\n    api_key='lp_your_api_key_here',\n    global_metadata={\n        'env': os.getenv('APP_ENV', 'production'),\n        'version': '2.0.0',\n        'region': 'eu-west-1',\n    },\n))\n```\n\n### Monitor Metrics in Production\n\n```python\nimport threading\n\ndef _monitor():\n    while True:\n        m = client.get_metrics()\n        if m.logs_dropped \u003e 0:\n            print(f\"WARNING: {m.logs_dropped} logs dropped\")\n        if m.circuit_breaker_trips \u003e 0:\n            print(\"ERROR: Circuit breaker tripped\")\n        time.sleep(60)\n\nthreading.Thread(target=_monitor, daemon=True).start()\n```\n\n---\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT License — see [LICENSE](LICENSE) for details.\n\n## Links\n\n- [LogTide Website](https://logtide.dev)\n- [Documentation](https://logtide.dev/docs/sdks/python/)\n- [GitHub Issues](https://github.com/logtide-dev/logtide-python/issues)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogtide-dev%2Flogtide-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flogtide-dev%2Flogtide-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flogtide-dev%2Flogtide-python/lists"}