Tutorial: Observability & Tracing (E17)¶
This tutorial corresponds to the example file examples/E17_observability_tracing_example.py
.
It demonstrates how to use Genie's built-in tracing capabilities for debugging and monitoring. It shows how to:
- Configure a tracer plugin (e.g., ConsoleTracerPlugin
or OpenTelemetryTracerPlugin
).
- Observe the automatic trace events generated by core Genie
operations (like LLM calls).
- Manually emit custom application-level trace events using genie.observability.trace_event()
.
Example Code¶
examples/E17_observability_tracing_example.py¶
"""
Example: Using Observability and Interaction Tracing (genie.observability
)
This example demonstrates how to enable and use the interaction tracing feature of Genie Tooling. It shows configuration for both ConsoleTracerPlugin and the new OpenTelemetryTracerPlugin.
To Run with Console Tracer:
1. Ensure Genie Tooling is installed (poetry install --all-extras
).
2. Run from the root of the project:
poetry run python examples/E17_observability_tracing_example.py
You should see trace logs in your console output.
To Run with OpenTelemetry Tracer (e.g., to Jaeger):
1. Ensure OTel dependencies are installed: poetry install --extras observability
2. Start an OTel collector (e.g., Jaeger all-in-one):
docker run -d --name jaeger -e COLLECTOR_OTLP_ENABLED=true -p 16686:16686 -p 4317:4317 -p 4318:4318 jaegertracing/all-in-one:latest
3. Modify the app_config
below to use otel_tracer
and configure the OTLP endpoint.
4. Run the script. Traces should appear in Jaeger UI (http://localhost:16686).
"""
import asyncio
import logging
import traceback
import uuid
from typing import Optional
from genie_tooling.config.features import FeatureSettings from genie_tooling.config.models import MiddlewareConfig from genie_tooling.genie import Genie
async def run_observability_demo(): print("--- Observability and Tracing Example ---")
logging.basicConfig(level=logging.INFO)
app_config_console = MiddlewareConfig(
features=FeatureSettings(
llm="ollama",
llm_ollama_model_name="mistral:latest",
observability_tracer="console_tracer"
),
observability_tracer_configurations={
"console_tracer_plugin_v1": {
"log_level": "INFO"
}
}
)
app_config_otel = MiddlewareConfig(
features=FeatureSettings(
llm="ollama",
llm_ollama_model_name="mistral:latest",
observability_tracer="otel_tracer",
token_usage_recorder="otel_metrics_recorder"
),
observability_tracer_configurations={
"otel_tracer_plugin_v1": {
"otel_service_name": "genie-e17-demo-app",
"otel_service_version": "0.1.0",
"exporter_type": "otlp_http",
"otlp_http_endpoint": "http://localhost:4318/v1/traces",
"resource_attributes": {"deployment.environment": "development_e17"}
}
}
)
# --- CHOOSE CONFIGURATION TO RUN ---
app_config = app_config_console
# app_config = app_config_otel # Uncomment to use OpenTelemetry
# ------------------------------------
genie: Optional[Genie] = None
try:
print(f"\nInitializing Genie with tracer: {app_config.features.observability_tracer}...")
genie = await Genie.create(config=app_config)
print("Genie initialized! Automatic traces will now be generated.")
print("\n--- Performing operations that trigger automatic traces ---")
try:
chat_response = await genie.llm.chat([{"role": "user", "content": "Hello Tracer! Tell me a short story."}])
print(f"LLM Response: {chat_response['message']['content'][:60]}...")
except Exception as e_llm:
print(f"LLM call failed (expected if Ollama not running): {e_llm}")
print("\n--- Emitting a custom trace event ---")
custom_correlation_id = str(uuid.uuid4())
await genie.observability.trace_event(
event_name="my_app.custom_operation.start",
data={"user_id": "test_user", "input_param": "example_value"},
component="MyApplicationLogic",
correlation_id=custom_correlation_id
)
await asyncio.sleep(0.1)
try:
raise ValueError("Something went wrong in custom op!")
except ValueError as e_custom:
await genie.observability.trace_event(
event_name="my_app.custom_operation.error",
data={
"status": "failed",
"error_message": str(e_custom),
"error_type": type(e_custom).__name__,
"error_stacktrace": traceback.format_exc()
},
component="MyApplicationLogic",
correlation_id=custom_correlation_id
)
print("Custom trace events (including an error) emitted.")
except Exception as e:
print(f"\nAn error occurred: {e}")
logging.exception("Observability demo error details:")
finally:
if genie:
await genie.close()
print("\nGenie torn down.")
if name == "main": asyncio.run(run_observability_demo())