Architecture¶
OmniObserve follows a modular architecture with clear separation between interfaces and implementations.
Package Structure¶
omniobserve/
├── omniobserve.go # Main package with re-exports
├── omniobserve/ # Unified entry point with HTTP middleware
├── llmops/ # LLM observability interfaces
│ ├── llmops.go # Core interfaces (Provider, Tracer, Evaluator, etc.)
│ ├── trace.go # Trace and Span interfaces
│ ├── types.go # Data types (EvalInput, Dataset, Prompt, etc.)
│ ├── options.go # Functional options
│ ├── provider.go # Provider registration system
│ ├── errors.go # Error definitions
│ ├── metrics/ # Evaluation metrics (hallucination, relevance, etc.)
│ ├── langfuse/ # Langfuse provider adapter
│ └── slog/ # slog provider adapter
├── observops/ # App observability interfaces
│ ├── observops.go # Core interfaces (Provider, Meter, Tracer)
│ ├── options.go # Functional options
│ ├── otlp/ # OTLP provider (vendor-agnostic)
│ ├── datadog/ # Datadog provider
│ ├── newrelic/ # New Relic provider
│ └── dynatrace/ # Dynatrace provider
├── agentops/ # Agent operations monitoring
│ ├── ent/ # Ent ORM schemas
│ ├── middleware/ # HTTP middleware
│ └── postgres/ # PostgreSQL storage
├── semconv/ # OpenTelemetry semantic conventions
│ ├── agent/ # Agentic AI conventions (gen_ai.agent.*)
│ └── journey/ # User journey conventions (session.*, page.*, ui.*)
├── specs/ # Observability specifications
│ ├── classes/ # Class-based SLO management
│ ├── red/ # RED metrics (Rate, Errors, Duration)
│ ├── use/ # USE metrics (Utilization, Saturation, Errors)
│ ├── golden/ # 4 Golden Signals mapping
│ ├── openslo/ # OpenSLO SLI/SLO definitions
│ ├── otel/ # OTel semantic conventions
│ ├── recorder/ # Integration with observops.Provider
│ └── schema/ # JSON Schema generation
├── sloghandler/ # slog.Handler implementations
│ ├── dual.go # Local + remote handler
│ ├── fanout.go # Multi-handler fanout
│ └── trace.go # Trace context injection
├── integrations/ # Integrations with external libraries
│ ├── omnillm/ # OmniLLM observability hook
│ ├── sevaluation/ # Structured evaluation integration
│ └── observability/ # HTTP client/server middleware helpers
├── mlops/ # ML operations interfaces (experiments, model registry)
├── examples/ # Usage examples
│ └── evaluation/ # Metrics evaluation example
├── sdk/ # Provider-specific SDKs
│ └── langfuse/ # Langfuse Go SDK
└── typescript/ # TypeScript SDK
└── packages/core/ # @omniobserve/core - mirrors Go types and semconv
Provider Adapters¶
Provider adapters are distributed in two ways:
Embedded Adapters¶
Adapters included in omniobserve:
llmops/langfuse- Langfuse adapterllmops/slog- slog adapter for local development
Standalone SDK Adapters¶
Adapters in their own repositories:
github.com/agentplexus/go-opik/llmops- Opik adaptergithub.com/agentplexus/go-phoenix/llmops- Phoenix adapter
Core Interfaces¶
Provider Interface¶
The main interface that all observability backends implement:
type Provider interface {
Tracer // Trace/span operations
Evaluator // Evaluation and feedback
PromptManager // Prompt template management
DatasetManager // Test dataset management
ProjectManager // Project/workspace management
AnnotationManager // Span/trace annotations
io.Closer
Name() string
}
Tracer Interface¶
type Tracer interface {
StartTrace(ctx context.Context, name string, opts ...TraceOption) (context.Context, Trace, error)
StartSpan(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span, error)
TraceFromContext(ctx context.Context) (Trace, bool)
SpanFromContext(ctx context.Context) (Span, bool)
Flush(ctx context.Context) error
}
Evaluator Interface¶
type Evaluator interface {
AddFeedbackScore(ctx context.Context, traceID, spanID, name string, score float64, opts ...FeedbackOption) error
}
Provider Registration¶
Providers register themselves using the database/sql style pattern:
// In provider package init()
func init() {
llmops.Register("opik", &opikDriver{})
}
// In application code
import _ "github.com/agentplexus/go-opik/llmops"
provider, _ := llmops.Open("opik", llmops.WithAPIKey("..."))
Context Propagation¶
Traces and spans are propagated via context.Context:
// Trace stored in context
ctx, trace, _ := provider.StartTrace(ctx, "workflow")
// Spans automatically link to trace from context
ctx, span, _ := provider.StartSpan(ctx, "step")
// Nested spans link to parent span
ctx, childSpan, _ := provider.StartSpan(ctx, "nested")
Functional Options¶
Configuration uses the functional options pattern:
// Client options
provider, _ := llmops.Open("opik",
llmops.WithAPIKey("..."),
llmops.WithProjectName("my-project"),
llmops.WithTimeout(30 * time.Second),
)
// Trace options
ctx, trace, _ := provider.StartTrace(ctx, "workflow",
llmops.WithTraceInput(input),
llmops.WithTraceMetadata(metadata),
)
// Span options
ctx, span, _ := provider.StartSpan(ctx, "llm-call",
llmops.WithSpanType(llmops.SpanTypeLLM),
llmops.WithModel("gpt-4"),
)
Error Handling¶
The library provides typed errors for common conditions:
var (
ErrMissingAPIKey = errors.New("missing API key")
ErrProviderNotFound = errors.New("provider not found")
ErrTraceNotFound = errors.New("trace not found")
)
// Error checking
if errors.Is(err, llmops.ErrMissingAPIKey) {
// Handle missing API key
}
if llmops.IsNotFound(err) {
// Handle not found
}
if llmops.IsRateLimited(err) {
// Handle rate limiting
}
Direct SDK Access¶
For provider-specific features, use the underlying SDKs directly: