sp-obs


Namesp-obs JSON
Version 0.1.3 PyPI version JSON
download
home_pageNone
SummaryObservability integration with Spinal
upload_time2025-07-28 09:33:33
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseNone
keywords ai llm monitoring observability opentelemetry tracing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # SP-OBS: Spinal OpenTelemetry Integration

SP-OBS is Spinal's cost tracking library built on top of open telemetry. It works by adding isolated tracers to libraries that have not been instrumented
and attached a processor to libraries that aloready have been instrumented. 
This means we can also play nice with other observability libraries out there. 
## Features

- 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

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

### With AI Provider Support

```bash
# For OpenAI support
pip install sp-obs[openai]

# For Anthropic support  
pip install sp-obs[anthropic]

# For all providers
pip install sp-obs[all]
```

## Quick Start

### Configuration

First, configure SP-OBS with your endpoint and API key:

```python
import sp_obs

# Configure globally (recommended)
sp_obs.configure(
    api_key="your-api-key"
    # endpoint defaults to "https://cloud.withspinal.com" if not specified
)
```

Or use environment variables:
- `SPINAL_TRACING_ENDPOINT` (defaults to "https://cloud.withspinal.com")
- `SPINAL_API_KEY`

### Instrumenting AI Providers

```python
import sp_obs

# Configure SP-OBS
sp_obs.configure()

# Instrument providers
sp_obs.instrument_openai()
sp_obs.instrument_anthropic()
sp_obs.instrument_httpx()
sp_obs.instrument_requests()
```

### Adding Context to Traces

Use the context manager to add user and workflow information:

```python
import sp_obs

# Add context using context manager
with sp_obs.add_context(
    workflow_id="workflow-123",
    user_id="user-456",
    aggregation_id="session-789"  # optional
):
    # All spans created here will have this context
    response = client.chat.completions.create(...)
```

## Configuration Options

### Environment Variables

- `SPINAL_TRACING_ENDPOINT`: HTTP endpoint to send spans to (default: "https://cloud.withspinal.com")
- `SPINAL_API_KEY`: API key for authentication
- `SPINAL_PROCESS_MAX_QUEUE_SIZE`: Max spans in queue (default: 2048)
- `SPINAL_PROCESS_SCHEDULE_DELAY`: Export delay in ms (default: 5000)
- `SPINAL_PROCESS_MAX_EXPORT_BATCH_SIZE`: Batch size (default: 512)
- `SPINAL_PROCESS_EXPORT_TIMEOUT`: Export timeout in ms (default: 30000)

### Advanced Configuration

```python
sp_obs.configure(
    api_key="your-api-key",
    endpoint="https://cloud.withspinal.com",  # Optional - this is the default
    headers={"Custom-Header": "value"},
    timeout=5,
    max_queue_size=2048,
    max_export_batch_size=512,
    schedule_delay_millis=5000,
    export_timeout_millis=30000,
    scrubber=my_custom_scrubber  # Optional
)
```

## Data Scrubbing

SP-OBS includes automatic scrubbing of sensitive data:

```python
from sp_obs import DefaultScrubber, NoOpScrubber

# Use default scrubber (redacts tokens, keys, passwords)
sp_obs.configure(scrubber=DefaultScrubber())

# Or disable scrubbing
sp_obs.configure(scrubber=NoOpScrubber())

# Or implement custom scrubbing
class MyCustomScrubber:
    def scrub_attributes(self, attributes: dict) -> dict:
        # Your scrubbing logic
        return attributes

sp_obs.configure(scrubber=MyCustomScrubber())
```

## Performance Considerations

SP-OBS uses a BatchSpanProcessor to minimize performance impact:

- Spans are batched and sent asynchronously in a background thread
- Default batch size: 512 spans
- Default flush interval: 5 seconds
- Spans are dropped if queue exceeds max size (default: 2048)

To tune for high-volume applications:

```python
sp_obs.configure(
    max_queue_size=5000,          # Increase queue size
    max_export_batch_size=1000,   # Larger batches
    schedule_delay_millis=2000    # More frequent exports
)
```

## What Spans Are Captured?

SP-OBS automatically captures:
- AI/LLM spans (identified by `gen_ai.system` attribute)
- HTTPX and request spans
- 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 Application

