| 1 | # Dependencies: opentelemetry-exporter-otlp |
| 2 | |
| 3 | import os |
| 4 | import time |
| 5 | from opentelemetry import trace |
| 6 | from opentelemetry.sdk.trace import TracerProvider |
| 7 | from opentelemetry.sdk.trace.export import BatchSpanProcessor |
| 8 | from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter |
| 9 | from opentelemetry.sdk.resources import Resource |
| 10 | from opentelemetry.semconv.resource import ResourceAttributes |
| 11 | |
| 12 | |
| 13 | # Configure OpenTelemetry |
| 14 | |
| 15 | # For comet.com |
| 16 | os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://www.comet.com/opik/api/v1/private/otel" |
| 17 | os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = "Authorization=<your-api-key>,Comet-Workspace=<your-workspace-name>,projectName=<your-project-name>" |
| 18 | |
| 19 | # Configure the tracer provider |
| 20 | resource = Resource.create({ |
| 21 | ResourceAttributes.SERVICE_NAME: "opentelemetry-example" |
| 22 | }) |
| 23 | |
| 24 | # Create a tracer provider |
| 25 | tracer_provider = TracerProvider(resource=resource) |
| 26 | |
| 27 | # Set up the OTLP HTTP exporter |
| 28 | otlp_exporter = OTLPSpanExporter() |
| 29 | |
| 30 | # Add the exporter to the tracer provider |
| 31 | tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter)) |
| 32 | |
| 33 | # Set the tracer provider |
| 34 | trace.set_tracer_provider(tracer_provider) |
| 35 | |
| 36 | # Get a tracer |
| 37 | tracer = trace.get_tracer("example-tracer") |
| 38 | |
| 39 | def main(): |
| 40 | # Simulate user request |
| 41 | user_request = "What's the weather like today?" |
| 42 | |
| 43 | # Create a parent span representing the entire chatbot conversation |
| 44 | with tracer.start_as_current_span("chatbot_conversation") as conversation_span: |
| 45 | print(f"User request: {user_request}") |
| 46 | |
| 47 | # Add user request as an attribute to the parent span |
| 48 | conversation_span.set_attribute("input", user_request) |
| 49 | conversation_span.set_attribute("conversation.id", "conv_12345") |
| 50 | conversation_span.set_attribute("conversation.type", "weather_inquiry") |
| 51 | |
| 52 | # Add thread ID as an attribute to the parent span to group related spans into |
| 53 | # a single conversational thread |
| 54 | conversation_span.set_attribute("thread_id", "user_12345") |
| 55 | |
| 56 | # Process the user request |
| 57 | |
| 58 | # Simulate initial processing |
| 59 | time.sleep(0.2) |
| 60 | |
| 61 | # Create a child span for LLM generation using GenAI conventions |
| 62 | with tracer.start_as_current_span("llm_completion") as llm_span: |
| 63 | print("Generating LLM response...") |
| 64 | |
| 65 | # Create a prompt for the LLM |
| 66 | llm_prompt = f"User question: {user_request}\n\nProvide a concise answer about the weather." |
| 67 | |
| 68 | # Add GenAI semantic convention attributes |
| 69 | llm_span.set_attribute("gen_ai.operation.name", "completion") |
| 70 | llm_span.set_attribute("gen_ai.system", "gpt") |
| 71 | llm_span.set_attribute("gen_ai.request.model", "gpt-4") |
| 72 | llm_span.set_attribute("gen_ai.response.model", "gpt-4") |
| 73 | llm_span.set_attribute("gen_ai.request.input", llm_prompt) # Add the prompt |
| 74 | llm_span.set_attribute("gen_ai.usage.input_tokens", 10) # Example token count |
| 75 | llm_span.set_attribute("gen_ai.usage.output_tokens", 25) # Example token count |
| 76 | llm_span.set_attribute("gen_ai.usage.total_tokens", 35) # Example token count |
| 77 | llm_span.set_attribute("gen_ai.request.temperature", 0.7) |
| 78 | llm_span.set_attribute("gen_ai.request.max_tokens", 100) |
| 79 | |
| 80 | # Simulate LLM thinking time |
| 81 | time.sleep(0.5) |
| 82 | |
| 83 | # Generate chatbot response |
| 84 | chatbot_response = "It's sunny with a high of 75°F in your area today!" |
| 85 | |
| 86 | # Set response in the LLM span |
| 87 | llm_span.set_attribute("gen_ai.response.output", chatbot_response) |
| 88 | |
| 89 | print("LLM generation completed") |
| 90 | |
| 91 | # Back in parent span context |
| 92 | conversation_span.set_attribute("output", chatbot_response) |
| 93 | # Response has been generated |
| 94 | |
| 95 | print(f"Chatbot response: {chatbot_response}") |
| 96 | |
| 97 | if __name__ == "__main__": |
| 98 | main() |
| 99 | |
| 100 | # Ensure all spans are flushed before the program exits |
| 101 | tracer_provider.shutdown() |
| 102 | |
| 103 | print("\nSpans have been sent to OpenTelemetry collector.") |
| 104 | print("If you configured Comet.com, you can view the traces in your Comet project.") |