Metadata-Version: 2.4
Name: sp-obs
Version: 0.5.3
Summary: Observability integration with Spinal
Project-URL: Homepage, https://github.com/withspinal/sp-obs
Project-URL: Issues, https://github.com/withspinal/sp-obs/issues
Author-email: Andrew van Rensburg <andrew@withspinal.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ai,llm,monitoring,observability,opentelemetry,spinal,tracing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.11
Requires-Dist: aiohttp>=3.13.0
Requires-Dist: grpcio<2,>=1.68.1
Requires-Dist: httpx<1.0.0,>=0.28.0
Requires-Dist: opentelemetry-api<2,>=1.38.0
Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.58b0
Requires-Dist: opentelemetry-instrumentation-grpc>=0.59b0
Requires-Dist: opentelemetry-instrumentation-httpx<1,>=0.57b0
Requires-Dist: opentelemetry-instrumentation-requests<1,>=0.57b0
Requires-Dist: opentelemetry-sdk<2,>=1.38.0
Requires-Dist: opentelemetry-semantic-conventions-ai>=0.4.12
Requires-Dist: orjson<4,>=3.11.1
Description-Content-Type: text/markdown

# sp-obs

SP-OBS is Spinal's cost tracking library built on top of OpenTelemetry. It works by automatically instrumenting HTTP libraries (httpx, requests, aiohttp) and gRPC calls, while attaching a processor to existing OpenTelemetry setups. This dual approach allows it to integrate seamlessly with existing observability frameworks while selectively forwarding AI/LLM operations and billing events to Spinal's platform.

## Features

- Seamlessly integrates with existing OpenTelemetry setups
- Works with Logfire, vanilla OpenTelemetry, or any OTEL-compatible framework
- Automatic instrumentation of httpx, requests, aiohttp libraries and gRPC calls
- Adds user and workflow context to spans for better tracking
- Selective span processing - only sends relevant AI/billing spans
- Built-in data scrubbing for sensitive information

## Installation

```bash
pip install sp-obs
```

## Quick Start

```python
import sp_obs

# Configure with your API key
sp_obs.configure(api_key="your-api-key")

# That's it! AI calls are now tracked automatically
```

## Integration with Other Observability Tools

**IMPORTANT**: When using sp-obs alongside other OpenTelemetry providers (Logfire, Langwatch, Langsmith, Langfuse, etc.), you **MUST** set `set_global_tracer=False` to prevent tracer conflicts.

By default, sp-obs sets itself as the global tracer provider. When another OTEL library is already managing tracing, both libraries attempting to set the global tracer will cause conflicts.

### Using with Langwatch/Langsmith/Langfuse

```python
import langwatch

# Set up your primary observability tool first
langwatch.setup(api_key="your-langwatch-key")

# Configure sp-obs with set_global_tracer=False
sp_obs.configure(
    api_key="your-spinal-key",
    set_global_tracer=False
)
```

### Using with Logfire

```python
import logfire
import sp_obs

# Set up Logfire first
logfire.configure()

# Configure sp-obs with set_global_tracer=False
sp_obs.configure(
    api_key="your-spinal-key",
    set_global_tracer=False
)
```

**Note**: sp-obs will still capture and forward AI/LLM spans to Spinal even with `set_global_tracer=False`. It works by attaching its processor to the existing tracer provider.

## Adding Context

Use tags to add business context to your AI operations:

```python
# Context manager (recommended)
with sp_obs.tag(user_id="user-123", workflow_id="chat-session"):
    # All AI calls here will be tagged
    response = openai_client.chat.completions.create(...)

# Or set tags globally
sp_obs.tag(user_id="user-123", workflow_id="chat-session")
```

## Supported Providers

**LLMs**: OpenAI, Anthropic, Perplexity
**Text-to-Speech**: ElevenLabs
**Speech-to-Text**: Deepgram
**APIs & Tools**: SerpAPI, ScrapingBee, Firecrawl

## Billing Events

Track custom billing events within a tagged context:

```python
with sp_obs.tag(user_id="user-123", workflow_id="checkout"):
    sp_obs.add_billing_event(
        success=True,
        amount=99.99,
        currency="USD"
    )
```

## Environment Variables

- `SPINAL_API_KEY` - Your API key
- `SPINAL_TRACING_ENDPOINT` - Custom endpoint (default: https://cloud.withspinal.com)

## Advanced Configuration

### Batch Processing

Control how spans are batched and exported to optimize for your application's needs:

```python
sp_obs.configure(
    api_key="your-api-key",
    max_queue_size=2048,          # Max buffered spans before dropping
    max_export_batch_size=512,    # Spans per batch
    schedule_delay_millis=5000,   # Export interval (ms)
    export_timeout_millis=30000   # Export timeout (ms)
)
```

**Parameter Guide:**

- **`max_queue_size`** (default: 2048)
  - Controls memory usage
  - **Increase** for high-volume applications (10k+ spans/min) to prevent drops during traffic spikes
  - **Decrease** for resource-constrained environments to limit memory footprint
  - **Performance impact**: Higher values = more memory but fewer outgoing network calls

- **`max_export_batch_size`** (default: 512)
  - Balances network efficiency vs. latency
  - **Increase** (up to 2048) for high-throughput applications to reduce network overhead
  - **Decrease** (to 128-256) for low-latency requirements to export spans more frequently
  - **Performance impact**: Larger batches = better network efficiency but slightly higher latency

- **`schedule_delay_millis`** (default: 5000ms)
  - How often to export spans, regardless of batch size
  - **Decrease** (to 1000-2000ms) when you need near real-time visibility
  - **Increase** (to 10000-30000ms) to reduce API calls and network overhead
  - **Performance impact**: Lower values = fresher data but more API calls and network usage

- **`export_timeout_millis`** (default: 30000ms)
  - Maximum time to wait for export to complete before failing
  - **Increase** for unreliable networks or when exporting large batches
  - **Decrease** if you prefer to drop spans rather than block on slow exports
  - **Performance impact**: Only matters when network is slow; higher values prevent timeouts

**Recommended Configurations:**

```python
# High-volume production (10k+ spans/min)
sp_obs.configure(max_queue_size=4096, max_export_batch_size=1024, schedule_delay_millis=3000)

# Low-latency requirements (real-time dashboards)
sp_obs.configure(max_queue_size=1024, max_export_batch_size=128, schedule_delay_millis=1000)

# Resource-constrained (serverless, edge)
sp_obs.configure(max_queue_size=512, max_export_batch_size=256, schedule_delay_millis=10000)
```

### Data Scrubbing

Automatically redact sensitive information from spans:

```python
from sp_obs import DefaultScrubber, NoOpScrubber

# Use default scrubber (removes tokens, keys, passwords)
sp_obs.configure(
    api_key="your-api-key",
    scrubber=DefaultScrubber()
)

# Disable scrubbing
sp_obs.configure(
    api_key="your-api-key",
    scrubber=NoOpScrubber()
)

# Custom scrubber
class CustomScrubber:
    def scrub_attributes(self, attributes: dict) -> dict:
        # Your scrubbing logic
        return attributes

sp_obs.configure(
    api_key="your-api-key",
    scrubber=CustomScrubber()
)
```

### Additional Options

```python
sp_obs.configure(
    api_key="your-api-key",
    endpoint="https://custom.endpoint.com",  # Custom endpoint
    headers={"X-Custom": "header"},          # Additional headers
    timeout=10,                              # Request timeout (seconds)
    set_global_tracer=False                  # See "Integration with Other Observability Tools"
)
```

## License

MIT