genai-otel-instrument 0.1.2.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.

Files changed (24) hide show
  1. genai_otel/__version__.py +2 -2
  2. genai_otel/auto_instrument.py +18 -1
  3. genai_otel/config.py +22 -1
  4. genai_otel/cost_calculator.py +204 -13
  5. genai_otel/cost_enrichment_processor.py +175 -0
  6. genai_otel/gpu_metrics.py +50 -0
  7. genai_otel/instrumentors/base.py +300 -44
  8. genai_otel/instrumentors/cohere_instrumentor.py +140 -76
  9. genai_otel/instrumentors/huggingface_instrumentor.py +142 -13
  10. genai_otel/instrumentors/langchain_instrumentor.py +75 -75
  11. genai_otel/instrumentors/mistralai_instrumentor.py +234 -38
  12. genai_otel/instrumentors/ollama_instrumentor.py +104 -35
  13. genai_otel/instrumentors/replicate_instrumentor.py +59 -14
  14. genai_otel/instrumentors/togetherai_instrumentor.py +120 -16
  15. genai_otel/instrumentors/vertexai_instrumentor.py +79 -15
  16. genai_otel/llm_pricing.json +869 -589
  17. genai_otel/logging_config.py +45 -45
  18. genai_otel/py.typed +2 -2
  19. {genai_otel_instrument-0.1.2.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/METADATA +294 -33
  20. {genai_otel_instrument-0.1.2.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/RECORD +24 -23
  21. {genai_otel_instrument-0.1.2.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/WHEEL +0 -0
  22. {genai_otel_instrument-0.1.2.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/entry_points.txt +0 -0
  23. {genai_otel_instrument-0.1.2.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/licenses/LICENSE +0 -0
  24. {genai_otel_instrument-0.1.2.dev0.dist-info → genai_otel_instrument-0.1.7.dev0.dist-info}/top_level.txt +0 -0
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genai-otel-instrument
3
- Version: 0.1.2.dev0
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
@@ -191,7 +191,7 @@ Dynamic: license-file
191
191
  [![GitHub Issues](https://img.shields.io/github/issues/Mandark-droid/genai_otel_instrument)](https://github.com/Mandark-droid/genai_otel_instrument/issues)
192
192
  [![GitHub Pull Requests](https://img.shields.io/github/issues-pr/Mandark-droid/genai_otel_instrument)](https://github.com/Mandark-droid/genai_otel_instrument/pulls)
193
193
 
194
- [![Code Coverage](https://img.shields.io/badge/coverage-95%25-brightgreen.svg)](https://github.com/Mandark-droid/genai_otel_instrument)
194
+ [![Code Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen.svg)](https://github.com/Mandark-droid/genai_otel_instrument)
195
195
  [![Code Style: Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
196
196
  [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
197
197
  [![Type Checked: mypy](https://img.shields.io/badge/type%20checked-mypy-blue.svg)](http://mypy-lang.org/)
@@ -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 per request
211
- 🎮 **GPU Metrics** - Real-time GPU utilization, memory, temperature, power
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
@@ -255,9 +256,9 @@ For a more comprehensive demonstration of various LLM providers and MCP tools, r
255
256
  ## What Gets Instrumented?
256
257
 
257
258
  ### LLM Providers (Auto-detected)
258
- - OpenAI, Anthropic, Google AI, AWS Bedrock, Azure OpenAI
259
- - Cohere, Mistral AI, Together AI, Groq, Ollama
260
- - Vertex AI, Replicate, Anyscale, HuggingFace
259
+ - **With Full Cost Tracking**: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure OpenAI, Cohere, Mistral AI, Together AI, Groq, Ollama, Vertex AI
260
+ - **Hardware/Local Pricing**: Replicate (hardware-based $/second), HuggingFace (local execution, free)
261
+ - **Other Providers**: Anyscale
261
262
 
262
263
  ### Frameworks
263
264
  - LangChain (chains, agents, tools)
@@ -271,15 +272,86 @@ For a more comprehensive demonstration of various LLM providers and MCP tools, r
271
272
  - **APIs**: HTTP/REST requests (requests, httpx)
272
273
 
273
274
  ### OpenInference (Optional - Python 3.10+ only)
274
- - Smolagents
275
- - MCP
276
- - LiteLLM
275
+ - Smolagents - HuggingFace smolagents framework tracing
276
+ - MCP - Model Context Protocol instrumentation
277
+ - LiteLLM - Multi-provider LLM proxy
278
+
279
+ **Cost Enrichment:** OpenInference instrumentors are automatically enriched with cost tracking! When cost tracking is enabled (`GENAI_ENABLE_COST_TRACKING=true`), a custom `CostEnrichmentSpanProcessor` extracts model and token usage from OpenInference spans and adds cost attributes (`gen_ai.usage.cost.total`, `gen_ai.usage.cost.prompt`, `gen_ai.usage.cost.completion`) using our comprehensive pricing database of 145+ models.
280
+
281
+ The processor supports OpenInference semantic conventions:
282
+ - Model: `llm.model_name`, `embedding.model_name`
283
+ - Tokens: `llm.token_count.prompt`, `llm.token_count.completion`
284
+ - Operations: `openinference.span.kind` (LLM, EMBEDDING, CHAIN, RETRIEVER, etc.)
277
285
 
278
286
  **Note:** OpenInference instrumentors require Python >= 3.10. Install with:
279
287
  ```bash
280
288
  pip install genai-otel-instrument[openinference]
281
289
  ```
282
290
 
291
+ ## Cost Tracking Coverage
292
+
293
+ The library includes comprehensive cost tracking with pricing data for **145+ models** across **11 providers**:
294
+
295
+ ### Providers with Full Token-Based Cost Tracking
296
+ - **OpenAI**: GPT-4o, GPT-4 Turbo, GPT-3.5 Turbo, o1/o3 series, embeddings, audio, vision (35+ models)
297
+ - **Anthropic**: Claude 3.5 Sonnet/Opus/Haiku, Claude 3 series (10+ models)
298
+ - **Google AI**: Gemini 1.5/2.0 Pro/Flash, PaLM 2 (12+ models)
299
+ - **AWS Bedrock**: Amazon Titan, Claude, Llama, Mistral models (20+ models)
300
+ - **Azure OpenAI**: Same as OpenAI with Azure-specific pricing
301
+ - **Cohere**: Command R/R+, Command Light, Embed v3/v2 (8+ models)
302
+ - **Mistral AI**: Mistral Large/Medium/Small, Mixtral, embeddings (8+ models)
303
+ - **Together AI**: DeepSeek-R1, Llama 3.x, Qwen, Mixtral (25+ models)
304
+ - **Groq**: Llama 3.x series, Mixtral, Gemma models (15+ models)
305
+ - **Ollama**: Local models with token tracking (pricing via cost estimation)
306
+ - **Vertex AI**: Gemini models via Google Cloud with usage metadata extraction
307
+
308
+ ### Special Pricing Models
309
+ - **Replicate**: Hardware-based pricing ($/second of GPU/CPU time) - not token-based
310
+ - **HuggingFace Transformers**: Local execution - no API costs
311
+
312
+ ### Pricing Features
313
+ - **Differential Pricing**: Separate rates for prompt tokens vs. completion tokens
314
+ - **Reasoning Tokens**: Special pricing for OpenAI o1/o3 reasoning tokens
315
+ - **Cache Pricing**: Anthropic prompt caching costs (read/write)
316
+ - **Granular Cost Metrics**: Per-request cost breakdown by token type
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.
352
+
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).
354
+
283
355
  ## Collected Telemetry
284
356
 
285
357
  ### Traces
@@ -299,7 +371,8 @@ Every LLM call, database query, API request, and vector search is traced with fu
299
371
  - `gen_ai.usage.cost.cache_write` - Cache write cost (Anthropic)
300
372
  - `gen_ai.client.errors` - Error counts by operation and type
301
373
  - `gen_ai.gpu.*` - GPU utilization, memory, temperature, power (ObservableGauges)
302
- - `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`)
303
376
  - `gen_ai.server.ttft` - Time to First Token for streaming responses (histogram, 1ms-10s buckets)
304
377
  - `gen_ai.server.tbt` - Time Between Tokens for streaming responses (histogram, 10ms-2.5s buckets)
305
378
 
@@ -346,7 +419,14 @@ Every LLM call, database query, API request, and vector search is traced with fu
346
419
 
347
420
  **Streaming Attributes:**
348
421
  - `gen_ai.server.ttft` - Time to First Token (seconds) for streaming responses
349
- - `gen_ai.streaming.token_count` - Total number of chunks/tokens in streaming response
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
350
430
 
351
431
  **Content Events (opt-in):**
352
432
  - `gen_ai.prompt.{index}` events with role and content
@@ -403,6 +483,181 @@ genai_otel.instrument(
403
483
 
404
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.
405
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
+
406
661
  ## Example: Full-Stack GenAI App
407
662
 
408
663
  ```python
@@ -585,27 +840,33 @@ genai_otel.instrument(
585
840
 
586
841
  Completing remaining items from [OTEL_SEMANTIC_GAP_ANALYSIS_AND_IMPLEMENTATION_PLAN.md](OTEL_SEMANTIC_GAP_ANALYSIS_AND_IMPLEMENTATION_PLAN.md):
587
842
 
588
- **Phase 4: Optional Enhancements**
589
- - ✅ Session & User Tracking - Track sessions and users across requests
590
- ```python
591
- genai_otel.instrument(
592
- session_id_extractor=lambda ctx: ctx.get("session_id"),
593
- user_id_extractor=lambda ctx: ctx.get("user_id")
594
- )
595
- ```
596
-
597
- - ✅ RAG/Embedding Attributes - Enhanced observability for retrieval-augmented generation
598
- - `embedding.model_name` - Embedding model used
599
- - `embedding.vector_dimensions` - Vector dimensions
600
- - `retrieval.documents.{i}.document.id` - Retrieved document IDs
601
- - `retrieval.documents.{i}.document.score` - Relevance scores
602
- - `retrieval.documents.{i}.document.content` - Document content (truncated)
603
-
604
- - Agent Workflow Tracking - Better support for agentic workflows
605
- - `agent.name` - Agent identifier
606
- - `agent.iteration` - Current iteration number
607
- - `agent.action` - Action taken
608
- - `agent.observation` - Observation received
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.
609
870
 
610
871
  #### 🔄 Migration Support
611
872
 
@@ -1,33 +1,34 @@
1
1
  genai_otel/__init__.py,sha256=OWgm1dihRkwBQU8fUPnVhE5XCZeF5f15UyH4w6LqGZU,4469
2
- genai_otel/__version__.py,sha256=eqjW0HD_fPOqOyADJFBWSMmbfbnb7cqTc_62GX2lDJU,751
3
- genai_otel/auto_instrument.py,sha256=bLOR_9y2gSB4VfwRrYI7YX_et-NwrpIzbOnmkNqbDHE,15343
2
+ genai_otel/__version__.py,sha256=amWIeki4bm5YbDNKNBNcQKLS8IoAVLPuipySazUun7Y,751
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=GSJZApBNKKXm5rp5jQsDk91qcHYzCrhmf06DHbpZMBE,6685
6
- genai_otel/cost_calculator.py,sha256=Jlp-UPO8vcfWy5u46ib1I_6w0bvVrMsz1kWi1Vn6QX4,10588
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
7
8
  genai_otel/exceptions.py,sha256=gIRvbI7c4V-M-PG9jS0o4ESRwHUWCm6DVihjfyJI1yg,429
8
- genai_otel/gpu_metrics.py,sha256=gHqV17mJ59VscilR_Bcd1ccBDdDiUs5w0bE1hNk7NqI,11168
9
- genai_otel/llm_pricing.json,sha256=fFajtjXvcNfuz_JOblz4BXpiliZvtL1Fybpa9hJv-v4,17733
10
- genai_otel/logging_config.py,sha256=XSBeslTqeHUBBadKJV2W8JFIOXorEVZ6W0xqNKjiPlA,1463
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
11
12
  genai_otel/metrics.py,sha256=Vngwtc1MAMAE7JVpbT_KfiCQ5TdIAKIs_0oztjJdDTg,2671
12
- genai_otel/py.typed,sha256=oe-lun16QtsTO6qa3gicjgj_F4jU7LSKCnBYLr6P5Yk,88
13
+ genai_otel/py.typed,sha256=WJtVGe64tcQSssSo4RD7zCf_3u7X2BmFCWDCroWOcaQ,88
13
14
  genai_otel/instrumentors/__init__.py,sha256=39CQZZS-AcHNn37pdt1rCOVBvX9t5RGMPY3sEulQzMA,1821
14
15
  genai_otel/instrumentors/anthropic_instrumentor.py,sha256=3koeXSJccALdZiRibavwQt8_lrXYwEhdWfA3dnCo_ng,4837
15
16
  genai_otel/instrumentors/anyscale_instrumentor.py,sha256=WUcQVDK8W76gkrAT_TLgzFd7NY42Rn6x0irT7VV2bbI,774
16
17
  genai_otel/instrumentors/aws_bedrock_instrumentor.py,sha256=W469XxNVsb6eDjerk3SkjZFZEOIzH_HkBkmqqSCRBhU,3670
17
18
  genai_otel/instrumentors/azure_openai_instrumentor.py,sha256=HumsAAtW9YzbcyBCrIGhE5KvZ6-mxSbsEoI_W0JU7xg,2428
18
- genai_otel/instrumentors/base.py,sha256=Xke8H3WeLLW6kyKX3z3WC6A34dnOagWGgiIuicZ-rqs,24219
19
- genai_otel/instrumentors/cohere_instrumentor.py,sha256=gFypgFH-xm-Aao03vLcRCGklylBGZt0F0n2y9_HgkFo,2442
19
+ genai_otel/instrumentors/base.py,sha256=5N0eMDoPT49PedhoDM0EGu8NE9UvseaiWhqfb9UHTIw,38210
20
+ genai_otel/instrumentors/cohere_instrumentor.py,sha256=fsKvHaWvMRAGRbOtybVJVVz-FS_-wmgTJo3Q_F86BOY,5074
20
21
  genai_otel/instrumentors/google_ai_instrumentor.py,sha256=ExNo0_OxfCxaRpuUXYU8UZ-ClQRHRLUvf7-kMC6zdc8,2984
21
22
  genai_otel/instrumentors/groq_instrumentor.py,sha256=bCm7IDmDyvg0-XuzcCSO5xf9QvDlQGwb7bdQ_ooS6QI,3398
22
- genai_otel/instrumentors/huggingface_instrumentor.py,sha256=parX4Vm0fgrzf2H2mpIMs24oRpM6bCQpCqfW3B_ilC4,3558
23
- genai_otel/instrumentors/langchain_instrumentor.py,sha256=1Y_zGBQcUNrh877k146XOW4wLBXBkNtbyuEkORXFIyQ,2760
23
+ genai_otel/instrumentors/huggingface_instrumentor.py,sha256=XlSuHEkxEWu0dAXtw1pAFE3n-M8WFRfKUsgbUSV_Arw,9204
24
+ genai_otel/instrumentors/langchain_instrumentor.py,sha256=002ZrKP04l7VaYxo7nAAwl-uvMVwpzVehO2oS23ed-o,2685
24
25
  genai_otel/instrumentors/llamaindex_instrumentor.py,sha256=zZ1J7W4yQo1Ur6Y5y0UXpDdEx9oDnmsqNIin5Jrv9os,1206
25
- genai_otel/instrumentors/mistralai_instrumentor.py,sha256=6KGgC_GeJagP-hYQjCBGcgahteZpWhF9RxmlITfq2Bs,4807
26
- genai_otel/instrumentors/ollama_instrumentor.py,sha256=gS_2YW0mEo_wg82vglQR0HuZ0NCmCU0JKQ90kw6f5kk,2875
26
+ genai_otel/instrumentors/mistralai_instrumentor.py,sha256=Blo8X4WV-xQe-xF-jhkaGPavkgayANf1F3zCTzuhuL0,12478
27
+ genai_otel/instrumentors/ollama_instrumentor.py,sha256=lv45qf8Cqe_HmF7BIMojZcBFK8AA13uUrCVOKAFhN0k,5286
27
28
  genai_otel/instrumentors/openai_instrumentor.py,sha256=0q2vml2oWnTRzfVTEP0_njfxqZS8b3Qek-apeecXvvs,9263
28
- genai_otel/instrumentors/replicate_instrumentor.py,sha256=7Jk0yTlmM2-sJpkfozA9LVB52fXKYV3tLhAvWSLvn58,1270
29
- genai_otel/instrumentors/togetherai_instrumentor.py,sha256=iFounG9OtJXyN3oxk9_k_XKmtC_WUtnUxN4d_IxIomY,1324
30
- genai_otel/instrumentors/vertexai_instrumentor.py,sha256=aphjvokd82mlyA738WUqGojT88OIFd85u4z2kHnBqrE,1453
29
+ genai_otel/instrumentors/replicate_instrumentor.py,sha256=-G_Tj0VkAfg-cOKvnk4G56eJiADjyIgv6xEgyAWlFdw,3028
30
+ genai_otel/instrumentors/togetherai_instrumentor.py,sha256=--r0YhCBIrpgyFiUwwc1LFTPoxAAXXV4lOAD66laqEY,5414
31
+ genai_otel/instrumentors/vertexai_instrumentor.py,sha256=F0-z0YXANHqccTT3SHbr7ggj3l4ebI_WwubIkPYPa68,4058
31
32
  genai_otel/mcp_instrumentors/__init__.py,sha256=0yVx5bwFxCmI72BORDKLgkn0t5h_xRXvtjUskVE60eo,512
32
33
  genai_otel/mcp_instrumentors/api_instrumentor.py,sha256=tAogtajeq4zjaM4-05XYSOzD3ig2mXX9_xFyGHL4auQ,5690
33
34
  genai_otel/mcp_instrumentors/base.py,sha256=oF_GyGZPEDS-NapIYzM_-TV1KYJeVlXXFzxzs9sMsqU,4044
@@ -36,9 +37,9 @@ genai_otel/mcp_instrumentors/kafka_instrumentor.py,sha256=QJYJC1rvo_zZAIaw-cp_Ic
36
37
  genai_otel/mcp_instrumentors/manager.py,sha256=1Pj5lkEOL8Yq1Oeud4ZExN6k6NLIVtTzKnFLNiFdJvw,5895
37
38
  genai_otel/mcp_instrumentors/redis_instrumentor.py,sha256=KUbs0dMyfMzU4T0SS8u43I5fvr09lcBBM92I3KCsYUw,943
38
39
  genai_otel/mcp_instrumentors/vector_db_instrumentor.py,sha256=2vhnk4PGpfYKr-XlRbnCIOap4BPKHOn--fh-ai2YXlM,9994
39
- genai_otel_instrument-0.1.2.dev0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
40
- genai_otel_instrument-0.1.2.dev0.dist-info/METADATA,sha256=xx-j-EJnh9GTQe-LUtTanUregUyEQrBY3ZgY2SCGWZg,27296
41
- genai_otel_instrument-0.1.2.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
- genai_otel_instrument-0.1.2.dev0.dist-info/entry_points.txt,sha256=E9UqoHA_fq69yNGAY3SRYf5HH94sZT5DiDueiU1v0KM,57
43
- genai_otel_instrument-0.1.2.dev0.dist-info/top_level.txt,sha256=cvCm8PUwvYUSQKruk-x6S-_YuDyhOBk8gD910XICcbg,11
44
- genai_otel_instrument-0.1.2.dev0.dist-info/RECORD,,
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,,