UNPKG

spinal-obs-node

Version:

WithSpinal cost-aware OpenTelemetry SDK for Node.js

350 lines (263 loc) 7.34 kB
# Spinal Local Mode Spinal's local mode allows you to collect and analyze API usage data locally without sending data to the cloud. This is perfect for development, testing, and cost analysis without requiring an API key. ## Quick Start ### 1. Install Spinal ```bash npm install spinal-obs-node ``` ### 2. Configure in Local Mode ```javascript import { configure, instrumentHTTP, instrumentOpenAI, tag, shutdown } from 'spinal-obs-node'; // Configure Spinal in local mode configure({ mode: 'local', localStorePath: './spans.jsonl' // Optional: custom path for span data }); // Instrument HTTP and OpenAI API calls instrumentHTTP(); instrumentOpenAI(); ``` ### 3. Add Contextual Tags ```javascript // Tag your operations for cost grouping and analysis const userFlowTag = tag({ aggregationId: 'user-signup-flow', tenant: 'acme-corp', userId: 'user-123' }); // Your application code here // ... make API calls ... // Clean up when done userFlowTag.dispose(); ``` ### 4. View Collected Data Use the CLI to view your collected data: ```bash # Display recent spans in table format npx spinal local # Show summary statistics npx spinal local --format summary # Export as JSON npx spinal local --format json --limit 50 ``` ## Configuration Options ### Environment Variables ```bash # Set local mode (default if no API key is provided) SPINAL_MODE=local # Custom path for span storage SPINAL_LOCAL_STORE_PATH=./my-spans.jsonl # Tuning parameters SPINAL_PROCESS_MAX_QUEUE_SIZE=2048 SPINAL_PROCESS_MAX_EXPORT_BATCH_SIZE=512 SPINAL_PROCESS_SCHEDULE_DELAY=5000 SPINAL_PROCESS_EXPORT_TIMEOUT=30000 ``` ### Programmatic Configuration ```javascript configure({ mode: 'local', localStorePath: './custom-spans.jsonl', maxQueueSize: 1024, maxExportBatchSize: 256, scheduleDelayMs: 2000, exportTimeoutMs: 15000 }); ``` ## Integration Examples ### Express.js Backend ```javascript import express from 'express'; import { configure, instrumentHTTP, instrumentOpenAI, tag } from 'spinal-obs-node'; // Configure Spinal configure({ mode: 'local' }); instrumentHTTP(); instrumentOpenAI(); const app = express(); app.post('/api/chat', async (req, res) => { // Tag the request for cost tracking const requestTag = tag({ aggregationId: 'chat-api', userId: req.user?.id, sessionId: req.session?.id }); try { // Your OpenAI API call here const response = await openai.chat.completions.create({ model: 'gpt-4o-mini', messages: req.body.messages }); res.json(response.data); } finally { requestTag.dispose(); } }); ``` ### Next.js Application ```javascript // pages/api/chat.js import { configure, instrumentHTTP, instrumentOpenAI, tag } from 'spinal-obs-node'; // Configure once at module level if (!global.spinalConfigured) { configure({ mode: 'local' }); instrumentHTTP(); instrumentOpenAI(); global.spinalConfigured = true; } export default async function handler(req, res) { const requestTag = tag({ aggregationId: 'nextjs-chat', userId: req.headers['x-user-id'] }); try { // Your API logic here const result = await processChatRequest(req.body); res.json(result); } finally { requestTag.dispose(); } } ``` ### FastAPI Backend (Python with Node.js instrumentation) ```python # If you have a Node.js service alongside FastAPI import subprocess import json def analyze_costs(): # Run Spinal CLI to get cost analysis result = subprocess.run( ['npx', 'spinal', 'local', '--format', 'summary'], capture_output=True, text=True ) return json.loads(result.stdout) ``` ## CLI Commands ### View Local Data ```bash # Default table view (last 10 spans) npx spinal local # Show more spans npx spinal local --limit 50 # Summary format npx spinal local --format summary # JSON export npx spinal local --format json --limit 100 > spans.json ``` ### Cost Analysis ```bash # Get cost summary npx spinal report # Analyze specific time window npx spinal report --since 7d ``` ### Configuration Status ```bash # Check current configuration npx spinal status ``` ## Data Format Spans are stored in JSONL format with the following structure: ```json { "name": "HTTP GET", "trace_id": "1234567890abcdef", "span_id": "abcdef1234567890", "parent_span_id": null, "start_time": 1640995200000000, "end_time": 1640995201000000, "status": { "code": "OK" }, "attributes": { "http.method": "GET", "http.url": "https://api.openai.com/v1/chat/completions", "spinal.model": "openai:gpt-4o-mini", "spinal.input_tokens": 150, "spinal.output_tokens": 75, "aggregationId": "user-signup-flow", "tenant": "acme-corp" }, "events": [], "links": [] } ``` ## Cost Tracking Spinal automatically tracks costs for: - **OpenAI API calls**: Based on model, input tokens, and output tokens - **HTTP requests**: Duration and endpoint information - **Custom spans**: Any manually created spans with cost attributes ### Cost Attributes Add these attributes to your spans for cost tracking: ```javascript tag({ 'spinal.model': 'openai:gpt-4o-mini', 'spinal.input_tokens': 150, 'spinal.output_tokens': 75, 'spinal.estimated_cost': 0.0025 }); ``` ## Best Practices ### 1. Early Configuration Configure Spinal as early as possible in your application lifecycle: ```javascript // At the top of your main file import { configure, instrumentHTTP, instrumentOpenAI } from 'spinal-obs-node'; configure({ mode: 'local' }); instrumentHTTP(); instrumentOpenAI(); ``` ### 2. Meaningful Aggregation IDs Use descriptive aggregation IDs for cost grouping: ```javascript tag({ aggregationId: 'user-onboarding-flow', feature: 'email-verification', userType: 'premium' }); ``` ### 3. Proper Cleanup Always dispose of tags when done: ```javascript const tag = tag({ aggregationId: 'my-operation' }); try { // Your code here } finally { tag.dispose(); } ``` ### 4. Regular Analysis Set up regular cost analysis: ```bash # Daily cost check npx spinal local --format summary # Weekly report npx spinal report --since 7d ``` ## Troubleshooting ### No Spans Generated 1. **Check configuration**: Ensure `mode: 'local'` is set 2. **Verify instrumentation**: Call `instrumentHTTP()` and `instrumentOpenAI()` 3. **Check file path**: Verify `localStorePath` is writable 4. **Wait for export**: Spans are exported asynchronously (default: 5s delay) ### Performance Impact - **Minimal overhead**: <1ms per span - **Memory usage**: Configurable queue size (default: 2048 spans) - **Disk usage**: ~1KB per span in JSONL format ### Data Privacy Local mode ensures complete privacy: - No data sent to external servers - All data stored locally - Sensitive information automatically scrubbed - Full control over data retention ## Migration to Cloud Mode When ready to use cloud features: 1. **Get API key**: Sign up at [dashboard.withspinal.com](https://dashboard.withspinal.com) 2. **Set environment variable**: `SPINAL_API_KEY=your-key-here` 3. **Update configuration**: Remove `mode: 'local'` or set `mode: 'cloud'` 4. **Data migration**: Historical local data can be imported to cloud dashboard ```javascript // Cloud mode configuration configure({ apiKey: process.env.SPINAL_API_KEY, mode: 'cloud' // or omit for auto-detection }); ```