Skip to content

Arize & Phoenix Integration Guide

This document provides comprehensive guidance on integrating Graphite with Arize and Phoenix for distributed tracing and observability.

Table of Contents

Overview

Graphite integrates with OpenTelemetry to provide distributed tracing through multiple backends:

  • Arize: Production-grade monitoring and observability platform for AI applications
  • Phoenix: Local/remote tracing solution ideal for development and debugging
  • Auto: Automatic detection of available tracing endpoints
  • In-Memory: Testing mode without external dependencies

The integration is built on top of OpenTelemetry and automatically instruments: - OpenAI API calls - LLM interactions - Tool executions - Workflow orchestration - Node operations

Installation

Core Dependencies

Grafi includes the following observability dependencies by default:

dependencies = [
    "openinference-instrumentation-openai>=0.1.30",
    "arize-otel>=0.10.0",
    "arize-phoenix-otel>=0.13.1",
]

These are automatically installed when you install Grafi:

# Using pip
pip install grafi

# Using poetry
poetry add grafi

# Using uv
uv pip install grafi

Optional Development Dependencies

For local Phoenix tracing during development:

pip install arize-phoenix

Configuration

Docker Compose

To run Phoenix you can run it on your local machine via docker compose

version: '3.8'

services:

  phoenix:
    image: arizephoenix/phoenix:latest
    ports:
      - "6006:6006"
      - "4317:4317"

Environment Variables

Arize Configuration

Set these environment variables when using Arize:

# Required for Arize
export ARIZE_API_KEY="your-arize-api-key"
export ARIZE_SPACE_ID="your-space-id"
export ARIZE_PROJECT_NAME="your-project-name"

Phoenix Configuration

Set these environment variables to override default Phoenix settings:

# Optional - defaults to localhost:4317
export PHOENIX_ENDPOINT="localhost" # if using docker compose and ports are forwarded
export PHOENIX_PORT="4317" # This will override port settings in setup_tracing()

Setup Function Parameters

The setup_tracing() function accepts the following parameters:

def setup_tracing(
    tracing_options: TracingOptions = TracingOptions.AUTO,
    collector_endpoint: str = "localhost",
    collector_port: int = 4317,
    project_name: str = "grafi-trace",
) -> Tracer:
  • tracing_options: Backend to use (ARIZE, PHOENIX, AUTO, IN_MEMORY)
  • collector_endpoint: Hostname of the collector (default: "localhost")
  • collector_port: Port number of the collector (default: 4317)
  • project_name: Name for the tracing project (default: "grafi-trace")

Tracing Options

Grafi provides four tracing backend options through the TracingOptions enum:

1. ARIZE - Production Monitoring

Use Arize for production environments with enterprise-grade observability:

from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

tracing = setup_tracing(
    tracing_options=TracingOptions.ARIZE,
    collector_endpoint="https://otlp.arize.com/v1",
    project_name="my-dev-project",
)

When to use: - Production deployments - Need for team collaboration and sharing - Require advanced analytics and monitoring - Enterprise compliance requirements

2. PHOENIX - Local/Remote Development

Use Phoenix for development and debugging:

from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

tracer = setup_tracing(
    tracing_options=TracingOptions.PHOENIX,
    collector_endpoint="localhost",
    collector_port=4317,
    project_name="my-dev-project"
)

When to use: - Local development and debugging - Quick iteration and testing - Learning and experimentation - Running Phoenix locally or on a remote server

3. AUTO - Automatic Detection

Let Grafi automatically detect available tracing endpoints:

from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

tracer = setup_tracing(
    tracing_options=TracingOptions.AUTO,
    collector_endpoint="localhost",
    collector_port=4317
)

Detection priority: 1. Default collector endpoint (if available) 2. Phoenix endpoint from environment variables 3. Falls back to in-memory tracing

When to use: - Development environments with optional Phoenix - CI/CD pipelines - Flexible deployment scenarios

4. IN_MEMORY - Testing

Use in-memory tracing for tests and offline work:

tracer = setup_tracing(tracing_options=TracingOptions.IN_MEMORY)

When to use: - Unit and integration tests - CI/CD without external dependencies - Offline development - Minimal overhead scenarios

