Tracer Architecture Overview
Overview
The HoneyHive SDK features a completely rewritten modular tracer architecture that provides enhanced maintainability, testability, and extensibility while maintaining 100% backwards compatibility.
Architecture Principles
The new architecture is built on four key principles:
Modular Design: Functionality separated into focused, single-responsibility modules
Mixin Composition: Dynamic inheritance using Python mixins for flexible feature combination
Graceful Degradation: Robust error handling that never crashes the host application
Backwards Compatibility: All existing code continues to work unchanged
%%{init: {'theme':'base', 'themeVariables': {'primaryColor': '#4F81BD', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#ffffff', 'lineColor': '#ffffff', 'mainBkg': 'transparent', 'secondBkg': 'transparent', 'tertiaryColor': 'transparent', 'clusterBkg': 'transparent', 'clusterBorder': '#ffffff', 'edgeLabelBackground': 'transparent', 'background': 'transparent'}, 'flowchart': {'linkColor': '#ffffff', 'linkWidth': 2}}}%%
graph TB
subgraph "HoneyHiveTracer Composition"
HT[HoneyHiveTracer]
HT --> Base[HoneyHiveTracerBase]
HT --> Ops[TracerOperationsMixin]
HT --> Ctx[TracerContextMixin]
end
subgraph "Core Module"
Base --> Config[config_interface.py]
Base --> Context[context.py]
Ops --> Operations[operations.py]
end
subgraph "Infrastructure"
Base --> Env[environment.py]
Base --> Res[resources.py]
end
subgraph "Processing"
Ops --> OTLP[otlp_exporter.py]
Ops --> Span[span_processor.py]
Ops --> CtxProc[context.py]
end
subgraph "Integration"
Base --> Compat[compatibility.py]
Base --> Detect[detection.py]
Base --> Error[error_handling.py]
end
Module Structure
The tracer architecture is organized into 6 core modules with 35 total files:
Core Module (tracer/core/)
Purpose: Foundation classes and core tracer functionality
File |
Description |
|---|---|
|
|
|
|
|
|
|
|
|
Configuration interface abstractions |
Infrastructure Module (tracer/infra/)
Purpose: Environment detection and resource management
File |
Description |
|---|---|
|
Environment detection and validation |
|
Resource management and cleanup |
Instrumentation Module (tracer/instrumentation/)
Purpose: Decorators and span enrichment
File |
Description |
|---|---|
|
|
|
Span enrichment with context |
|
Instrumentation initialization |
Integration Module (tracer/integration/)
Purpose: Compatibility and provider integration
File |
Description |
|---|---|
|
Backwards compatibility layer |
|
Provider and instrumentor detection |
|
Error handling middleware |
|
HTTP instrumentation integration |
|
Span processor integration |
Lifecycle Module (tracer/lifecycle/)
Purpose: Tracer lifecycle management
File |
Description |
|---|---|
|
Core lifecycle operations |
|
Flush operations and batching |
|
Shutdown and cleanup |
Processing Module (tracer/processing/)
Purpose: Span and context processing
File |
Description |
|---|---|
|
Context injection and extraction |
|
OTLP exporter configuration (supports Protobuf and JSON formats) |
|
OTLP export profiles |
|
OTLP session management |
|
Custom span processor |
Utilities Module (tracer/utils/)
Purpose: Shared utility functions
File |
Description |
|---|---|
|
Event type definitions |
|
General utility functions |
|
Git integration utilities |
|
Context propagation utilities |
|
Session management utilities |
Mixin Composition Pattern
The HoneyHiveTracer class uses dynamic mixin composition to combine functionality:
class HoneyHiveTracer(HoneyHiveTracerBase, TracerOperationsMixin, TracerContextMixin):
"""Main tracer class composed from multiple mixins."""
# Combines:
# - HoneyHiveTracerBase: Core initialization and configuration
# - TracerOperationsMixin: Span creation and event management
# - TracerContextMixin: Context and baggage management
Benefits of Mixin Composition
Single Responsibility: Each mixin handles one aspect of functionality
Easy Testing: Individual mixins can be tested in isolation
Flexible Extension: New mixins can be added without modifying existing code
Clean Interfaces: Clear separation of concerns
Multi-Instance Architecture
The modular design enables true multi-instance support:
# Multiple independent tracer instances
prod_tracer = HoneyHiveTracer(
config=TracerConfig(
api_key="hh_prod_key",
project="production-app",
source="production"
)
)
dev_tracer = HoneyHiveTracer(
config=TracerConfig(
api_key="hh_dev_key",
project="development-app",
source="development"
)
)
# Each tracer operates independently
with prod_tracer.start_span("prod-operation") as span:
# Production tracing
pass
with dev_tracer.start_span("dev-operation") as span:
# Development tracing
pass
Key Features
Independent Configuration: Each tracer has its own API key, project, settings
Isolated State: No shared state between tracer instances
Concurrent Operation: Thread-safe multi-instance operation
Resource Management: Independent lifecycle management
Advanced Multi-Instance Scenarios
Scenario 1: Environment-Based Routing
import os
from honeyhive import HoneyHiveTracer
from honeyhive.config.models import TracerConfig
# Environment-based tracer selection
if os.getenv("ENVIRONMENT") == "production":
tracer = HoneyHiveTracer(
config=TracerConfig(
api_key=os.getenv("HH_PROD_API_KEY"),
project="prod-llm-app",
source="production",
verbose=False
)
)
else:
tracer = HoneyHiveTracer(
config=TracerConfig(
api_key=os.getenv("HH_DEV_API_KEY"),
project="dev-llm-app",
source="development",
verbose=True
)
)
Scenario 2: Multi-Tenant Application
class MultiTenantTracer:
def __init__(self):
self.tracers = {}
def get_tracer(self, tenant_id: str) -> HoneyHiveTracer:
if tenant_id not in self.tracers:
self.tracers[tenant_id] = HoneyHiveTracer(
config=TracerConfig(
api_key=f"hh_tenant_{tenant_id}_key",
project=f"tenant-{tenant_id}",
source="multi-tenant-app"
)
)
return self.tracers[tenant_id]
# Usage
multi_tracer = MultiTenantTracer()
# Each tenant gets isolated tracing
tenant_a_tracer = multi_tracer.get_tracer("tenant_a")
tenant_b_tracer = multi_tracer.get_tracer("tenant_b")
Scenario 3: Workflow-Specific Tracers
# Different tracers for different workflows
data_pipeline_tracer = HoneyHiveTracer(
config=TracerConfig(
api_key="hh_data_key",
project="data-pipeline",
source="etl-service"
)
)
llm_inference_tracer = HoneyHiveTracer(
config=TracerConfig(
api_key="hh_inference_key",
project="llm-inference",
source="inference-service"
)
)
evaluation_tracer = HoneyHiveTracer(
config=TracerConfig(
api_key="hh_eval_key",
project="model-evaluation",
source="evaluation-service"
)
)
# Each workflow traces to its dedicated project
@data_pipeline_tracer.trace
def process_data():
pass
@llm_inference_tracer.trace
def generate_response():
pass
@evaluation_tracer.trace
def evaluate_model():
pass
Error Handling Strategy
The architecture implements graceful degradation throughout:
Graceful Degradation Principles
Never Crash Host Application: SDK errors never propagate to user code
Continue Operation: Failures in one component don’t stop others
Informative Logging: Clear error messages for debugging
Safe Defaults: Fallback to safe default values on errors
Implementation
try:
# Attempt operation
result = risky_operation()
except Exception as e:
logger.warning(f"Operation failed gracefully: {e}")
# Continue with safe default
result = safe_default_value()
Migration from Old Architecture
The modular architecture replaces the previous monolithic design:
Old Architecture (Replaced)
tracer/decorators.py→instrumentation/decorators.pytracer/error_handler.py→integration/error_handling.pytracer/http_instrumentation.py→integration/http.pytracer/otel_tracer.py→ Replaced by modularcore/componentstracer/processor_integrator.py→integration/processor.pytracer/provider_detector.py→integration/detection.pytracer/span_processor.py→processing/span_processor.py
Benefits of Migration
Improved Maintainability: Smaller, focused files are easier to maintain
Better Testing: Each module can be tested independently
Enhanced Extensibility: New features can be added without modifying existing code
Clearer Dependencies: Module boundaries make dependencies explicit
Performance Characteristics
The modular architecture maintains excellent performance:
Optimization Features
Lazy Loading: Modules loaded only when needed
Efficient Composition: Mixin composition has minimal overhead
Connection Pooling: Shared HTTP connection pools across modules
Batch Processing: Optimized span batching and export
Benchmarks
Initialization Time: < 10ms for full tracer setup
Span Creation: < 1ms per span with full enrichment
Memory Usage: ~5MB base memory footprint
Multi-Instance Overhead: < 2MB per additional tracer instance
Development and Testing
The modular architecture enhances development workflows:
Testing Strategy
Unit Tests: Each module has dedicated unit tests (37 new test files)
Integration Tests: End-to-end testing with real API calls (12 new test files)
Compatibility Tests: Backwards compatibility validation
Performance Tests: Benchmarking and regression testing
Development Benefits
Faster Development: Smaller modules are quicker to understand and modify
Easier Debugging: Clear module boundaries simplify troubleshooting
Parallel Development: Multiple developers can work on different modules
Code Reviews: Smaller, focused changes are easier to review
Future Extensibility
The modular design enables future enhancements:
Planned Extensions
Custom Processors: Plugin architecture for custom span processors
Provider Adapters: Adapters for additional OpenTelemetry providers
Metric Collection: Optional metrics collection modules
Advanced Sampling: Sophisticated sampling strategies
Extension Points
New Mixins: Add functionality through additional mixins
Module Plugins: Extend existing modules with plugin interfaces
Custom Processors: Implement custom processing logic
Provider Integrations: Add support for new OpenTelemetry providers
Backwards Compatibility Guarantee
Despite the complete architectural rewrite, 100% backwards compatibility is maintained:
Compatibility Features
Parameter Compatibility: All original parameters continue to work
Method Compatibility: All public methods maintain the same signatures
Behavior Compatibility: Existing functionality behaves identically
Import Compatibility: All imports continue to work unchanged
Migration Path
No migration required - existing code continues to work:
# This code works identically in both old and new architecture
tracer = HoneyHiveTracer(
api_key="hh_1234567890abcdef",
project="my-project",
verbose=True
)
@tracer.trace
def my_function():
return "Hello, World!"
See Also
Hybrid Configuration Approach - Configuration system details
HoneyHiveTracer API Reference - Complete tracer API reference
Migration Guide: v0.1.0+ Architecture - Migration guide with multi-instance examples
Architecture Overview - Overall SDK architecture