Understand OpenTelemetry and OpenInference, configure span processors, resource attributes, and multi-project routing
Take full control of OpenTelemetry. The getting started pages cover register() and OpenInference integrations — this page is for when you need more: batch processing for production, routing spans to multiple projects, or configuring resource attributes directly via the OpenTelemetry SDK.
OpenInference provides auto-instrumentors for popular frameworks. Install the package for your provider and attach it once — .instrument() in Python, registerInstrumentations({...}) / package-specific setup in JS/TS, or option.WithMiddleware(...) on the SDK client in Go — and every call is traced automatically.
Register sets the required openinference.project.name resource attribute, installs otel.SetTracerProvider, defaults to a BatchSpanProcessor, and falls back to environment variables when the matching Options fields are unset:
Field
Default
Description
SpaceID
$ARIZE_SPACE_ID
Required.
APIKey
$ARIZE_API_KEY
Required.
ProjectName
$ARIZE_PROJECT_NAME or "default"
Sets the openinference.project.name resource attribute.
Endpoint
$ARIZE_COLLECTOR_ENDPOINT or otlp.arize.com
Use arizeotel.EndpointArizeEurope for EU spaces.
ExtraHeaders
none
Merged into OTLP request headers alongside the required space_id / api_key.
ExtraResourceAttributes
none
Appended to the OTel Resource.
Insecure
false
Disables TLS — only for on-prem / local collectors.
SimpleProcessor
false (batched)
Synchronous export. Useful for tests and short CLIs.
SkipSetGlobal
false
Skip otel.SetTracerProvider. Set if you manage the global yourself.
Need multiple exporters (Arize + a local console for debugging, or Arize + Datadog)? Drop to raw sdktrace.NewTracerProvider:
import ( "context" "os" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace")ctx := context.Background()arizeExporter, _ := otlptracehttp.New(ctx, otlptracehttp.WithEndpoint("otlp.arize.com"), otlptracehttp.WithHeaders(map[string]string{ "space_id": os.Getenv("ARIZE_SPACE_ID"), "api_key": os.Getenv("ARIZE_API_KEY"), }),)consoleExporter, _ := stdouttrace.New(stdouttrace.WithPrettyPrint())// openinference.project.name is required so the collector can route spans to the right project.res, _ := resource.New(ctx, resource.WithAttributes( attribute.String("openinference.project.name", "your-project-name"), attribute.String("model.version", "v1"),))tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(arizeExporter), // production export to Arize sdktrace.WithBatcher(consoleExporter), // local debugging — drop in production sdktrace.WithResource(res),)otel.SetTracerProvider(tp)defer tp.Shutdown(ctx) // flushes batched spans before exit
Resource attributes describe the source of telemetry (service, model, environment). Set once on the TracerProvider.
Span attributes describe a single span. Set per-span in your code.
Span processors filter, batch, and perform operations on spans before export.
Project name resource attribute. The canonical OpenInference key is openinference.project.name — exposed as ResourceAttributes.PROJECT_NAME from openinference.semconv.resource in Python, SEMRESATTRS_PROJECT_NAME from @arizeai/openinference-semantic-conventions in JS/TS, and set automatically by arize-otel-go’s Options.ProjectName in Go. The Arize collector also accepts model_id as a legacy alias (shown in some older Python/JS examples on this page); both route spans to the same project.
OTLP auth headers. The Arize collector accepts both space_id / api_key (canonical, what arize-otel-go sends) and the arize-space-id / arize-api-key aliases shown in the older Python/JS examples. If you copy the raw-OTel Go snippet below into a stack that already uses the arize- prefixed form, pick one and stay consistent.
The most important processor decision for production is which span processor to use:
To route traces from one application to multiple Arize spaces or projects, use register_with_routing from arize-otel:
pip install arize-otel
from arize.otel import register_with_routing, set_routing_context# Register once with a single API key — routing happens per-contexttracer_provider = register_with_routing( api_key="your-api-key",)# Route specific operations to a different space + projectwith set_routing_context(space_id="other-space-id", project_name="other-project"): # Spans created in this block are routed to "other-space-id" / "other-project" ...
register_with_routing uses ARIZE_API_KEY from your environment if api_key isn’t passed. Both space_id and project_name must be set inside set_routing_context — otherwise routing won’t be applied.Python-only today. For JS/TS or Go apps — or more complex routing (e.g., by span attribute) — route at the OTel Collector layer instead. See OTEL Collector deployment patterns.
If you operate a centralized OpenTelemetry Collector serving many teams or spaces, see the shared-collector pattern that forwards arize-space-id from inbound request metadata — avoids redeploying the collector each time a new space is added.