Span Data Models ================ .. note:: **Technical specification for HoneyHive span data structures** This document defines the exact data models and formats used for spans in the HoneyHive SDK, which follow OpenTelemetry specifications. Spans represent units of work in a distributed trace, providing detailed timing and context information for operations in your LLM application. Core Span Model --------------- .. py:class:: Span The primary span data structure based on OpenTelemetry standards. .. py:attribute:: span_id :type: str Unique identifier for this span. **Format**: 16-character hexadecimal string (8 bytes) **Example**: ``"a1b2c3d4e5f6g7h8"`` **Required**: Auto-generated by SDK .. py:attribute:: trace_id :type: str Unique identifier for the entire trace. **Format**: 32-character hexadecimal string (16 bytes) **Example**: ``"1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p"`` **Required**: Auto-generated by SDK .. py:attribute:: parent_span_id :type: Optional[str] Parent span identifier for nested operations. **Format**: 16-character hexadecimal string (8 bytes) **Example**: ``"b2c3d4e5f6g7h8i9"`` **Required**: No (None for root spans) .. py:attribute:: operation_name :type: str Name of the operation represented by this span. **Format**: Descriptive string, typically kebab-case **Example**: ``"llm-chat-completion"`` **Required**: Yes .. py:attribute:: start_time :type: int Span start time in nanoseconds since Unix epoch. **Format**: 64-bit integer (nanoseconds) **Example**: ``1642253445123456789`` **Required**: Auto-generated by SDK .. py:attribute:: end_time :type: Optional[int] Span end time in nanoseconds since Unix epoch. **Format**: 64-bit integer (nanoseconds) **Example**: ``1642253447654321987`` **Required**: Auto-generated when span ends .. py:attribute:: duration_ns :type: Optional[int] Span duration in nanoseconds. **Calculation**: ``end_time - start_time`` **Example**: ``2530865198`` **Required**: Auto-calculated by SDK .. py:attribute:: status :type: SpanStatus Span completion status. **Structure**: .. code-block:: json { "code": "OK", "message": "Operation completed successfully" } **Status Codes**: - ``"UNSET"`` - Default status - ``"OK"`` - Operation completed successfully - ``"ERROR"`` - Operation failed **Required**: Auto-determined by SDK .. py:attribute:: attributes :type: Dict[str, Union[str, int, float, bool]] Key-value pairs providing additional context. **Restrictions**: - Keys must be strings - Values must be primitives (string, int, float, bool) - Arrays of primitives are also supported **Example**: .. code-block:: json { "llm.model": "gpt-3.5-turbo", "llm.provider": "openai", "llm.temperature": 0.7, "llm.max_tokens": 150, "llm.streaming": false, "http.status_code": 200, "operation.timeout_ms": 30000 } **Required**: No .. py:attribute:: events :type: List[SpanEvent] Timestamped events that occurred during the span. **Structure**: List of :py:class:`SpanEvent` objects **Required**: No .. py:attribute:: links :type: List[SpanLink] Links to other spans (causally related). **Structure**: List of :py:class:`SpanLink` objects **Required**: No .. py:attribute:: resource :type: Resource Resource information (service, instance, etc.). **Structure**: :py:class:`Resource` object **Required**: Yes (auto-populated by SDK) .. py:attribute:: instrumentation_scope :type: InstrumentationScope Information about the instrumentation library. **Structure**: :py:class:`InstrumentationScope` object **Required**: Yes (auto-populated by SDK) Span Event Model ---------------- .. py:class:: SpanEvent Represents a timestamped event within a span. .. py:attribute:: name :type: str Event name. **Example**: ``"request_started"``, ``"cache_miss"``, ``"retry_attempt"`` **Required**: Yes .. py:attribute:: timestamp :type: int Event timestamp in nanoseconds since Unix epoch. **Format**: 64-bit integer (nanoseconds) **Example**: ``1642253445500000000`` **Required**: Yes .. py:attribute:: attributes :type: Optional[Dict[str, Union[str, int, float, bool]]] Event-specific attributes. **Example**: .. code-block:: json { "retry.attempt": 2, "retry.reason": "rate_limit", "retry.delay_ms": 1000 } **Required**: No **Example Span Event**: .. code-block:: json { "name": "llm_response_received", "timestamp": 1642253446123456789, "attributes": { "response.token_count": 42, "response.finish_reason": "stop", "response.cached": false } } Span Link Model --------------- .. py:class:: SpanLink Links this span to another span (potentially in a different trace). .. py:attribute:: trace_id :type: str Trace ID of the linked span. **Format**: 32-character hexadecimal string **Required**: Yes .. py:attribute:: span_id :type: str Span ID of the linked span. **Format**: 16-character hexadecimal string **Required**: Yes .. py:attribute:: attributes :type: Optional[Dict[str, Union[str, int, float, bool]]] Link-specific attributes. **Example**: .. code-block:: json { "link.type": "follows_from", "link.description": "Async callback" } **Required**: No Resource Model -------------- .. py:class:: Resource Represents the entity producing telemetry. .. py:attribute:: attributes :type: Dict[str, Union[str, int, float, bool]] Resource attributes following OpenTelemetry semantic conventions. **Common Attributes**: .. code-block:: json { "service.name": "my-llm-app", "service.version": "1.2.0", "service.instance.id": "instance-001", "deployment.environment": "production", "host.name": "server-01", "process.pid": 12345, "telemetry.sdk.name": "honeyhive", "telemetry.sdk.version": "0.1.0", "telemetry.sdk.language": "python" } **Required**: Yes (auto-populated by SDK) Instrumentation Scope Model --------------------------- .. py:class:: InstrumentationScope Information about the instrumentation library that created the span. .. py:attribute:: name :type: str Name of the instrumentation library. **Example**: ``"honeyhive-python"`` **Required**: Yes .. py:attribute:: version :type: Optional[str] Version of the instrumentation library. **Example**: ``"0.1.0"`` **Required**: No .. py:attribute:: schema_url :type: Optional[str] Schema URL for semantic conventions. **Example**: ``"https://opentelemetry.io/schemas/1.21.0"`` **Required**: No HoneyHive Span Extensions ------------------------- In addition to standard OpenTelemetry fields, HoneyHive adds specialized attributes for LLM observability: **LLM Attributes**: .. code-block:: json { "llm.provider": "openai", "llm.model": "gpt-3.5-turbo-0613", "llm.temperature": 0.7, "llm.max_tokens": 150, "llm.top_p": 1.0, "llm.frequency_penalty": 0.0, "llm.presence_penalty": 0.0, "llm.streaming": false, "llm.function_call": "auto", "llm.tools_count": 3 } **Token Usage Attributes**: .. code-block:: json { "llm.usage.prompt_tokens": 50, "llm.usage.completion_tokens": 75, "llm.usage.total_tokens": 125, "llm.usage.cache_hit_tokens": 20, "llm.usage.cache_miss_tokens": 30 } **Cost Attributes**: .. code-block:: json { "llm.cost.prompt_cost_usd": 0.0001, "llm.cost.completion_cost_usd": 0.00015, "llm.cost.total_cost_usd": 0.00025, "llm.cost.currency": "USD" } **Request/Response Attributes**: .. code-block:: json { "llm.request.type": "chat", "llm.request.message_count": 3, "llm.request.system_message": true, "llm.response.finish_reason": "stop", "llm.response.choice_count": 1, "llm.response.logprobs": false } **Error Attributes**: .. code-block:: json { "error.type": "RateLimitError", "error.message": "Rate limit exceeded", "error.code": "rate_limit_exceeded", "error.retry_after_s": 60, "error.request_id": "req_abc123" } **Performance Attributes**: .. code-block:: json { "performance.latency_ms": 1250.5, "performance.queue_time_ms": 45.2, "performance.processing_time_ms": 1205.3, "performance.tokens_per_second": 60.8, "performance.cache_hit_rate": 0.75 } **User/Session Attributes**: .. code-block:: json { "user.id": "user_12345", "user.tier": "premium", "session.id": "session_abcdef", "session.turn": 3, "conversation.id": "conv_xyz789" } Span Context Model ------------------ .. py:class:: SpanContext Represents the portion of a span that must be propagated to child spans. .. py:attribute:: trace_id :type: str Trace identifier. **Format**: 32-character hexadecimal string **Required**: Yes .. py:attribute:: span_id :type: str Span identifier. **Format**: 16-character hexadecimal string **Required**: Yes .. py:attribute:: trace_flags :type: int Trace flags (typically 0x01 for sampled). **Values**: 8-bit integer **Required**: Yes .. py:attribute:: trace_state :type: Optional[str] Vendor-specific trace state. **Format**: Comma-separated key-value pairs **Example**: ``"honeyhive=abc123,vendor2=xyz789"`` **Required**: No .. py:attribute:: is_remote :type: bool Whether this context was propagated from a remote parent. **Required**: Yes Complete Span Example --------------------- **Full LLM Span**: .. code-block:: json { "span_id": "a1b2c3d4e5f6g7h8", "trace_id": "1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p", "parent_span_id": "b2c3d4e5f6g7h8i9", "operation_name": "openai-chat-completion", "start_time": 1642253445123456789, "end_time": 1642253447654321987, "duration_ns": 2530865198, "status": { "code": "OK", "message": "Request completed successfully" }, "attributes": { "llm.provider": "openai", "llm.model": "gpt-3.5-turbo", "llm.temperature": 0.7, "llm.max_tokens": 150, "llm.usage.prompt_tokens": 50, "llm.usage.completion_tokens": 75, "llm.usage.total_tokens": 125, "llm.cost.total_cost_usd": 0.00025, "http.method": "POST", "http.url": "https://api.openai.com/v1/chat/completions", "http.status_code": 200, "user.id": "user_12345", "session.id": "session_abcdef" }, "events": [ { "name": "request_started", "timestamp": 1642253445123456789, "attributes": { "request.size_bytes": 1024 } }, { "name": "response_received", "timestamp": 1642253447600000000, "attributes": { "response.size_bytes": 2048, "response.cached": false } } ], "links": [], "resource": { "attributes": { "service.name": "my-llm-app", "service.version": "1.2.0", "deployment.environment": "production", "telemetry.sdk.name": "honeyhive", "telemetry.sdk.version": "0.1.0" } }, "instrumentation_scope": { "name": "honeyhive-python", "version": "0.1.0", "schema_url": "https://opentelemetry.io/schemas/1.21.0" } } Trace Hierarchy Example ----------------------- **Parent-Child Span Relationship**: .. code-block:: json { "trace_id": "1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p", "spans": [ { "span_id": "root00000000", "parent_span_id": null, "operation_name": "rag-pipeline", "attributes": { "pipeline.type": "rag", "pipeline.version": "v2" } }, { "span_id": "search000000", "parent_span_id": "root00000000", "operation_name": "vector-search", "attributes": { "search.query": "What is machine learning?", "search.top_k": 5, "search.similarity_threshold": 0.8 } }, { "span_id": "llm000000000", "parent_span_id": "root00000000", "operation_name": "llm-generation", "attributes": { "llm.provider": "openai", "llm.model": "gpt-3.5-turbo", "llm.context_length": 4096 } } ] } Span Sampling ------------- **Sampling Decision**: Spans can be sampled based on various criteria: .. code-block:: json { "trace_flags": 1, "sampling": { "decision": "RECORD_AND_SAMPLE", "probability": 0.1, "reason": "TraceIdRatioBasedSampler", "attributes": { "sampling.rule": "high_value_users", "sampling.tier": "premium" } } } **Sampling Strategies**: - **Rate-based**: Sample a percentage of traces - **Adaptive**: Adjust sampling based on traffic volume - **Rule-based**: Sample based on attributes (user tier, error status) - **Tail-based**: Sample entire traces based on downstream criteria Span Export Format ------------------ **OTLP Format** (OpenTelemetry Protocol): The SDK supports both Protobuf (default) and JSON formats for OTLP export. Set the ``HH_OTLP_PROTOCOL`` environment variable to ``http/json`` to use JSON format, or ``http/protobuf`` (default) for Protobuf format. .. code-block:: json { "resource_spans": [ { "resource": { "attributes": [ {"key": "service.name", "value": {"string_value": "my-service"}} ] }, "scope_spans": [ { "scope": { "name": "honeyhive-python", "version": "0.1.0" }, "spans": [ { "trace_id": "base64EncodedTraceId", "span_id": "base64EncodedSpanId", "name": "operation-name", "start_time_unix_nano": 1642253445123456789, "end_time_unix_nano": 1642253447654321987, "attributes": [ {"key": "llm.model", "value": {"string_value": "gpt-3.5-turbo"}} ] } ] } ] } ] } **HoneyHive Format** (Enhanced): .. code-block:: json { "spans": [ { "span_id": "a1b2c3d4e5f6g7h8", "trace_id": "1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p", "operation_name": "llm-call", "honeyhive": { "project": "my-project", "session_id": "session_abc", "event_id": "event_123", "evaluation_scores": { "relevance": 0.85, "accuracy": 0.92 } } } ] } Best Practices -------------- **Span Design Guidelines**: 1. **Meaningful Names**: Use descriptive operation names that clearly indicate what work is being done 2. **Appropriate Granularity**: Create spans for significant operations, avoid over-instrumentation 3. **Rich Attributes**: Add relevant attributes that aid in debugging and analysis 4. **Error Handling**: Always set error status and attributes when operations fail 5. **Resource Attribution**: Include user, session, and business context 6. **Performance Metrics**: Capture relevant timing and throughput metrics **Attribute Naming**: Follow OpenTelemetry semantic conventions: - Use lowercase with underscores: ``llm.model``, ``http.status_code`` - Namespace related attributes: ``llm.*``, ``db.*``, ``http.*`` - Use consistent units: ``_ms`` for milliseconds, ``_bytes`` for bytes - Avoid sensitive data: Don't include API keys, passwords, PII **Performance Considerations**: 1. **Attribute Limits**: Be mindful of attribute count and size limits 2. **Event Usage**: Use events sparingly for significant occurrences only 3. **Link Usage**: Use links judiciously to avoid circular references 4. **Sampling**: Implement appropriate sampling to control data volume See Also -------- - :doc:`events` - Event data models and formats - :doc:`evaluations` - Evaluation data structures - :doc:`../api/tracer` - HoneyHiveTracer API for creating spans - :doc:`../configuration/environment-vars` - Span configuration options