Overview
RDK allows you to attach custom metadata to your traces for better filtering, grouping, and analysis. This includes tags, arbitrary metadata, user IDs, and session IDs.
Tags are simple string labels for categorizing traces:
from rdk import observe
@observe(name="chat", tags=["production", "gpt-4", "high-priority"])
def chat(message: str) -> str:
# ...
Tags are useful for:
- Environment labels (
production, staging, development)
- Feature flags (
new-model, experiment-a)
- Priority levels (
high-priority, batch)
Metadata is a dictionary for storing structured data:
from rdk import observe
@observe(
name="process-order",
metadata={
"order_type": "subscription",
"plan": "enterprise",
"region": "us-west-2",
}
)
def process_order(order_id: str) -> dict:
# ...
Common metadata fields:
- Business context (
order_type, plan, region)
- Request info (
request_id, source)
- Feature toggles (
model_version, experiment)
User ID
Track which user generated a trace:
from rdk import observe
@observe(name="chat", user_id="user_12345")
def chat(user_id: str, message: str) -> str:
# ...
# Or dynamically
@observe(name="chat")
def chat_dynamic(user_id: str, message: str) -> str:
# User ID from function parameter
# Would need to be set in metadata instead
...
Session ID
Group traces by session:
from rdk import observe
@observe(name="chat", session_id="session_abc123")
def chat(message: str) -> str:
# All calls in this session are linked
...
Session IDs help you:
- Track conversation history
- Debug multi-turn interactions
- Analyze user journeys
Complete Example
import os
import uuid
from anthropic import Anthropic
from rdk import init, observe, shutdown
init(
endpoint=os.environ.get("RDK_ENDPOINT"),
api_key=os.environ.get("RDK_API_KEY"),
)
class ChatService:
def __init__(self, user_id: str):
self.user_id = user_id
self.session_id = str(uuid.uuid4())
self.client = Anthropic()
@observe(
name="chat-service",
tags=["production", "chat"],
metadata={"service": "customer-support"}
)
def chat(self, message: str) -> str:
response = self.client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": message}]
)
return response.content[0].text
# Usage
service = ChatService(user_id="user_123")
response = service.chat("Hello!")
shutdown()
For dynamic values, use the decorator with a callable:
from rdk import observe
def get_trace_config(request_id: str, **kwargs):
return {
"name": f"request-{request_id}",
"tags": ["api"],
"metadata": {"request_id": request_id}
}
# Note: This pattern requires manual trace management
# See Manual Tracing for advanced use cases
Filtering Traces
Metadata enables powerful filtering in your dashboard:
-- Find all traces for a specific user
user_id = "user_123"
-- Find high-priority production traces
tags CONTAINS "production" AND tags CONTAINS "high-priority"
-- Find enterprise plan requests
metadata.plan = "enterprise"
Best Practices
Keep metadata values simple (strings, numbers, booleans). Avoid nested objects for better queryability.
- Consistent naming - Use a naming convention across your app
- Avoid PII - Don’t put sensitive data in metadata
- Limit cardinality - High-cardinality values (like UUIDs) can impact query performance
- Document your schema - Keep a reference of your metadata fields