Usage Examples

Example 1: Basic Setup with AUTO Detection

from grafi.common.containers.container import container
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

# Register the tracer with auto-detection
tracer = setup_tracing(tracing_options=TracingOptions.AUTO)
container.register_tracer(tracer)

# Your assistant code here

Example 2: Production Setup with Arize

from grafi.common.containers.container import container
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

# Ensure environment variables are set
# ARIZE_API_KEY, ARIZE_SPACE_ID, ARIZE_PROJECT_NAME

tracer = setup_tracing(
    tracing_options=TracingOptions.ARIZE,
    collector_endpoint="https://otlp.arize.com/v1",
    project_name="production-assistant"
)
container.register_tracer(tracer)

# Your assistant code here

Example 3: Development with Local Phoenix

First, start Phoenix locally:

# Install Phoenix if not already installed
pip install arize-phoenix

# Start Phoenix server
docker compose up

Then in your code:

from grafi.common.containers.container import container
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

tracer = setup_tracing(
    tracing_options=TracingOptions.PHOENIX,
    collector_endpoint="localhost",
    collector_port=4317,
    project_name="my-dev-assistant"
)
container.register_tracer(tracer)

# Your assistant code here

Visit http://localhost:6006 to view the Phoenix UI.

Example 4: Testing with In-Memory Tracing

from grafi.common.containers.container import container
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

# Use in-memory tracing for tests
tracer = setup_tracing(tracing_options=TracingOptions.IN_MEMORY)
container.register_tracer(tracer)

# Your test code here

Example 5: Remote Phoenix Instance

from grafi.common.containers.container import container
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

tracer = setup_tracing(
    # If you've set up the ENV Variables then some arguments can be skipped
    tracing_options=TracingOptions.PHOENIX,
    project_name="shared-dev-project"
)
container.register_tracer(tracer)

Example 6: Complete Assistant with Tracing

import os
import uuid
import asyncio
from grafi.common.containers.container import container
from grafi.common.events.topic_events.publish_to_topic_event import PublishToTopicEvent
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing
from grafi.common.models.async_result import async_func_wrapper
from grafi.common.models.invoke_context import InvokeContext
from grafi.common.models.message import Message
from grafi.assistants.assistant_base import AssistantBase

# Setup tracing
tracer = setup_tracing(tracing_options=TracingOptions.AUTO)
container.register_tracer(tracer)

# Get event store
event_store = container.event_store

# Create your assistant
async def main():
    assistant = (
        # YourAssistant is an instance of type grafi.assistants.assistant
        # https://github.com/binome-dev/graphite/blob/main/grafi/assistants/assistant.py
        YourAssistant.builder()
        .name("MyAssistant")
        .api_key(os.getenv("OPENAI_API_KEY"))
        .build()
    )

    # Create invoke context
    invoke_context = InvokeContext(
        conversation_id="conversation_id",
        invoke_id=uuid.uuid4().hex,
        assistant_request_id=uuid.uuid4().hex,
    )

    # Invoke assistant
    input_data = PublishToTopicEvent(
        invoke_context=invoke_context,
        data=[Message(content="Hello!", role="user")]
    )

    output = await async_func_wrapper(
        assistant.invoke(input_data, is_sequential=True)
    )
    print(output)

asyncio.run(main())

Best Practices

1. Environment-Specific Configuration

Use different tracing backends for different environments:

import os
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

env = os.getenv("ENVIRONMENT", "development")

if env == "production":
    tracing_option = TracingOptions.ARIZE
    endpoint = "https://otlp.arize.com/v1"
elif env == "staging":
    tracing_option = TracingOptions.PHOENIX
    endpoint = "staging-phoenix.example.com"
elif env == "development":
    tracing_option = TracingOptions.AUTO
    endpoint = "localhost"
else:  # testing
    tracing_option = TracingOptions.IN_MEMORY
    endpoint = "localhost"

tracer = setup_tracing(
    tracing_options=tracing_option,
    collector_endpoint=endpoint,
    project_name=f"{env}-assistant"
)

2. Early Initialization

Set up tracing early in your application lifecycle, before creating assistants:

