Skip to main content

LupisLabs Python SDK for AI application tracing and monitoring

Project description

Lupis Labs Python SDK

Python SDK for LupisLabs with OpenTelemetry tracing and custom event tracking.

Installation

pip install lupislabs

For async support (recommended):

pip install lupislabs[async]

Features

  • 🔍 Automatic HTTP Tracing: Captures requests from requests, http.client, urllib3, httpx, and aiohttp
  • 📊 Custom Event Tracking: Track custom events with properties and metadata
  • 💬 Chat ID Support: Group traces by conversation/chat ID
  • Batching: Automatically batches events for efficient transmission
  • 🐍 Python Support: Full Python 3.8+ support with async/await
  • 🔒 Privacy-First: Never collects request/response bodies, only analytics data

Quick Start

from lupislabs import LupisSDK, LupisConfig

lupis = LupisSDK.init(LupisConfig(
    project_id="your-project-id",
))

# Supported HTTP clients are instrumented automatically.
# Make your AI/HTTP calls here and traces will appear in the Lupis desktop app.

Supported HTTP Clients

The SDK automatically captures outbound calls made with:

  • requests.Session
  • http.client.HTTPConnection / HTTPSConnection
  • urllib3 connection pools
  • httpx.Client and httpx.AsyncClient
  • aiohttp.ClientSession

Nested client usage (for example requestsurllib3http.client) is deduplicated so only a single trace is emitted per HTTP call.

Once configured, the SDK stores the instance globally. Calling LupisSDK.init(...) again returns the existing instance, and you can retrieve it from anywhere with LupisSDK.get_instance().

# In another module
from lupislabs import LupisSDK

lupis = LupisSDK.get_instance()
if lupis and lupis.is_enabled():
    lupis.track_event("button_click", {"button_name": "submit"})

Configuration

from lupislabs import LupisConfig

config = LupisConfig(
    project_id="your-project-id",  # Required
    ue,                   # Optional, default: True
    service_name="lupis-sdk",       # Optional, default: "lupis-sdk"
    service_version="1.0.0",        # Optional, default: "1.0.0"
    filter_sensitive_data=True,     # Optional, default: True
    sensitive_data_patterns=[       # Optional, default: common patterns
        "sk-[a-zA-Z0-9]{20,}",
        "Bearer [a-zA-Z0-9._-]+",
    ],
    redaction_mode="mask",          # Optional: "mask", "remove", "hash"
)

ℹ️ The traces endpoint defaults to the desktop collector at http://127.0.0.1:9009/api/traces. Override it by setting otlp_endpoint if you need to forward telemetry elsewhere.

Event Tracking

Basic Event Tracking

lupis.track_event("button_click", {
    "button_name": "submit",
    "page": "/dashboard",
})

Event with User Context

from lupislabs import LupisMetadata

lupis.track_event("feature_used", {
    "feature": "export_data",
    "format": "csv",
}, metadata=LupisMetadata(
    user_id="user_123",
    session_id="browser_session_456",
    organization_id="org_789",
))

Conversation Grouping

Group traces by conversation/thread using chat_id:

# Set global chat ID for all subsequent traces
lupis.set_chat_id("conversation_123")

# Or set per-operation chat ID
await lupis.run(async def my_ai_function():
    # Your AI conversation code here
    pass
, options=LupisBlockOptions(chat_id="conversation_123"))

lupis.clear_chat_id()

Metadata Types

sessionId vs chatId

  • session_id: Browser/app session identifier that persists across conversations

    • Used for analytics and user journey tracking
    • Example: "browser_session_abc123"
  • chat_id: Individual conversation/thread identifier

    • Used for grouping related traces within a conversation
    • Changes for each new conversation
    • Example: "chat_thread_xyz789"

Example Usage

from lupislabs import LupisMetadata, LupisBlockOptions

# Set user context (persists across conversations)
lupis.set_metadata(LupisMetadata(
    user_id="user_123",
    organization_id="org_456",
    session_id="browser_session_abc123",  # Same across conversations
))

# Start a new conversation
lupis.set_chat_id("conversation_1")

await lupis.run(async def ai_conversation_1():
    # AI conversation code
    pass
, options=LupisBlockOptions(chat_id="conversation_1"))

# Start another conversation (same session, different chat)
lupis.set_chat_id("conversation_2")

await lupis.run(async def ai_conversation_2():
    # Another AI conversation code
    pass
, options=LupisBlockOptions(chat_id="conversation_2"))

Event Batching

Events are automatically batched and sent to the server:

  • Batch Size: Up to 50 events per batch
  • Flush Interval: Every 5 seconds
  • Auto-flush: Background worker + process exit hook

OpenTelemetry Integration

The SDK automatically instruments HTTP requests and creates traces. Access the tracer:

tracer = lupis.get_tracer()

with lupis.create_span("custom-operation", {
    "custom.attribute": "value",
}) as span:
    # Your code here
    pass

Data Collection

The SDK collects only analytics-focused data while protecting sensitive information:

Collected Data

  • HTTP Metadata: URL, method, status code, duration, headers (filtered)
  • Token Usage: Input/output/cache tokens from AI providers
  • Cost Analytics: Calculated costs based on token usage and provider pricing
  • Model Information: AI model used for requests
  • User Context: User ID, organization ID, session ID, chat ID
  • Custom Events: Manually tracked events with properties
  • Performance Metrics: Response times, error rates, success/failure status

Never Collected

  • Request Bodies: Full request payloads are never captured
  • Response Bodies: Full response content is never captured
  • Sensitive Data: API keys, tokens, passwords (filtered by default)
  • Personal Information: PII is not collected by default

