Documentation Index Fetch the complete documentation index at: https://docs.honeyhive.ai/llms.txt
Use this file to discover all available pages before exploring further.
Auto-instrumentation captures what your agent did - which models it called, how long each step took, how many tokens it used. Enrichments capture why it matters - which user triggered the run, what feature they were using, whether the result was any good, and what config produced it.
Types of Enrichments
HoneyHive organizes custom attributes into typed namespaces. Each has a dedicated guide.
User Properties Attach user IDs, account tiers, and other user context for per-user filtering and analysis.
User Feedback Capture thumbs-up/down ratings, comments, and implicit signals directly on traces.
Custom Metrics Log evaluation scores, guardrail results, and other numeric measurements computed in your app.
Config Log prompt versions, model parameters, and other configuration context on traces.
Online Experiments Tag traces with experiment IDs and variant names to analyze A/B tests in HoneyHive.
You can also attach arbitrary key-value pairs as metadata (e.g. feature flags, request IDs, environment tags). Any key that doesn’t belong to a typed namespace lands in metadata by default.
For the full list of namespaces and data types, see the Schema Reference .
How to Enrich
There are three functions, each scoped to a different level of your trace.
enrich_session()
enrich_span()
using_attributes
Set attributes once and apply them to all traces in the session. Ideal for tenant context, app version, or user tier. import os
from honeyhive import HoneyHiveTracer
tracer = HoneyHiveTracer.init(
api_key = os.getenv( "HH_API_KEY" ),
project = os.getenv( "HH_PROJECT" )
)
tracer.enrich_session({
"tenant_id" : "acme_corp" ,
"user_tier" : "premium" ,
"app_version" : "2.1.0"
})
You can enrich a specific session by ID, which is useful in distributed systems: tracer.enrich_session(
session_id = "sess_abc123" ,
metadata = { "completed" : True }
)
Add attributes to the current active span. Use inside any @trace-decorated function for per-call context. import os
from honeyhive import HoneyHiveTracer, enrich_span, trace
HoneyHiveTracer.init(
api_key = os.getenv( "HH_API_KEY" ),
project = os.getenv( "HH_PROJECT" )
)
@trace
def process_query ( query : str , user_id : str ):
enrich_span({
"user_id" : user_id,
"query_length" : len (query),
"feature" : "search"
})
# Your logic here...
Enrich auto-instrumented LLM spans (like OpenAI ChatCompletion) without wrapping them in @trace. Use the using_attributes context manager from OpenInference. import os
from honeyhive import HoneyHiveTracer
from openinference.instrumentation import using_attributes
from openinference.instrumentation.openai import OpenAIInstrumentor
import openai
tracer = HoneyHiveTracer.init(
api_key = os.getenv( "HH_API_KEY" ),
project = os.getenv( "HH_PROJECT" )
)
OpenAIInstrumentor().instrument( tracer_provider = tracer.provider)
client = openai.OpenAI()
with using_attributes(
user_id = "user_12345" ,
metadata = { "feature" : "chat_support" }
):
response = client.chat.completions.create(
model = "gpt-4o-mini" ,
messages = [{ "role" : "user" , "content" : "Hello!" }]
)
using_attributes attaches metadata directly to auto-instrumented spans. For your own functions, use @trace with enrich_span().
Global vs Instance Methods
from honeyhive import HoneyHiveTracer, enrich_span
# Global function — works within any @trace context
enrich_span({ "user_id" : "user_123" })
# Instance method — recommended for production
tracer = HoneyHiveTracer.init( ... )
tracer.enrich_span({ "user_id" : "user_123" })
tracer.enrich_session({ "tenant_id" : "acme" })
Use instance methods in production for an explicit tracer reference.
Invocation Patterns
Both enrich_span() and enrich_session() accept data in several forms.
enrich_span({
"user_id" : "user_12345" ,
"feature" : "chat"
})
enrich_span(
user_id = "user_12345" ,
feature = "chat"
)
Organize data by type using named parameters: enrich_span(
metadata = { "user_id" : "user_12345" , "feature" : "chat" },
metrics = { "latency_ms" : 150 , "score" : 0.95 },
user_properties = { "plan" : "premium" },
feedback = { "rating" : 5 }
)
Mixed (namespaces + keywords)
Extra keyword arguments are added to metadata automatically: enrich_span(
metadata = { "user_id" : "user_12345" },
metrics = { "score" : 0.95 },
feature = "chat" , # → metadata.feature
priority = "high" # → metadata.priority
)
Common Use Cases
Attach user identity and message metadata to every traced call. @trace
def generate_response ( user_id : str , message : str ):
enrich_span(
user_properties = { "user_id" : user_id},
metadata = { "message_length" : len (message)}
)
# LLM call...
Tag traces by feature to compare performance across different parts of your app. @trace
def summarize_document ( document : str , feature : str ):
enrich_span({
"feature" : feature,
"document_length" : len (document)
})
# LLM call...
Log scores and experiment variants alongside your traces. @trace
def generate_recommendation ( product_id : str , user_id : str ):
enrich_span(
user_properties = { "user_id" : user_id},
metadata = { "product_id" : product_id, "ab_variant" : "B" },
metrics = { "recommendation_score" : 0.92 }
)
# LLM call...
Enrich spans with success/failure status and error details for debugging. @trace
def risky_operation ( operation_id : str , data : dict ):
enrich_span( metadata = { "operation_id" : operation_id})
try :
result = process(data)
enrich_span( metadata = { "success" : True })
return result
except Exception as e:
enrich_span(
metadata = { "success" : False },
error = str (e)
)
raise
Putting It All Together
This example combines session-level and span-level enrichment in a single application.
Full example: session + span enrichment
import os
from honeyhive import HoneyHiveTracer, enrich_span, trace
from openinference.instrumentation.openai import OpenAIInstrumentor
import openai
tracer = HoneyHiveTracer.init(
api_key = os.getenv( "HH_API_KEY" ),
project = os.getenv( "HH_PROJECT" )
)
OpenAIInstrumentor().instrument( tracer_provider = tracer.provider)
# Session-level context (set once)
tracer.enrich_session({
"tenant_id" : "acme_corp" ,
"user_tier" : "premium" ,
"app_version" : "2.1.0"
})
client = openai.OpenAI()
# Span-level context (per call)
@trace
def chat ( message : str , user_id : str ):
enrich_span({
"user_id" : user_id,
"message_length" : len (message),
"feature" : "chat_support"
})
response = client.chat.completions.create(
model = "gpt-4o-mini" ,
messages = [{ "role" : "user" , "content" : message}]
)
return response.choices[ 0 ].message.content
# Each call inherits session context + gets its own span context
chat( "Hello!" , user_id = "user_123" )
chat( "What's the weather?" , user_id = "user_456" )
Viewing Enriched Data
Open the Session view
Go to your project in the HoneyHive dashboard and select Traces .
Inspect a session
Click any session to expand it. Your enriched data appears in the Metadata and Attributes panels.
Best Practices
Do Don’t Use consistent key names across your app Include sensitive data (passwords, API keys, PII) Add user/session IDs for debugging Attach large values (>1KB per field) Include feature and endpoint identifiers Use random or generated key names Use descriptive names (user_id not uid) Duplicate data already captured by auto-instrumentation
SDK Reference
Python SDK enrich_span() and enrich_session()