# Good: Setup tracing first
tracer = setup_tracing(tracing_options=TracingOptions.AUTO)
container.register_tracer(tracer)

# Then create assistants
assistant = MyAssistant.builder().build()

3. Project Naming Conventions

Use descriptive project names to organize traces:

tracer = setup_tracing(
    tracing_options=TracingOptions.PHOENIX,
    project_name=f"{app_name}-{environment}-{version}"
)

4. Secure Credential Management

Never hardcode API keys. Use environment variables or secret management:

import os

# Good: Use environment variables
os.environ["ARIZE_API_KEY"] = os.getenv("ARIZE_API_KEY")

# Bad: Never hardcode
# os.environ["ARIZE_API_KEY"] = "hardcoded-key"

5. Graceful Degradation with AUTO Mode

Use AUTO mode to gracefully degrade when tracing endpoints are unavailable:

# Will automatically fall back to in-memory if no endpoint available
tracer = setup_tracing(tracing_options=TracingOptions.AUTO)

6. Testing Isolation

Use IN_MEMORY mode in tests to avoid external dependencies:

import pytest
from grafi.common.instrumentations.tracing import TracingOptions, setup_tracing

@pytest.fixture(autouse=True)
def setup_test_tracing():
    tracer = setup_tracing(tracing_options=TracingOptions.IN_MEMORY)
    container.register_tracer(tracer)
    yield
    # Cleanup if needed

Troubleshooting

Issue: "Phoenix endpoint is not available"

Symptom: ValueError when using PHOENIX tracing option

Solution: 1. Ensure Phoenix is running:

 docker compose up
 nc -zv localhost 4317

 Connection to localhost (::1) 4317 port [tcp/*] succeeded!

 nc -zv localhost 6006

 Connection to localhost (::1) 6006 port [tcp/x11-6] succeeded!

  1. Check the endpoint and port are correct:
tracer = setup_tracing(
    tracing_options=TracingOptions.PHOENIX,
    collector_endpoint="localhost",
    collector_port=4317
)
  1. Use AUTO mode for graceful fallback:
tracer = setup_tracing(tracing_options=TracingOptions.AUTO)

Issue: Arize traces not appearing

Symptom: No traces visible in Arize dashboard

Solution: 1. Verify environment variables are set:

import os
print(os.getenv("ARIZE_API_KEY"))
print(os.getenv("ARIZE_SPACE_ID"))
print(os.getenv("ARIZE_PROJECT_NAME"))

  1. Check the collector endpoint:

    tracer = setup_tracing(
        tracing_options=TracingOptions.ARIZE,
        collector_endpoint="https://otlp.arize.com/v1"
    )
    

  2. Verify API key has proper permissions

Issue: Connection timeout with Phoenix

Symptom: Slow startup or timeout errors

Solution: 1. The endpoint check has a 0.1s timeout, which is normal 2. Use AUTO mode to automatically fall back:

tracer = setup_tracing(tracing_options=TracingOptions.AUTO)

  1. For PHOENIX mode, ensure the endpoint is reachable:
    nc -zv localhost 4317
    

Issue: OpenAI instrumentation not working

Symptom: OpenAI calls not showing in traces

Solution: 1. Ensure OpenAI is instrumented (done automatically by setup_tracing) 2. Verify tracer is registered before creating assistants:

container.register_tracer(tracer)  # Must be before assistant creation

Issue: Traces showing in wrong project

Symptom: Traces appear in unexpected project

Solution: Specify project name explicitly:

tracer = setup_tracing(
    tracing_options=TracingOptions.PHOENIX,
    project_name="my-specific-project"
)

Debug Logging

Enable debug logging to troubleshoot tracing issues:

from loguru import logger
import sys

logger.remove()
logger.add(sys.stderr, level="DEBUG")

# Now setup tracing
tracer = setup_tracing(tracing_options=TracingOptions.AUTO)

Additional Resources

Arize Resources

Phoenix Resources

Grafi Resources

Support

For issues related to:

  • Graphite tracing integration: Open an issue on the Grafi repository
  • Arize platform: Contact Arize support or consult their documentation
  • Phoenix: Check the Phoenix GitHub issues or documentation