🔒 Privacy Protection

  • Sensitive data filtering enabled by default
  • Request/response bodies skipped to reduce span size
  • Focus on analytics and cost tracking only
  • User-controlled data collection

Sensitive Data Filtering

The SDK automatically filters sensitive data in production to protect API keys, tokens, and other sensitive information. This feature is enabled by default for security.

Default Filtering

The SDK automatically filters these common sensitive patterns:

API Keys & Tokens

  • sk-[a-zA-Z0-9]{20,} - OpenAI API keys
  • pk_[a-zA-Z0-9]{20,} - Paddle API keys
  • ak-[a-zA-Z0-9]{20,} - Anthropic API keys
  • Bearer [a-zA-Z0-9._-]+ - Bearer tokens
  • x-api-key, authorization - API key headers

Authentication

  • password, passwd, pwd - Password fields
  • token, access_token, refresh_token, session_token - Various tokens
  • secret, private_key, api_secret - Secret fields

Personal Data

  • ssn, social_security - Social Security Numbers
  • credit_card, card_number - Credit card numbers
  • cvv, cvc - Security codes

Redaction Modes

Choose how sensitive data is replaced when initializing the SDK:

Mask Mode (Default)

lupis = LupisSDK.init(LupisConfig(
    project_id="your-project-id",
    redaction_mode="mask",  # Default
))

# Examples:
# sk-1234567890abcdef1234567890abcdef12345678 → sk-1***5678
# Bearer sk-1234567890abcdef1234567890abcdef12345678 → Bear***5678
# password: 'secret-password' → password: '***'

Remove Mode

lupis = LupisSDK.init(LupisConfig(
    project_id="your-project-id",
    redaction_mode="remove",
))

# Examples:
# sk-1234567890abcdef1234567890abcdef12345678 → [REDACTED]
# password: 'secret-password' → password: [REDACTED]

Hash Mode

lupis = LupisSDK.init(LupisConfig(
    project_id="your-project-id",
    redaction_mode="hash",
))

# Examples:
# sk-1234567890abcdef1234567890abcdef12345678 → [HASH:2dd0e9d5]
# password: 'secret-password' → password: [HASHED]

Custom Patterns

Add your own sensitive data patterns during initialization:

lupis = LupisSDK.init(LupisConfig(
    project_id="your-project-id",
    filter_sensitive_data=True,
    sensitive_data_patterns=[
        "sk-[a-zA-Z0-9]{20,}",  # OpenAI API keys
        "Bearer [a-zA-Z0-9._-]+",  # Bearer tokens
        "custom_secret",  # Your custom field
        "my_api_key",  # Your custom field
        "email",  # Email addresses
    ],
    redaction_mode="mask",
))

What Gets Filtered

The SDK filters sensitive data in:

  • Request Headers: Authorization, API keys, tokens
  • Span Attributes: All OpenTelemetry span attributes
  • Custom Events: Event properties containing sensitive data

Note: Request and response bodies are never collected, so no filtering is needed for them.

Disable Filtering (Development Only)

⚠️ Warning: Only disable filtering in development environments:

lupis = LupisSDK.init(LupisConfig(
    project_id="your-project-id",
    filter_sensitive_data=False,  # ⚠️ Sensitive data will be exposed!
))

Production Security

  • Enabled by default - No configuration needed
  • Comprehensive coverage - Common sensitive patterns included
  • Configurable - Add custom patterns as needed
  • Performance optimized - Minimal impact when enabled
  • Debugging friendly - Mask mode preserves partial data for debugging

Shutdown (optional)

The SDK flushes pending work on a timer and registers an atexit hook so traces are sent during normal process shutdown—no manual shutdown call is required for typical apps. Call await lupis.shutdown() only when you need to force an immediate flush (for example, in short-lived scripts or tests).

Examples

See the examples/ directory for more usage examples:

  • event_tracking_example.py - Custom event tracking
  • anthropic_example.py - Anthropic API integration
  • openai_example.py - OpenAI API integration
  • langchain_example.py - LangChain integration
  • streaming_example.py - Streaming responses

Requirements

  • Python 3.8+
  • requests
  • opentelemetry-api
  • opentelemetry-sdk
  • opentelemetry-exporter-otlp-proto-http
  • opentelemetry-instrumentation-requests

License

Made with ❤️ by the Lupis team

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lupislabs-1.0.1.tar.gz (25.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lupislabs-1.0.1-py3-none-any.whl (26.2 kB view details)

Uploaded Python 3

File details

Details for the file lupislabs-1.0.1.tar.gz.

File metadata

  • Download URL: lupislabs-1.0.1.tar.gz
  • Upload date:
  • Size: 25.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lupislabs-1.0.1.tar.gz
Algorithm Hash digest
SHA256 ccfd9716a850b4d416f230ecba3c76965d13407f511658bdf68c60684b552294
MD5 13ecc5536e5cdb2b108ac2a1fdfd0e9a
BLAKE2b-256 c3fce9334194d44289cadb17de6e91818309140ba5693387865c3be518347a3b

See more details on using hashes here.

Provenance

The following attestation bundles were made for lupislabs-1.0.1.tar.gz:

Publisher: publish-python.yml on henchiyb/lupis-labs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lupislabs-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: lupislabs-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 26.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lupislabs-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e97fd27d5597445b7cf3e53b0a05bcd769584333aebaea23161d019bb422dc42
MD5 6c1d6d443de9f2d0266f3abe9f713849
BLAKE2b-256 9a2607370555e93b5dbb3e612f6cbdd6187d4ba7db067e690c1adbb78c78cbf3

See more details on using hashes here.

Provenance

The following attestation bundles were made for lupislabs-1.0.1-py3-none-any.whl:

Publisher: publish-python.yml on henchiyb/lupis-labs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page