Advanced SDK Topics
SDKManual spans, sampling, rate limiting, and advanced configuration.
Beyond the basics, Traccia provides advanced features for fine-grained control over tracing, performance optimization, and custom instrumentation scenarios.
Manual Span Creation
While the @observe() decorator covers most use cases, sometimes you need manual control over span creation and lifecycle.
Using Context Managers (Python) or Active Spans (Node)
from traccia import span
# Simple spanwith span("database_query"): result = db.execute("SELECT * FROM users")
# With attributeswith span("api_call", {"endpoint": "/users", "method": "GET"}) as s: response = requests.get("https://api.example.com/users") s.set_attribute("status_code", response.status_code) s.set_attribute("response_time_ms", response.elapsed.total_seconds() * 1000)Using Tracer Directly
from traccia import get_tracer
tracer = get_tracer("my-service")
# Context managerwith tracer.start_as_current_span("operation") as span: span.set_attribute("user_id", "123") span.add_event("Processing started") try: result = process_data() span.set_status(SpanStatus.OK) except Exception as e: span.record_exception(e) span.set_status(SpanStatus.ERROR, str(e)) raise
# Manual start/end (use with caution)span = tracer.start_span("manual-span")try: do_work()finally: span.end() # Always call end()!Long-Lived Spans (Streaming)
For streaming LLM responses or multi-step async callbacks, use span_scope() / spanScope() to keep a parent span open until you explicitly call end(). Use run() / runAsync() so child spans attach correctly.
from traccia import span_scope
async def chat_turn(user_msg: str): turn = span_scope("chat.turn", attributes={"span.type": "llm"}) try: async def _stream(): async for chunk in llm.stream(user_msg): yield chunk
async for chunk in turn.run_async(lambda: _stream()): yield chunk except Exception as e: turn.end(error=e) raise else: turn.end()Span Methods
set_attribute(key, value) — Add or update a span attributeadd_event(name, attributes=) — Add a timestamped eventrecord_exception(exception) — Record an exception eventset_status(status, description="") — Set span status (OK, ERROR, UNSET)end() — End the span (automatic with context managers)Manual span management
span.end() is called, even if an exception occurs. Use try/finally blocks or context managers.Sampling
Sampling reduces the volume of traces sent to your backend by randomly selecting a percentage of traces to export. This is useful for high-throughput applications where capturing every trace would be too expensive.
Head-Based Sampling
Traccia uses head-based sampling, which means the sampling decision is made when the trace starts and applies to all spans in that trace.
from traccia import init
# Sample 10% of tracesinit(sample_rate=0.1)
# Sample 50% of tracesinit(sample_rate=0.5)
# Sample all traces (default)init(sample_rate=1.0)Via Configuration
[tracing]sample_rate = 0.1 # Sample 10% of tracesCost vs. observability
Rate Limiting
Rate limiting controls the maximum number of spans exported per second, preventing your application from overwhelming the backend or consuming too many resources during traffic spikes.
Configuration
from traccia import init
# Limit to 100 spans per secondinit(max_spans_per_second=100)
# With blocking configurationinit( max_spans_per_second=100, max_block_ms=100, # Block up to 100ms before dropping max_queue_size=5000 # Max queued spans)Via Configuration File
[rate_limiting]max_spans_per_second = 100.0max_block_ms = 100max_queue_size = 5000How It Works
max_block_ms waiting for tokens.max_queue_size spans can be queued. When full, oldest spans are dropped.Dropped spans
Runtime Configuration
Some configuration values can be changed at runtime without restarting your application. This is useful for per-request metadata like session IDs, user IDs, and tenant IDs.
from traccia import runtime_config
# Set runtime metadata (applies to all subsequent spans)runtime_config.set_session_id("session-abc123")runtime_config.set_user_id("user-xyz789")runtime_config.set_tenant_id("tenant-acme")runtime_config.set_project_id("project-ml")runtime_config.set_agent_id("support-bot")
# Get current valuessession_id = runtime_config.get_session_id()user_id = runtime_config.get_user_id()
# Enable debug logging at runtimeruntime_config.set_debug(True)
# Set attribute truncation limitruntime_config.set_attr_truncation_limit(2000)Multi-Tenant Pattern
from traccia import init, runtime_config, observe
# Initialize once at startupinit(api_key="tr_live_xxxxxxxxxxxx")
# Per-request handler@observe()def handle_request(request): # Set tenant context from request runtime_config.set_tenant_id(request.headers.get("X-Tenant-ID")) runtime_config.set_user_id(request.user.id) runtime_config.set_session_id(request.session.id) # All spans in this request will have these IDs return process_request(request)Span Processors
Traccia uses span processors to enrich, transform, and export spans. Understanding the processor pipeline helps you understand what happens to your traces.
Built-in Processors
TokenCountingProcessor
Automatically counts tokens for LLM calls using tiktoken. Adds llm.usage.prompt_tokens, llm.usage.completion_tokens, llm.usage.total_tokens, and llm.usage.source.
Control: enable_token_counting=True/False
CostAnnotatingProcessor
Calculates estimated costs based on token counts and model pricing. Adds llm.cost.usd and llm.pricing.* metadata. Skips non-LLM spans when span.type is set to a value other than llm.
Control: enable_costs=True/False
AgentEnrichmentProcessor
Enriches spans with agent metadata from runtime config and agent_config.json. Adds session/user/tenant/project/agent IDs.
Always enabled (core functionality)
GuardrailDetectorProcessor
Detects missing or triggered guardrails and writes findings onto span attributes.
Control: guardrail_heuristics=True/False
GovernanceEnrichmentProcessor
Adds baseline governance attributes and optional EU AI Act overlay fields to every span.
Control: compliance={frameworks: ["eu_ai_act"]}
RedactionSpanProcessor
Masks email, phone, and SSN-like patterns on sensitive span attributes before export.
Control: redact_pii=True or TRACCIA_REDACT_PII=1
RateLimitingSpanProcessor
Enforces rate limits on span export. Blocks and drops spans when limit exceeded.
Control: max_spans_per_second
BatchSpanProcessor
Batches spans before export for efficiency. Flushes on schedule or when batch size reached.
Control: max_export_batch_size, schedule_delay_millis
Processor Pipeline
Processors run in registration order when a span ends. Optional processors are skipped when disabled.
Context Propagation
For distributed systems with multiple services or agents, you need to propagate trace context across HTTP boundaries to maintain parent-child relationships.
Automatic Propagation
When auto-instrumentation is enabled for requests and FastAPI, context propagation happens automatically.
Manual Propagation
Both SDKs expose W3C Trace Context helpers for manual header injection and extraction. Auto-instrumentation for HTTP clients and servers handles this automatically when enabled.
from traccia.instrumentation import inject_http_headers, extract_parent_contextimport requests
# Client: Inject context into outgoing requestheaders = {}inject_http_headers(headers)response = requests.post( "http://other-service/api", headers=headers, json=data)
# Server: Extract context from incoming requestfrom fastapi import Request
@app.post("/api")def handle_request(request: Request): parent_context = extract_parent_context(dict(request.headers)) # Spans created here will be children of the incoming trace ...W3C Trace Context
traceparent and tracestate headers) for maximum compatibility.Performance Considerations
Minimize Overhead
- • Use sampling for high-throughput applications
- • Enable rate limiting to cap resource usage
- • Skip large arguments/results with decorator options
- • Increase batch size and delay for fewer exports
Typical Overhead
- • Per-span overhead: ~50-200 microseconds
- • Memory per span: ~1-2 KB
- • Network: Batched exports reduce connection overhead
- • CPU: Token counting adds ~1-5ms for LLM calls
Next Steps
© 2026 Traccia.