```python
from fastapi import FastAPI
import sp_obs
from openai import AsyncOpenAI

app = FastAPI()
client = AsyncOpenAI()

# Configure on startup
@app.on_event("startup")
async def startup():
    sp_obs.configure()
    sp_obs.instrument_openai()

@app.post("/generate")
async def generate(user_id: str, workflow_id: str):
    with sp_obs.add_context(user_id=user_id, workflow_id=workflow_id):
        response = await client.chat.completions.create(
            model="gpt-4",
            messages=[{"role": "user", "content": "Hello"}]
        )
        return response
```

## License

MIT License - see LICENSE file for details.
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "sp-obs",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "ai, llm, monitoring, observability, opentelemetry, tracing",
    "author": null,
    "author_email": "Andrew van Rensburg <andrew@withspinal.com>",
    "download_url": "https://files.pythonhosted.org/packages/5c/bd/e3a0b2ce22144158aa0fed61bbcbad71a400469a3d07e838e4fa96b8b2de/sp_obs-0.1.3.tar.gz",
    "platform": null,
    "description": "# SP-OBS: Spinal OpenTelemetry Integration\n\nSP-OBS is Spinal's cost tracking library built on top of open telemetry. It works by adding isolated tracers to libraries that have not been instrumented\nand attached a processor to libraries that aloready have been instrumented. \nThis means we can also play nice with other observability libraries out there. \n## Features\n\n- Seamlessly integrates with existing OpenTelemetry setups\n- Works with Logfire, vanilla OpenTelemetry, or any OTEL-compatible framework\n- Adds user and workflow context to spans for better tracking\n- Selective span processing - only sends relevant AI/billing spans\n\n## Installation\n\n```bash\npip install sp-obs\n```\n\n### With AI Provider Support\n\n```bash\n# For OpenAI support\npip install sp-obs[openai]\n\n# For Anthropic support  \npip install sp-obs[anthropic]\n\n# For all providers\npip install sp-obs[all]\n```\n\n## Quick Start\n\n### Configuration\n\nFirst, configure SP-OBS with your endpoint and API key:\n\n```python\nimport sp_obs\n\n# Configure globally (recommended)\nsp_obs.configure(\n    api_key=\"your-api-key\"\n    # endpoint defaults to \"https://cloud.withspinal.com\" if not specified\n)\n```\n\nOr use environment variables:\n- `SPINAL_TRACING_ENDPOINT` (defaults to \"https://cloud.withspinal.com\")\n- `SPINAL_API_KEY`\n\n### Instrumenting AI Providers\n\n```python\nimport sp_obs\n\n# Configure SP-OBS\nsp_obs.configure()\n\n# Instrument providers\nsp_obs.instrument_openai()\nsp_obs.instrument_anthropic()\nsp_obs.instrument_httpx()\nsp_obs.instrument_requests()\n```\n\n### Adding Context to Traces\n\nUse the context manager to add user and workflow information:\n\n```python\nimport sp_obs\n\n# Add context using context manager\nwith sp_obs.add_context(\n    workflow_id=\"workflow-123\",\n    user_id=\"user-456\",\n    aggregation_id=\"session-789\"  # optional\n):\n    # All spans created here will have this context\n    response = client.chat.completions.create(...)\n```\n\n## Configuration Options\n\n### Environment Variables\n\n- `SPINAL_TRACING_ENDPOINT`: HTTP endpoint to send spans to (default: \"https://cloud.withspinal.com\")\n- `SPINAL_API_KEY`: API key for authentication\n- `SPINAL_PROCESS_MAX_QUEUE_SIZE`: Max spans in queue (default: 2048)\n- `SPINAL_PROCESS_SCHEDULE_DELAY`: Export delay in ms (default: 5000)\n- `SPINAL_PROCESS_MAX_EXPORT_BATCH_SIZE`: Batch size (default: 512)\n- `SPINAL_PROCESS_EXPORT_TIMEOUT`: Export timeout in ms (default: 30000)\n\n### Advanced Configuration\n\n```python\nsp_obs.configure(\n    api_key=\"your-api-key\",\n    endpoint=\"https://cloud.withspinal.com\",  # Optional - this is the default\n    headers={\"Custom-Header\": \"value\"},\n    timeout=5,\n    max_queue_size=2048,\n    max_export_batch_size=512,\n    schedule_delay_millis=5000,\n    export_timeout_millis=30000,\n    scrubber=my_custom_scrubber  # Optional\n)\n```\n\n## Data Scrubbing\n\nSP-OBS includes automatic scrubbing of sensitive data:\n\n```python\nfrom sp_obs import DefaultScrubber, NoOpScrubber\n\n# Use default scrubber (redacts tokens, keys, passwords)\nsp_obs.configure(scrubber=DefaultScrubber())\n\n# Or disable scrubbing\nsp_obs.configure(scrubber=NoOpScrubber())\n\n# Or implement custom scrubbing\nclass MyCustomScrubber:\n    def scrub_attributes(self, attributes: dict) -> dict:\n        # Your scrubbing logic\n        return attributes\n\nsp_obs.configure(scrubber=MyCustomScrubber())\n```\n\n## Performance Considerations\n\nSP-OBS uses a BatchSpanProcessor to minimize performance impact:\n\n- Spans are batched and sent asynchronously in a background thread\n- Default batch size: 512 spans\n- Default flush interval: 5 seconds\n- Spans are dropped if queue exceeds max size (default: 2048)\n\nTo tune for high-volume applications:\n\n```python\nsp_obs.configure(\n    max_queue_size=5000,          # Increase queue size\n    max_export_batch_size=1000,   # Larger batches\n    schedule_delay_millis=2000    # More frequent exports\n)\n```\n\n## What Spans Are Captured?\n\nSP-OBS automatically captures:\n- AI/LLM spans (identified by `gen_ai.system` attribute)\n- HTTPX and request spans\n- Explicitly created billing event spans\n- Spans with attached user/workflow context\n\nAll other spans are ignored to minimize overhead and data transfer.\n\n## Integration Examples\n\n### FastAPI Application\n\n```python\nfrom fastapi import FastAPI\nimport sp_obs\nfrom openai import AsyncOpenAI\n\napp = FastAPI()\nclient = AsyncOpenAI()\n\n# Configure on startup\n@app.on_event(\"startup\")\nasync def startup():\n    sp_obs.configure()\n    sp_obs.instrument_openai()\n\n@app.post(\"/generate\")\nasync def generate(user_id: str, workflow_id: str):\n    with sp_obs.add_context(user_id=user_id, workflow_id=workflow_id):\n        response = await client.chat.completions.create(\n            model=\"gpt-4\",\n            messages=[{\"role\": \"user\", \"content\": \"Hello\"}]\n        )\n        return response\n```\n\n## License\n\nMIT License - see LICENSE file for details.",
    "bugtrack_url": null,
    "license": null,
    "summary": "Observability integration with Spinal",
    "version": "0.1.3",
    "project_urls": {
        "Homepage": "https://github.com/withspinal/sp-obs",
        "Issues": "https://github.com/withspinal/sp-obs/issues"
    },
    "split_keywords": [
        "ai",
        " llm",
        " monitoring",
        " observability",
        " opentelemetry",
        " tracing"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ac1ddd82c46aa1a390e89d9ee98ff88921cea23d6e21b029b43b108c7b200502",
                "md5": "72e1d3c85555090e2de734b044bab925",
                "sha256": "001f363a195ec695a367f976a3f0dcf5660e6cf9998078d46f6bd61007f9db0f"
            },
            "downloads": -1,
            "filename": "sp_obs-0.1.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "72e1d3c85555090e2de734b044bab925",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 17182,
            "upload_time": "2025-07-28T09:33:31",
            "upload_time_iso_8601": "2025-07-28T09:33:31.351763Z",
            "url": "https://files.pythonhosted.org/packages/ac/1d/dd82c46aa1a390e89d9ee98ff88921cea23d6e21b029b43b108c7b200502/sp_obs-0.1.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5cbde3a0b2ce22144158aa0fed61bbcbad71a400469a3d07e838e4fa96b8b2de",
                "md5": "8d858120b6f7830e21ee283e3846892d",
                "sha256": "64073311e5e3a1afec4b4e899cd5651b9276855739b19186268072f47f495cd8"
            },
            "downloads": -1,
            "filename": "sp_obs-0.1.3.tar.gz",
            "has_sig": false,
            "md5_digest": "8d858120b6f7830e21ee283e3846892d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 58627,
            "upload_time": "2025-07-28T09:33:33",
            "upload_time_iso_8601": "2025-07-28T09:33:33.379077Z",
            "url": "https://files.pythonhosted.org/packages/5c/bd/e3a0b2ce22144158aa0fed61bbcbad71a400469a3d07e838e4fa96b8b2de/sp_obs-0.1.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-28 09:33:33",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "withspinal",
    "github_project": "sp-obs",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "sp-obs"
}
        
Elapsed time: 1.73701s