Freeplay <> OpenTelemetry
Getting started with OpenTelemetry Tracing in Freeplay
Building LLM applications with modern frameworks is great—until you need to understand what's actually happening under the hood. Traditional observability tools weren't built for the nuances of LLM interactions: token counts, model parameters, prompt templates, tool calls, and multi-step agent workflows.
That's where OpenTelemetry (OTel) comes in. By integrating Freeplay with OTel, you get purpose-built LLM observability that works with any framework or orchestration approach. Whether you're using Langgraph, building custom agents, or mixing frameworks, Freeplay captures what matters—automatically.
Why OTel + Freeplay?
- Framework flexibility: Your team uses Langgraph. Another team built custom agents. A third is evaluating Google ADK. With OTel, one integration supports all of them.
- LLM-native insights: We automatically capture model parameters, token counts, tool schemas, and prompt templates—the data you actually need to improve your AI applications.
- No architectural changes: Freeplay observes your orchestration logic without becoming part of it. Your code stays clean, your flexibility stays intact.
- Built on standards: OpenInference semantic conventions mean your instrumentation is portable and future-proof.
Freeplay focuses on LLM observability
We only record traces and spans containing meaningful LLM information per OpenInference semantic conventions—not general application telemetry.
Recommended approach:
- Use OpenInference instrumentation libraries when available (easiest option)
- Follow OpenInference semantic conventions for custom instrumentation
- For advanced control, use our OTel-compliant API directly
If your framework lacks an OpenInference library, you can still record data using standard OpenInference attributes like
input.value
,output.value
, andgen_ai.request.model
. See the supported attributes reference below.
Getting Started
Step 1: Install dependencies
pip install freeplay opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp
Step 2: Configure the OTel exporter
Set up Freeplay as your OTel span processing endpoint:
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk import trace as trace_sdk
import os
freeplay_api_url = "https://app.freeplay.ai/api/v2"
exporter = OTLPSpanExporter(
endpoint=f"{freeplay_api_url}/v0/otel/v1/traces",
headers={
"Authorization": f"Bearer {os.environ['FREEPLAY_API_KEY']}",
"X-Freeplay-Project-Id": os.environ["FREEPLAY_PROJECT_ID"],
},
)
tracer_provider = trace_sdk.TracerProvider()
tracer_provider.add_span_processor(SimpleSpanProcessor(exporter))
Getting your credentials:
- API Key: Freeplay Settings → API Access
- Project ID: Found in your project settings
Step 3: Instrument your application
We recommend using OpenInference instrumentation libraries when available. For example, with Google ADK:
from google.adk.instrumentation import GoogleADKInstrumentor
GoogleADKInstrumentor().instrument(tracer_provider=tracer_provider)
That's it! Your LLM interactions are now being captured and sent to Freeplay.
Step 4: Enable debugging (optional but recommended)
During development, print spans to your console for easier debugging:
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
tracer_provider.add_span_processor(
SimpleSpanProcessor(ConsoleSpanExporter())
)
Framework examples
Langgraph/Langchain
Custom instrumentation
If you're building with a framework that doesn't have an OpenInference instrumentation library, you can manually instrument your code following OpenInference conventions:
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("llm_call") as span:
# Set OpenInference attributes
span.set_attribute("openinference.span.kind", "LLM")
span.set_attribute("gen_ai.request.model", "gpt-4")
span.set_attribute("input.value", user_query)
# Make your LLM call
response = your_llm_call(user_query)
# Record output and token usage
span.set_attribute("output.value", response)
span.set_attribute("gen_ai.usage.input_tokens", token_count.input)
span.set_attribute("gen_ai.usage.output_tokens", token_count.output)
Key concepts
Span types
Freeplay processes different span types based on openinference.span.kind
:
- LLM: Direct LLM API calls with prompts, completions, and token usage
- AGENT: Higher-level agentic workflows with decision-making
- CHAIN: Sequential operations or pipelines
- TOOL: External tool or function calls
Set the appropriate span kind to ensure Freeplay correctly interprets your traces.
Sessions and traces
Use session and trace identifiers to organize related interactions:
# Link multiple traces to the same conversation session
span.set_attribute("session.id", session_id)
# Or use Freeplay-specific attributes (takes precedence)
span.set_attribute("freeplay.session.id", session_id)
# Name your agent for better organization
span.set_attribute("agent.name", "customer_support_agent")
This enables you to track multi-turn conversations and group related agent runs in Freeplay's observability UI.
Environment tagging
Tag traces with your deployment environment to separate production from development data:
span.set_attribute("freeplay.environment", "production")
# or "staging", "development", etc.
Supported attributes reference
OpenInference attributes
Freeplay maps OpenInference attributes to internal fields for consistent observability. These are the standard attributes you should use when instrumenting your LLM applications:
OTEL Attribute | Freeplay Field | Payload Type | Notes |
---|---|---|---|
openinference.span.kind | N/A | RecordPayload | Determines span type (LLM, AGENT, CHAIN, TOOL) |
gen_ai.request.model | completion.model_name | RecordPayload | LLM model name |
llm.model_name | completion.model_name | RecordPayload | Alternative LLM model name |
gen_ai.usage.input_tokens | completion.token_counts.prompt_token_count | RecordPayload | Input token count |
llm.token_count.prompt | completion.token_counts.prompt_token_count | RecordPayload | Alternative input token count |
gen_ai.usage.output_tokens | completion.token_counts.return_token_count | RecordPayload | Output token count |
llm.token_count.completion | completion.token_counts.return_token_count | RecordPayload | Alternative output token count |
llm.provider | completion.provider_name | RecordPayload | LLM provider (openai, anthropic, google) |
gen_ai.system | completion.provider_name | RecordPayload | Alternative provider identifier |
llm.input_messages.* | completion.api_messages | RecordPayload | Input messages (flattened array format) |
llm.output_messages.* | completion.api_messages | RecordPayload | Output messages (flattened array format) |
llm.tools.* | completion.tool_schema | RecordPayload | Tool/function definitions |
llm.prompt_template.variables | completion.inputs | RecordPayload | Variables applied to template (merged into inputs) |
llm.invocation_parameters | completion.llm_parameters | RecordPayload | Parameters used during LLM invocation (JSON) |
input.value | trace.input | TracePayload | Trace input data |
output.value | trace.output | TracePayload | Trace output data |
tool.name | trace.name | TracePayload | Tool span name |
agent.name | trace.agent_name | TracePayload | Agent span name |
session.id | completion.session_id | RecordPayload | Session identifier |
session.id | trace.session_id | TracePayload | Session identifier |
Freeplay-specific attributes
Enhance your traces with Freeplay-specific metadata for tighter integration with Freeplay features:
OTEL Attribute | Freeplay Field | Payload Type | Notes |
---|---|---|---|
freeplay.session.id | completion.session_id | RecordPayload | Freeplay session ID (takes precedence over session.id ) |
freeplay.session.id | trace.session_id | TracePayload | Freeplay session ID (takes precedence over session.id ) |
freeplay.environment | completion.tag | RecordPayload | Environment tag (e.g., "production", "staging") |
freeplay.prompt_template.id | completion.prompt_template_id | RecordPayload | Link to Freeplay prompt template |
freeplay.prompt_template.version.id | completion.prompt_template_version_id | RecordPayload | Specific prompt template version |
freeplay.test_run.id | completion.test_run_id | RecordPayload | Associate with test run |
freeplay.test_case.id | completion.test_case_id | RecordPayload | Associate with specific test case |
freeplay.input_variables | completion.inputs | RecordPayload | Input variables (JSON) |
freeplay.metadata.* | completion.custom_metadata | RecordPayload | Custom metadata (flattened dict format) |
freeplay.eval_results.* | completion.eval_results | RecordPayload | Evaluation results (flattened dict format) |
Next steps
Once you've integrated OTel with Freeplay, you can:
- View traces in the Freeplay observability dashboard
- Run evaluations on your logged interactions to measure quality
- Build datasets from production traces for systematic testing
- Monitor performance across different model versions and configurations
- Track costs with automatic token usage and cost calculations
Additional resources
Updated about 17 hours ago