Observabilty intergration with Spinal
Project description
SP-OBS: Spinal OpenTelemetry Integration
SP-OBS is an OpenTelemetry span interceptor that automatically attaches to existing TracerProvider instances to duplicate AI/LLM spans to custom endpoints for billing and monitoring.
Features
- Automatically intercepts AI/LLM spans (e.g., from OpenAI, Anthropic)
- Seamlessly integrates with existing OpenTelemetry setups
- Works with Logfire, vanilla OpenTelemetry, or any OTEL-compatible framework
- Adds user and workflow context to spans for better tracking
- Selective span processing - only sends relevant AI/billing spans
Installation
pip install sp-obs
Quick Start
With Existing OpenTelemetry Setup
If you already have OpenTelemetry configured (e.g., via Logfire, manual setup, or auto-instrumentation):
from sp_obs import spinal_attach
# Simply attach to the existing TracerProvider
spinal_attach()
With Logfire
import logfire
from sp_obs import spinal_attach
# Configure logfire without sending to their backend
logfire.configure(send_to_logfire=False)
# Attach Spinal processor
spinal_attach()
# Use logfire instrumentation as normal
logfire.instrument_openai()
Without Any OpenTelemetry Setup
from sp_obs import spinal_attach
# Initialize OpenTelemetry and attach Spinal
spinal_attach(init_otel_if_needed=True, service_name="my-service")
Manual Configuration
For more control, you can manually create and add the processor:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from sp_obs import SpinalConfig, SpinalSpanProcessor
# Set up OpenTelemetry
provider = TracerProvider()
trace.set_tracer_provider(provider)
# Configure and add Spinal processor
config = SpinalConfig(
endpoint="https://your-endpoint.com/spans",
api_key="your-api-key"
)
processor = SpinalSpanProcessor(config)
provider.add_span_processor(processor)
Configuration
Environment Variables
SPINAL_TRACING_ENDPOINT: HTTP endpoint to send spans toSPINAL_API_KEY: API key for authentication
SpinalConfig Options
config = SpinalConfig(
endpoint="https://your-endpoint.com/spans", # Required
api_key="your-api-key", # Required
headers={"Custom-Header": "value"}, # Optional custom headers
timeout=5, # Request timeout in seconds
batch_size=100 # Batch size for span export
)
Adding Context to Traces
Add user and workflow context that will be attached to all relevant spans:
from sp_obs import spinal_add_context, spinal_add_as_billable
# Add context for tracking
context_token = spinal_add_context(
workflow_id="workflow-123",
user_id="user-456"
)
# Your AI/LLM operations here...
# Mark specific operations as billable
spinal_add_as_billable({
"operation": "text_generation",
"model": "gpt-4",
"tokens": 1500
})
Checking TracerProvider Status
from sp_obs import is_tracer_provider_configured
if is_tracer_provider_configured():
print("OpenTelemetry is already configured")
else:
print("No TracerProvider configured")
What Spans Are Captured?
SP-OBS automatically captures:
- AI/LLM spans (identified by
gen_ai.systemattribute) - Explicitly created billing event spans
- Spans with attached user/workflow context
All other spans are ignored to minimize overhead and data transfer.
Integration Examples
FastAPI with Logfire
from fastapi import FastAPI
import logfire
from sp_obs import spinal_attach, spinal_add_context
app = FastAPI()
# Configure observability
logfire.configure(send_to_logfire=False)
spinal_attach()
logfire.instrument_openai()
@app.post("/generate")
async def generate(user_id: str, workflow_id: str):
# Add context for this request
token = spinal_add_context(
user_id=user_id,
workflow_id=workflow_id
)
# Your OpenAI call here - automatically tracked
response = await openai_client.chat.completions.create(...)
return response
Standalone Script
from openai import OpenAI
from sp_obs import spinal_attach, spinal_add_context
# Initialize with automatic OTEL setup
spinal_attach(init_otel_if_needed=True)
# Add context
spinal_add_context(user_id="test-user", workflow_id="batch-job-1")
# Use OpenAI - spans automatically captured
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello!"}]
)
License
[Your License Here]
Project details
Release history Release notifications | RSS feed
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 sp_obs-0.1.0.tar.gz.
File metadata
- Download URL: sp_obs-0.1.0.tar.gz
- Upload date:
- Size: 23.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4255e16eb81c09c0fc657ff6a9c1c00b8493ebc5dd9874b4e0adb9dd01a9b10b
|
|
| MD5 |
84bd0513a9a8c980e8b245b3cf5ce6ee
|
|
| BLAKE2b-256 |
fca668566132c4d891c0b35e1a00d13b2a988cecaa24dad880d31e77157ec61e
|
File details
Details for the file sp_obs-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sp_obs-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
266f4c04bb33df99ff2c168de14941df37b32c00b6696b3f928a5633ab611217
|
|
| MD5 |
b4d58901ed4107049f87206464e1cbff
|
|
| BLAKE2b-256 |
50c4cde7220a58a2998634bae860050a9951036349fc3f6307fb1d816df126b8
|