Because Phoenix is built on OpenTelemetry, you can run into situations where other OpenTelemetry traces unrelated to your LLM calls are logged into Phoenix. You can also run into cases where Phoenix traces are sent to other OTEL endpoints.
You have a few options to avoid these cases:
Filtering spans based on specific criteria
Selectively suppressing instrumentation on specific calls
Disable instrumentation on the offending package
Defining your own FilterProcessor
Filtering all Spans that meet a criteria
A good option if you want to keep both instrumentations running simultaneously is to define a custom ConditionalSpanProcessor. This custom processor can use conditions you define to selectively distribute spans.
This example uses a ConsoleSpanExporter as the second exporter alongside Phoenix. You could replace this with another exporter of a different kind.
from opentelemetry.sdk.trace.export import SpanExporter, SpanProcessor# Custom SpanProcessor that only exports spans based on a conditionclassConditionalSpanProcessor(SpanProcessor):def__init__(self,exporter: SpanExporter,condition:callable): self.exporter = exporter self.condition = conditiondefon_start(self,span,parent_context):passdefon_end(self,span):# Only export spans that meet the conditionif self.condition(span): self.exporter.export([span])defshutdown(self): self.exporter.shutdown()defforce_flush(self,timeout_millis=None): self.exporter.force_flush(timeout_millis)# Define conditions for sending spans to specific exportersdefconsole_condition(span):return"console"in span.name # Example: send to Console if "console" is in the span namedefphoenix_condition(span):# return "phoenix" in span.name # Example: send to Phoenix if "phoenix" is in the span namereturnnotconsole_condition(span)# Example: send to Phoenix if "console" is not in the span name
You can set your conditions to be related to any criteria on your spans.
With this defined, you can now create instances for each of your destinations:
import osfrom opentelemetry.sdk.trace.export import ConsoleSpanExporterfrom opentelemetry import trace as trace_apifrom opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporterfrom opentelemetry.sdk.trace import TracerProviderfrom dotenv import load_dotenvload_dotenv()from openinference.instrumentation.openai import OpenAIInstrumentordefinstrument():# Add Phoenix API Key to the headers for tracing and API access PHOENIX_API_KEY = os.getenv("PHOENIX_API_KEY") os.environ["PHOENIX_CLIENT_HEADERS"]=f"api_key={PHOENIX_API_KEY}" tracer_provider =TracerProvider()# Create the Console exporter console_exporter =ConsoleSpanExporter()# Add the Console exporter to the tracer provider tracer_provider.add_span_processor(ConditionalSpanProcessor(console_exporter, console_condition) )# Create the Phoenix exporter. Replace endpoint with your endpoint if self-hosting otlp_exporter =OTLPSpanExporter(endpoint="https://app.phoenix.arize.com/v1/traces")# Add the Phoenix exporter to the tracer provider tracer_provider.add_span_processor(ConditionalSpanProcessor(otlp_exporter, phoenix_condition) )# Set the tracer provider trace_api.set_tracer_provider(tracer_provider)# Auto-instrumentors can still be usedOpenAIInstrumentor().instrument(tracer_provider=tracer_provider, skip_dep_check=True)
From here, spans will be filtered based on the criteria you've set:
import openaidefrun_app():# Create a tracer tracer = trace_api.get_tracer(__name__)# Example of creating and exporting spanswith tracer.start_as_current_span("console-span"):print("This span will be exported to Console only.")# This request will only be exported to Phoenix client = openai.OpenAI() client.chat.completions.create(model="gpt-4o-mini", messages=[{"role": "user", "content": "Hello, world!"}])
Selectively suppress individual calls
If you instead want to selectively suppress instrumentation of individual calls, you can do so using the _SUPPRESS_INSTRUMENTATION_KEY:
from opentelemetry.context import _SUPPRESS_INSTRUMENTATION_KEY, attach, detach, set_value
token =attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))# your method call(s) that you want suppresseddetach(token)
Disabling Instrumentation
Certain libraries will automatically enable instrumentation if they detect the presence of the OTEL libraries. For example, google-cloud-bigquery displays this behavior.
If you simply want to suppress traces from one of these libraries, most libraries offer an option to suppress their traces.
For example, BigQuery traces can be surpressed with:
Phoenix does not automatically instrument any libraries unless you've called one of our auto-instrumentors. To disable tracing of one of those auto-instrumentors, see Disabling Instrumentation
Defining your own Filter Processor
If you've defined your own OTEL collector, you can instead set up app-wide criteria to block traces that meet certain criteria using a Filter Processor. This approach is more involved, as it requires defining your own OTEL span collector.