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, andaiohttp - 📊 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.Sessionhttp.client.HTTPConnection/HTTPSConnectionurllib3connection poolshttpx.Clientandhttpx.AsyncClientaiohttp.ClientSession
Nested client usage (for example requests → urllib3 → http.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 settingotlp_endpointif 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 keyspk_[a-zA-Z0-9]{20,}- Paddle API keysak-[a-zA-Z0-9]{20,}- Anthropic API keysBearer [a-zA-Z0-9._-]+- Bearer tokensx-api-key,authorization- API key headers
Authentication
password,passwd,pwd- Password fieldstoken,access_token,refresh_token,session_token- Various tokenssecret,private_key,api_secret- Secret fields
Personal Data
ssn,social_security- Social Security Numberscredit_card,card_number- Credit card numberscvv,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 trackinganthropic_example.py- Anthropic API integrationopenai_example.py- OpenAI API integrationlangchain_example.py- LangChain integrationstreaming_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccfd9716a850b4d416f230ecba3c76965d13407f511658bdf68c60684b552294
|
|
| MD5 |
13ecc5536e5cdb2b108ac2a1fdfd0e9a
|
|
| BLAKE2b-256 |
c3fce9334194d44289cadb17de6e91818309140ba5693387865c3be518347a3b
|
Provenance
The following attestation bundles were made for lupislabs-1.0.1.tar.gz:
Publisher:
publish-python.yml on henchiyb/lupis-labs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lupislabs-1.0.1.tar.gz -
Subject digest:
ccfd9716a850b4d416f230ecba3c76965d13407f511658bdf68c60684b552294 - Sigstore transparency entry: 679506316
- Sigstore integration time:
-
Permalink:
henchiyb/lupis-labs@333820fd0a3b0c96756c70e0695eefd29337be47 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/henchiyb
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@333820fd0a3b0c96756c70e0695eefd29337be47 -
Trigger Event:
workflow_dispatch
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e97fd27d5597445b7cf3e53b0a05bcd769584333aebaea23161d019bb422dc42
|
|
| MD5 |
6c1d6d443de9f2d0266f3abe9f713849
|
|
| BLAKE2b-256 |
9a2607370555e93b5dbb3e612f6cbdd6187d4ba7db067e690c1adbb78c78cbf3
|
Provenance
The following attestation bundles were made for lupislabs-1.0.1-py3-none-any.whl:
Publisher:
publish-python.yml on henchiyb/lupis-labs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lupislabs-1.0.1-py3-none-any.whl -
Subject digest:
e97fd27d5597445b7cf3e53b0a05bcd769584333aebaea23161d019bb422dc42 - Sigstore transparency entry: 679506432
- Sigstore integration time:
-
Permalink:
henchiyb/lupis-labs@333820fd0a3b0c96756c70e0695eefd29337be47 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/henchiyb
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@333820fd0a3b0c96756c70e0695eefd29337be47 -
Trigger Event:
workflow_dispatch
-
Statement type: