genai-otel-instrument 0.1.4.dev0__py3-none-any.whl → 0.1.7.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of genai-otel-instrument might be problematic. Click here for more details.
- genai_otel/__version__.py +2 -2
- genai_otel/config.py +19 -1
- genai_otel/cost_calculator.py +72 -6
- genai_otel/cost_enrichment_processor.py +175 -177
- genai_otel/gpu_metrics.py +50 -0
- genai_otel/instrumentors/base.py +228 -4
- genai_otel/instrumentors/cohere_instrumentor.py +140 -140
- genai_otel/instrumentors/huggingface_instrumentor.py +6 -2
- genai_otel/instrumentors/langchain_instrumentor.py +75 -75
- genai_otel/instrumentors/mistralai_instrumentor.py +17 -33
- genai_otel/llm_pricing.json +869 -869
- genai_otel/logging_config.py +45 -45
- genai_otel/py.typed +2 -2
- {genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/METADATA +250 -26
- {genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/RECORD +19 -19
- {genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/WHEEL +0 -0
- {genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/entry_points.txt +0 -0
- {genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/licenses/LICENSE +0 -0
- {genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/top_level.txt +0 -0
genai_otel/logging_config.py
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
"""Centralized logging configuration"""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
import os
|
|
5
|
-
import sys
|
|
6
|
-
from logging.handlers import RotatingFileHandler
|
|
7
|
-
from typing import Optional
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def setup_logging(
|
|
11
|
-
level: Optional[str] = None, log_dir: str = "logs", log_file_name: str = "genai_otel.log"
|
|
12
|
-
):
|
|
13
|
-
"""Configure logging for the library with configurable log level via environment variable
|
|
14
|
-
and log rotation.
|
|
15
|
-
"""
|
|
16
|
-
# Determine log level from environment variable or default to INFO
|
|
17
|
-
env_log_level = os.environ.get("GENAI_OTEL_LOG_LEVEL")
|
|
18
|
-
log_level_str = level or env_log_level or "INFO"
|
|
19
|
-
log_level = getattr(logging, log_level_str.upper(), logging.INFO)
|
|
20
|
-
|
|
21
|
-
# Create logs directory if it doesn't exist
|
|
22
|
-
os.makedirs(log_dir, exist_ok=True)
|
|
23
|
-
log_file_path = os.path.join(log_dir, log_file_name)
|
|
24
|
-
|
|
25
|
-
# Setup handlers
|
|
26
|
-
handlers = [logging.StreamHandler(sys.stdout)]
|
|
27
|
-
|
|
28
|
-
# Add rotating file handler
|
|
29
|
-
file_handler = RotatingFileHandler(log_file_path, maxBytes=10 * 1024 * 1024, backupCount=10)
|
|
30
|
-
handlers.append(file_handler)
|
|
31
|
-
|
|
32
|
-
# Set library logger
|
|
33
|
-
logger = logging.getLogger("genai_otel")
|
|
34
|
-
logger.setLevel(log_level)
|
|
35
|
-
|
|
36
|
-
# Clear existing handlers to prevent duplicates in case of multiple calls
|
|
37
|
-
if logger.handlers:
|
|
38
|
-
for handler in logger.handlers:
|
|
39
|
-
handler.close()
|
|
40
|
-
logger.handlers = []
|
|
41
|
-
|
|
42
|
-
for handler in handlers:
|
|
43
|
-
logger.addHandler(handler)
|
|
44
|
-
|
|
45
|
-
return logger
|
|
1
|
+
"""Centralized logging configuration"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from logging.handlers import RotatingFileHandler
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def setup_logging(
|
|
11
|
+
level: Optional[str] = None, log_dir: str = "logs", log_file_name: str = "genai_otel.log"
|
|
12
|
+
):
|
|
13
|
+
"""Configure logging for the library with configurable log level via environment variable
|
|
14
|
+
and log rotation.
|
|
15
|
+
"""
|
|
16
|
+
# Determine log level from environment variable or default to INFO
|
|
17
|
+
env_log_level = os.environ.get("GENAI_OTEL_LOG_LEVEL")
|
|
18
|
+
log_level_str = level or env_log_level or "INFO"
|
|
19
|
+
log_level = getattr(logging, log_level_str.upper(), logging.INFO)
|
|
20
|
+
|
|
21
|
+
# Create logs directory if it doesn't exist
|
|
22
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
23
|
+
log_file_path = os.path.join(log_dir, log_file_name)
|
|
24
|
+
|
|
25
|
+
# Setup handlers
|
|
26
|
+
handlers = [logging.StreamHandler(sys.stdout)]
|
|
27
|
+
|
|
28
|
+
# Add rotating file handler
|
|
29
|
+
file_handler = RotatingFileHandler(log_file_path, maxBytes=10 * 1024 * 1024, backupCount=10)
|
|
30
|
+
handlers.append(file_handler)
|
|
31
|
+
|
|
32
|
+
# Set library logger
|
|
33
|
+
logger = logging.getLogger("genai_otel")
|
|
34
|
+
logger.setLevel(log_level)
|
|
35
|
+
|
|
36
|
+
# Clear existing handlers to prevent duplicates in case of multiple calls
|
|
37
|
+
if logger.handlers:
|
|
38
|
+
for handler in logger.handlers:
|
|
39
|
+
handler.close()
|
|
40
|
+
logger.handlers = []
|
|
41
|
+
|
|
42
|
+
for handler in handlers:
|
|
43
|
+
logger.addHandler(handler)
|
|
44
|
+
|
|
45
|
+
return logger
|
genai_otel/py.typed
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
# Marker file for PEP 561
|
|
2
|
-
# This file indicates that the package supports type checking
|
|
1
|
+
# Marker file for PEP 561
|
|
2
|
+
# This file indicates that the package supports type checking
|
{genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: genai-otel-instrument
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7.dev0
|
|
4
4
|
Summary: Comprehensive OpenTelemetry auto-instrumentation for LLM/GenAI applications
|
|
5
5
|
Author-email: Kshitij Thakkar <kshitijthakkar@rocketmail.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -207,8 +207,9 @@ Production-ready OpenTelemetry instrumentation for GenAI/LLM applications with z
|
|
|
207
207
|
🚀 **Zero-Code Instrumentation** - Just install and set env vars
|
|
208
208
|
🤖 **15+ LLM Providers** - OpenAI, Anthropic, Google, AWS, Azure, and more
|
|
209
209
|
🔧 **MCP Tool Support** - Auto-instrument databases, APIs, caches, vector DBs
|
|
210
|
-
💰 **Cost Tracking** - Automatic cost calculation
|
|
211
|
-
|
|
210
|
+
💰 **Cost Tracking** - Automatic cost calculation for both streaming and non-streaming requests
|
|
211
|
+
⚡ **Streaming Support** - Full observability for streaming responses with TTFT/TBT metrics and cost tracking
|
|
212
|
+
🎮 **GPU Metrics** - Real-time GPU utilization, memory, temperature, power, and electricity cost tracking
|
|
212
213
|
📊 **Complete Observability** - Traces, metrics, and rich span attributes
|
|
213
214
|
➕ **Service Instance ID & Environment** - Identify your services and environments
|
|
214
215
|
⏱️ **Configurable Exporter Timeout** - Set timeout for OTLP exporter
|
|
@@ -314,6 +315,40 @@ The library includes comprehensive cost tracking with pricing data for **145+ mo
|
|
|
314
315
|
- **Cache Pricing**: Anthropic prompt caching costs (read/write)
|
|
315
316
|
- **Granular Cost Metrics**: Per-request cost breakdown by token type
|
|
316
317
|
- **Auto-Updated Pricing**: Pricing data maintained in `llm_pricing.json`
|
|
318
|
+
- **Custom Pricing**: Add pricing for custom/proprietary models via environment variable
|
|
319
|
+
|
|
320
|
+
### Adding Custom Model Pricing
|
|
321
|
+
|
|
322
|
+
For custom or proprietary models not in `llm_pricing.json`, you can provide custom pricing via the `GENAI_CUSTOM_PRICING_JSON` environment variable:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# For chat models
|
|
326
|
+
export GENAI_CUSTOM_PRICING_JSON='{"chat":{"my-custom-model":{"promptPrice":0.001,"completionPrice":0.002}}}'
|
|
327
|
+
|
|
328
|
+
# For embeddings
|
|
329
|
+
export GENAI_CUSTOM_PRICING_JSON='{"embeddings":{"my-custom-embeddings":0.00005}}'
|
|
330
|
+
|
|
331
|
+
# For multiple categories
|
|
332
|
+
export GENAI_CUSTOM_PRICING_JSON='{
|
|
333
|
+
"chat": {
|
|
334
|
+
"my-custom-chat": {"promptPrice": 0.001, "completionPrice": 0.002}
|
|
335
|
+
},
|
|
336
|
+
"embeddings": {
|
|
337
|
+
"my-custom-embed": 0.00005
|
|
338
|
+
},
|
|
339
|
+
"audio": {
|
|
340
|
+
"my-custom-tts": 0.02
|
|
341
|
+
}
|
|
342
|
+
}'
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Pricing Format:**
|
|
346
|
+
- **Chat models**: `{"promptPrice": <$/1k tokens>, "completionPrice": <$/1k tokens>}`
|
|
347
|
+
- **Embeddings**: Single number for price per 1k tokens
|
|
348
|
+
- **Audio**: Price per 1k characters (TTS) or per second (STT)
|
|
349
|
+
- **Images**: Nested structure with quality/size pricing (see `llm_pricing.json` for examples)
|
|
350
|
+
|
|
351
|
+
**Hybrid Pricing:** Custom prices are merged with default pricing from `llm_pricing.json`. If you provide custom pricing for an existing model, the custom price overrides the default.
|
|
317
352
|
|
|
318
353
|
**Coverage Statistics**: As of v0.1.3, 89% test coverage with 415 passing tests, including comprehensive cost calculation validation and cost enrichment processor tests (supporting both GenAI and OpenInference semantic conventions).
|
|
319
354
|
|
|
@@ -336,7 +371,8 @@ Every LLM call, database query, API request, and vector search is traced with fu
|
|
|
336
371
|
- `gen_ai.usage.cost.cache_write` - Cache write cost (Anthropic)
|
|
337
372
|
- `gen_ai.client.errors` - Error counts by operation and type
|
|
338
373
|
- `gen_ai.gpu.*` - GPU utilization, memory, temperature, power (ObservableGauges)
|
|
339
|
-
- `gen_ai.co2.emissions` - CO2 emissions tracking (opt-in)
|
|
374
|
+
- `gen_ai.co2.emissions` - CO2 emissions tracking (opt-in via `GENAI_ENABLE_CO2_TRACKING`)
|
|
375
|
+
- `gen_ai.power.cost` - Cumulative electricity cost in USD based on GPU power consumption (configurable via `GENAI_POWER_COST_PER_KWH`)
|
|
340
376
|
- `gen_ai.server.ttft` - Time to First Token for streaming responses (histogram, 1ms-10s buckets)
|
|
341
377
|
- `gen_ai.server.tbt` - Time Between Tokens for streaming responses (histogram, 10ms-2.5s buckets)
|
|
342
378
|
|
|
@@ -383,7 +419,14 @@ Every LLM call, database query, API request, and vector search is traced with fu
|
|
|
383
419
|
|
|
384
420
|
**Streaming Attributes:**
|
|
385
421
|
- `gen_ai.server.ttft` - Time to First Token (seconds) for streaming responses
|
|
386
|
-
- `gen_ai.streaming.token_count` - Total number of chunks
|
|
422
|
+
- `gen_ai.streaming.token_count` - Total number of chunks in streaming response
|
|
423
|
+
- `gen_ai.usage.prompt_tokens` - Actual prompt tokens (extracted from final chunk)
|
|
424
|
+
- `gen_ai.usage.completion_tokens` - Actual completion tokens (extracted from final chunk)
|
|
425
|
+
- `gen_ai.usage.total_tokens` - Total tokens (extracted from final chunk)
|
|
426
|
+
- `gen_ai.usage.cost.total` - Total cost for streaming request
|
|
427
|
+
- `gen_ai.usage.cost.prompt` - Prompt tokens cost for streaming request
|
|
428
|
+
- `gen_ai.usage.cost.completion` - Completion tokens cost for streaming request
|
|
429
|
+
- All granular cost attributes (reasoning, cache_read, cache_write) also available for streaming
|
|
387
430
|
|
|
388
431
|
**Content Events (opt-in):**
|
|
389
432
|
- `gen_ai.prompt.{index}` events with role and content
|
|
@@ -440,6 +483,181 @@ genai_otel.instrument(
|
|
|
440
483
|
|
|
441
484
|
A `sample.env` file has been generated in the project root directory. This file contains commented-out examples of all supported environment variables, along with their default values or expected formats. You can copy this file to `.env` and uncomment/modify the variables to configure the instrumentation for your specific needs.
|
|
442
485
|
|
|
486
|
+
## Advanced Features
|
|
487
|
+
|
|
488
|
+
### Session and User Tracking
|
|
489
|
+
|
|
490
|
+
Track user sessions and identify users across multiple LLM requests for better analytics, debugging, and cost attribution.
|
|
491
|
+
|
|
492
|
+
**Configuration:**
|
|
493
|
+
|
|
494
|
+
```python
|
|
495
|
+
import genai_otel
|
|
496
|
+
from genai_otel import OTelConfig
|
|
497
|
+
|
|
498
|
+
# Define extractor functions
|
|
499
|
+
def extract_session_id(instance, args, kwargs):
|
|
500
|
+
"""Extract session ID from request metadata."""
|
|
501
|
+
# Option 1: From kwargs metadata
|
|
502
|
+
metadata = kwargs.get("metadata", {})
|
|
503
|
+
return metadata.get("session_id")
|
|
504
|
+
|
|
505
|
+
# Option 2: From custom headers
|
|
506
|
+
# headers = kwargs.get("headers", {})
|
|
507
|
+
# return headers.get("X-Session-ID")
|
|
508
|
+
|
|
509
|
+
# Option 3: From thread-local storage
|
|
510
|
+
# import threading
|
|
511
|
+
# return getattr(threading.current_thread(), "session_id", None)
|
|
512
|
+
|
|
513
|
+
def extract_user_id(instance, args, kwargs):
|
|
514
|
+
"""Extract user ID from request metadata."""
|
|
515
|
+
metadata = kwargs.get("metadata", {})
|
|
516
|
+
return metadata.get("user_id")
|
|
517
|
+
|
|
518
|
+
# Configure with extractors
|
|
519
|
+
config = OTelConfig(
|
|
520
|
+
service_name="my-rag-app",
|
|
521
|
+
endpoint="http://localhost:4318",
|
|
522
|
+
session_id_extractor=extract_session_id,
|
|
523
|
+
user_id_extractor=extract_user_id,
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
genai_otel.instrument(config)
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
**Usage:**
|
|
530
|
+
|
|
531
|
+
```python
|
|
532
|
+
from openai import OpenAI
|
|
533
|
+
|
|
534
|
+
client = OpenAI()
|
|
535
|
+
|
|
536
|
+
# Pass session and user info via metadata
|
|
537
|
+
response = client.chat.completions.create(
|
|
538
|
+
model="gpt-3.5-turbo",
|
|
539
|
+
messages=[{"role": "user", "content": "What is OpenTelemetry?"}],
|
|
540
|
+
extra_body={"metadata": {"session_id": "sess_12345", "user_id": "user_alice"}}
|
|
541
|
+
)
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**Span Attributes Added:**
|
|
545
|
+
- `session.id` - Unique session identifier for tracking conversations
|
|
546
|
+
- `user.id` - User identifier for per-user analytics and cost tracking
|
|
547
|
+
|
|
548
|
+
**Use Cases:**
|
|
549
|
+
- Track multi-turn conversations across requests
|
|
550
|
+
- Analyze usage patterns per user
|
|
551
|
+
- Debug session-specific issues
|
|
552
|
+
- Calculate per-user costs and quotas
|
|
553
|
+
- Build user-specific dashboards
|
|
554
|
+
|
|
555
|
+
### RAG and Embedding Attributes
|
|
556
|
+
|
|
557
|
+
Enhanced observability for Retrieval-Augmented Generation (RAG) workflows, including embedding generation and document retrieval.
|
|
558
|
+
|
|
559
|
+
**Helper Methods:**
|
|
560
|
+
|
|
561
|
+
The `BaseInstrumentor` provides helper methods to add RAG-specific attributes to your spans:
|
|
562
|
+
|
|
563
|
+
```python
|
|
564
|
+
from opentelemetry import trace
|
|
565
|
+
from genai_otel.instrumentors.base import BaseInstrumentor
|
|
566
|
+
|
|
567
|
+
# Get your instrumentor instance (or create spans manually)
|
|
568
|
+
tracer = trace.get_tracer(__name__)
|
|
569
|
+
|
|
570
|
+
# 1. Embedding Attributes
|
|
571
|
+
with tracer.start_as_current_span("embedding.create") as span:
|
|
572
|
+
# Your embedding logic
|
|
573
|
+
embedding_response = client.embeddings.create(
|
|
574
|
+
model="text-embedding-3-small",
|
|
575
|
+
input="OpenTelemetry provides observability"
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
# Add embedding attributes (if using BaseInstrumentor)
|
|
579
|
+
# instrumentor.add_embedding_attributes(
|
|
580
|
+
# span,
|
|
581
|
+
# model="text-embedding-3-small",
|
|
582
|
+
# input_text="OpenTelemetry provides observability",
|
|
583
|
+
# vector=embedding_response.data[0].embedding
|
|
584
|
+
# )
|
|
585
|
+
|
|
586
|
+
# Or manually set attributes
|
|
587
|
+
span.set_attribute("embedding.model_name", "text-embedding-3-small")
|
|
588
|
+
span.set_attribute("embedding.text", "OpenTelemetry provides observability"[:500])
|
|
589
|
+
span.set_attribute("embedding.vector.dimension", len(embedding_response.data[0].embedding))
|
|
590
|
+
|
|
591
|
+
# 2. Retrieval Attributes
|
|
592
|
+
with tracer.start_as_current_span("retrieval.search") as span:
|
|
593
|
+
# Your retrieval logic
|
|
594
|
+
retrieved_docs = [
|
|
595
|
+
{
|
|
596
|
+
"id": "doc_001",
|
|
597
|
+
"score": 0.95,
|
|
598
|
+
"content": "OpenTelemetry is an observability framework...",
|
|
599
|
+
"metadata": {"source": "docs.opentelemetry.io", "category": "intro"}
|
|
600
|
+
},
|
|
601
|
+
# ... more documents
|
|
602
|
+
]
|
|
603
|
+
|
|
604
|
+
# Add retrieval attributes (if using BaseInstrumentor)
|
|
605
|
+
# instrumentor.add_retrieval_attributes(
|
|
606
|
+
# span,
|
|
607
|
+
# documents=retrieved_docs,
|
|
608
|
+
# query="What is OpenTelemetry?",
|
|
609
|
+
# max_docs=5
|
|
610
|
+
# )
|
|
611
|
+
|
|
612
|
+
# Or manually set attributes
|
|
613
|
+
span.set_attribute("retrieval.query", "What is OpenTelemetry?"[:500])
|
|
614
|
+
span.set_attribute("retrieval.document_count", len(retrieved_docs))
|
|
615
|
+
|
|
616
|
+
for i, doc in enumerate(retrieved_docs[:5]): # Limit to 5 docs
|
|
617
|
+
prefix = f"retrieval.documents.{i}.document"
|
|
618
|
+
span.set_attribute(f"{prefix}.id", doc["id"])
|
|
619
|
+
span.set_attribute(f"{prefix}.score", doc["score"])
|
|
620
|
+
span.set_attribute(f"{prefix}.content", doc["content"][:500])
|
|
621
|
+
|
|
622
|
+
# Add metadata
|
|
623
|
+
for key, value in doc.get("metadata", {}).items():
|
|
624
|
+
span.set_attribute(f"{prefix}.metadata.{key}", str(value))
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Embedding Attributes:**
|
|
628
|
+
- `embedding.model_name` - Embedding model used
|
|
629
|
+
- `embedding.text` - Input text (truncated to 500 chars)
|
|
630
|
+
- `embedding.vector` - Embedding vector (optional, if configured)
|
|
631
|
+
- `embedding.vector.dimension` - Vector dimensions
|
|
632
|
+
|
|
633
|
+
**Retrieval Attributes:**
|
|
634
|
+
- `retrieval.query` - Search query (truncated to 500 chars)
|
|
635
|
+
- `retrieval.document_count` - Number of documents retrieved
|
|
636
|
+
- `retrieval.documents.{i}.document.id` - Document ID
|
|
637
|
+
- `retrieval.documents.{i}.document.score` - Relevance score
|
|
638
|
+
- `retrieval.documents.{i}.document.content` - Document content (truncated to 500 chars)
|
|
639
|
+
- `retrieval.documents.{i}.document.metadata.*` - Custom metadata fields
|
|
640
|
+
|
|
641
|
+
**Safeguards:**
|
|
642
|
+
- Text content truncated to 500 characters to avoid span size explosion
|
|
643
|
+
- Document count limited to 5 by default (configurable via `max_docs`)
|
|
644
|
+
- Metadata values truncated to prevent excessive attribute counts
|
|
645
|
+
|
|
646
|
+
**Complete RAG Workflow Example:**
|
|
647
|
+
|
|
648
|
+
See `examples/phase4_session_rag_tracking.py` for a comprehensive demonstration of:
|
|
649
|
+
- Session and user tracking across RAG pipeline
|
|
650
|
+
- Embedding attribute capture
|
|
651
|
+
- Retrieval attribute capture
|
|
652
|
+
- End-to-end RAG workflow with full observability
|
|
653
|
+
|
|
654
|
+
**Use Cases:**
|
|
655
|
+
- Monitor retrieval quality and relevance scores
|
|
656
|
+
- Debug RAG pipeline performance
|
|
657
|
+
- Track embedding model usage
|
|
658
|
+
- Analyze document retrieval patterns
|
|
659
|
+
- Optimize vector search configurations
|
|
660
|
+
|
|
443
661
|
## Example: Full-Stack GenAI App
|
|
444
662
|
|
|
445
663
|
```python
|
|
@@ -622,27 +840,33 @@ genai_otel.instrument(
|
|
|
622
840
|
|
|
623
841
|
Completing remaining items from [OTEL_SEMANTIC_GAP_ANALYSIS_AND_IMPLEMENTATION_PLAN.md](OTEL_SEMANTIC_GAP_ANALYSIS_AND_IMPLEMENTATION_PLAN.md):
|
|
624
842
|
|
|
625
|
-
**Phase 4: Optional Enhancements**
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
- ✅ RAG/Embedding Attributes - Enhanced observability for retrieval-augmented generation
|
|
635
|
-
- `
|
|
636
|
-
- `embedding.
|
|
637
|
-
- `retrieval.documents.{i}.document
|
|
638
|
-
-
|
|
639
|
-
- `
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
843
|
+
**Phase 4: Optional Enhancements (✅ COMPLETED)**
|
|
844
|
+
|
|
845
|
+
All Phase 4 features are now available! See the [Advanced Features](#advanced-features) section for detailed documentation.
|
|
846
|
+
|
|
847
|
+
- ✅ **Session & User Tracking** - Track sessions and users across requests with custom extractor functions
|
|
848
|
+
- Configurable via `session_id_extractor` and `user_id_extractor` in `OTelConfig`
|
|
849
|
+
- Automatically adds `session.id` and `user.id` span attributes
|
|
850
|
+
- See [Session and User Tracking](#session-and-user-tracking) for usage examples
|
|
851
|
+
|
|
852
|
+
- ✅ **RAG/Embedding Attributes** - Enhanced observability for retrieval-augmented generation
|
|
853
|
+
- Helper methods: `add_embedding_attributes()` and `add_retrieval_attributes()`
|
|
854
|
+
- Embedding attributes: `embedding.model_name`, `embedding.text`, `embedding.vector.dimension`
|
|
855
|
+
- Retrieval attributes: `retrieval.query`, `retrieval.document_count`, `retrieval.documents.{i}.document.*`
|
|
856
|
+
- See [RAG and Embedding Attributes](#rag-and-embedding-attributes) for usage examples
|
|
857
|
+
- Complete example: `examples/phase4_session_rag_tracking.py`
|
|
858
|
+
|
|
859
|
+
**Note on Agent Workflow Tracking:**
|
|
860
|
+
|
|
861
|
+
Agent workflow observability is already provided by the OpenInference Smolagents instrumentor (included when `smolagents` is in `enabled_instrumentors`). This is not a new Phase 4 feature, but an existing capability:
|
|
862
|
+
|
|
863
|
+
- `openinference.span.kind: "AGENT"` - Identifies agent spans
|
|
864
|
+
- `agent.name` - Agent identifier (via OpenInference)
|
|
865
|
+
- `agent.iteration` - Current iteration number (via OpenInference)
|
|
866
|
+
- `agent.action` - Action taken (via OpenInference)
|
|
867
|
+
- `agent.observation` - Observation received (via OpenInference)
|
|
868
|
+
|
|
869
|
+
Agent tracking requires Python >= 3.10 and the `smolagents` library. See [OpenInference Integration](#openinference-optional---python-310-only) for details.
|
|
646
870
|
|
|
647
871
|
#### 🔄 Migration Support
|
|
648
872
|
|
{genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/RECORD
RENAMED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
genai_otel/__init__.py,sha256=OWgm1dihRkwBQU8fUPnVhE5XCZeF5f15UyH4w6LqGZU,4469
|
|
2
|
-
genai_otel/__version__.py,sha256=
|
|
2
|
+
genai_otel/__version__.py,sha256=amWIeki4bm5YbDNKNBNcQKLS8IoAVLPuipySazUun7Y,751
|
|
3
3
|
genai_otel/auto_instrument.py,sha256=NF0Bo_sFMynSmXNh5KFxdsJQPKuPE2NI_bel1i-CtxU,16260
|
|
4
4
|
genai_otel/cli.py,sha256=mbhaTU0WIAkvPKdIing-guIxPDjEKQftChWQUtPFzkY,3170
|
|
5
|
-
genai_otel/config.py,sha256=
|
|
6
|
-
genai_otel/cost_calculator.py,sha256=
|
|
7
|
-
genai_otel/cost_enrichment_processor.py,sha256=
|
|
5
|
+
genai_otel/config.py,sha256=2CIbZH8WKkVzr73y9AOWmscvEW-kUwMLSAyOy9BFqGI,7871
|
|
6
|
+
genai_otel/cost_calculator.py,sha256=BOW-TC41lJ1GcL4hIGZ4NySyV8aro4_juMOe2IqtJ-A,18115
|
|
7
|
+
genai_otel/cost_enrichment_processor.py,sha256=07T7q2gBbB7b-L0Dt5VDsVuxB3XSfnpbtFjcV3ZTpk0,7099
|
|
8
8
|
genai_otel/exceptions.py,sha256=gIRvbI7c4V-M-PG9jS0o4ESRwHUWCm6DVihjfyJI1yg,429
|
|
9
|
-
genai_otel/gpu_metrics.py,sha256=
|
|
10
|
-
genai_otel/llm_pricing.json,sha256=
|
|
11
|
-
genai_otel/logging_config.py,sha256=
|
|
9
|
+
genai_otel/gpu_metrics.py,sha256=hBawkm-NErviwiLzb7z92INstFHec2pREn945rYgrT4,13408
|
|
10
|
+
genai_otel/llm_pricing.json,sha256=ZQ1uILEdQ_yNzenvlPpKazo9NnYqEZgbL_tzQ6Mw2oc,20825
|
|
11
|
+
genai_otel/logging_config.py,sha256=S8apGf93nBjoi_Bhce-LxwTwGTaJUeduPXKiWZ5SIa8,1418
|
|
12
12
|
genai_otel/metrics.py,sha256=Vngwtc1MAMAE7JVpbT_KfiCQ5TdIAKIs_0oztjJdDTg,2671
|
|
13
|
-
genai_otel/py.typed,sha256=
|
|
13
|
+
genai_otel/py.typed,sha256=WJtVGe64tcQSssSo4RD7zCf_3u7X2BmFCWDCroWOcaQ,88
|
|
14
14
|
genai_otel/instrumentors/__init__.py,sha256=39CQZZS-AcHNn37pdt1rCOVBvX9t5RGMPY3sEulQzMA,1821
|
|
15
15
|
genai_otel/instrumentors/anthropic_instrumentor.py,sha256=3koeXSJccALdZiRibavwQt8_lrXYwEhdWfA3dnCo_ng,4837
|
|
16
16
|
genai_otel/instrumentors/anyscale_instrumentor.py,sha256=WUcQVDK8W76gkrAT_TLgzFd7NY42Rn6x0irT7VV2bbI,774
|
|
17
17
|
genai_otel/instrumentors/aws_bedrock_instrumentor.py,sha256=W469XxNVsb6eDjerk3SkjZFZEOIzH_HkBkmqqSCRBhU,3670
|
|
18
18
|
genai_otel/instrumentors/azure_openai_instrumentor.py,sha256=HumsAAtW9YzbcyBCrIGhE5KvZ6-mxSbsEoI_W0JU7xg,2428
|
|
19
|
-
genai_otel/instrumentors/base.py,sha256=
|
|
20
|
-
genai_otel/instrumentors/cohere_instrumentor.py,sha256=
|
|
19
|
+
genai_otel/instrumentors/base.py,sha256=5N0eMDoPT49PedhoDM0EGu8NE9UvseaiWhqfb9UHTIw,38210
|
|
20
|
+
genai_otel/instrumentors/cohere_instrumentor.py,sha256=fsKvHaWvMRAGRbOtybVJVVz-FS_-wmgTJo3Q_F86BOY,5074
|
|
21
21
|
genai_otel/instrumentors/google_ai_instrumentor.py,sha256=ExNo0_OxfCxaRpuUXYU8UZ-ClQRHRLUvf7-kMC6zdc8,2984
|
|
22
22
|
genai_otel/instrumentors/groq_instrumentor.py,sha256=bCm7IDmDyvg0-XuzcCSO5xf9QvDlQGwb7bdQ_ooS6QI,3398
|
|
23
|
-
genai_otel/instrumentors/huggingface_instrumentor.py,sha256=
|
|
24
|
-
genai_otel/instrumentors/langchain_instrumentor.py,sha256=
|
|
23
|
+
genai_otel/instrumentors/huggingface_instrumentor.py,sha256=XlSuHEkxEWu0dAXtw1pAFE3n-M8WFRfKUsgbUSV_Arw,9204
|
|
24
|
+
genai_otel/instrumentors/langchain_instrumentor.py,sha256=002ZrKP04l7VaYxo7nAAwl-uvMVwpzVehO2oS23ed-o,2685
|
|
25
25
|
genai_otel/instrumentors/llamaindex_instrumentor.py,sha256=zZ1J7W4yQo1Ur6Y5y0UXpDdEx9oDnmsqNIin5Jrv9os,1206
|
|
26
|
-
genai_otel/instrumentors/mistralai_instrumentor.py,sha256=
|
|
26
|
+
genai_otel/instrumentors/mistralai_instrumentor.py,sha256=Blo8X4WV-xQe-xF-jhkaGPavkgayANf1F3zCTzuhuL0,12478
|
|
27
27
|
genai_otel/instrumentors/ollama_instrumentor.py,sha256=lv45qf8Cqe_HmF7BIMojZcBFK8AA13uUrCVOKAFhN0k,5286
|
|
28
28
|
genai_otel/instrumentors/openai_instrumentor.py,sha256=0q2vml2oWnTRzfVTEP0_njfxqZS8b3Qek-apeecXvvs,9263
|
|
29
29
|
genai_otel/instrumentors/replicate_instrumentor.py,sha256=-G_Tj0VkAfg-cOKvnk4G56eJiADjyIgv6xEgyAWlFdw,3028
|
|
@@ -37,9 +37,9 @@ genai_otel/mcp_instrumentors/kafka_instrumentor.py,sha256=QJYJC1rvo_zZAIaw-cp_Ic
|
|
|
37
37
|
genai_otel/mcp_instrumentors/manager.py,sha256=1Pj5lkEOL8Yq1Oeud4ZExN6k6NLIVtTzKnFLNiFdJvw,5895
|
|
38
38
|
genai_otel/mcp_instrumentors/redis_instrumentor.py,sha256=KUbs0dMyfMzU4T0SS8u43I5fvr09lcBBM92I3KCsYUw,943
|
|
39
39
|
genai_otel/mcp_instrumentors/vector_db_instrumentor.py,sha256=2vhnk4PGpfYKr-XlRbnCIOap4BPKHOn--fh-ai2YXlM,9994
|
|
40
|
-
genai_otel_instrument-0.1.
|
|
41
|
-
genai_otel_instrument-0.1.
|
|
42
|
-
genai_otel_instrument-0.1.
|
|
43
|
-
genai_otel_instrument-0.1.
|
|
44
|
-
genai_otel_instrument-0.1.
|
|
45
|
-
genai_otel_instrument-0.1.
|
|
40
|
+
genai_otel_instrument-0.1.7.dev0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
41
|
+
genai_otel_instrument-0.1.7.dev0.dist-info/METADATA,sha256=ogiTaS3MknTz1tAq51JbpZzpxozuLnkD-f2Z4iu57vk,39184
|
|
42
|
+
genai_otel_instrument-0.1.7.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
43
|
+
genai_otel_instrument-0.1.7.dev0.dist-info/entry_points.txt,sha256=E9UqoHA_fq69yNGAY3SRYf5HH94sZT5DiDueiU1v0KM,57
|
|
44
|
+
genai_otel_instrument-0.1.7.dev0.dist-info/top_level.txt,sha256=cvCm8PUwvYUSQKruk-x6S-_YuDyhOBk8gD910XICcbg,11
|
|
45
|
+
genai_otel_instrument-0.1.7.dev0.dist-info/RECORD,,
|
{genai_otel_instrument-0.1.4.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|