mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Telemetry and observability follow-up (#833)
* updated telemetry work * updated telemetry * slight improvement * updated tests * fixes for telemetry * fixes for mypy * added settings setup to runner to avoid error * streamline usage * updated tests * updated tests * further refinement * fix dumped item for otel * removed enable_workflow_otel * final fixes * final fixes * updated samples * removed exporters * fix tests * fixed last import' * fixed devui
This commit is contained in:
committed by
GitHub
Unverified
parent
f93f16a9ad
commit
2576e7a091
+2
-3
@@ -5,9 +5,8 @@
|
||||
# see ../../../env.example for details
|
||||
|
||||
# Otel specific variables
|
||||
APPLICATION_INSIGHTS_CONNECTION_STRING="..."
|
||||
APPLICATION_INSIGHTS_LIVE_METRICS=true
|
||||
APPLICATIONINSIGHTS_CONNECTION_STRING="..."
|
||||
APPLICATIONINSIGHTS_LIVE_METRICS=true
|
||||
OTLP_ENDPOINT="http://localhost:4317/"
|
||||
ENABLE_OTEL=true
|
||||
ENABLE_SENSITIVE_DATA=true
|
||||
WORKFLOW_ENABLE_OTEL=true
|
||||
+6
-10
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
# type: ignore
|
||||
import asyncio
|
||||
import os
|
||||
from random import randint
|
||||
from typing import TYPE_CHECKING, Annotated
|
||||
|
||||
@@ -14,18 +13,15 @@ if TYPE_CHECKING:
|
||||
|
||||
"""
|
||||
This is the simplest sample of using the Agent Framework with telemetry.
|
||||
Since it does not create a tracer or span in the script's code, we can let the Agent Framework SDK handle everything.
|
||||
If the environment variables are set correctly,
|
||||
the SDK will automatically initialize telemetry and collect traces and logs.
|
||||
|
||||
This relies on the environment setting up the telemetry, you can test this with
|
||||
by navigating to this folder and running:
|
||||
uv run --env-file=zero_code.env opentelemetry-instrument python 01-zero_code.py
|
||||
|
||||
Check the zero_code.env file for the settings used in this example and to adapt it to your environment.
|
||||
"""
|
||||
|
||||
|
||||
if "AGENT_FRAMEWORK_ENABLE_OTEL" not in os.environ:
|
||||
print("Set AGENT_FRAMEWORK_ENABLE_OTEL to enable telemetry with a OTLP endpoint.")
|
||||
if "AGENT_FRAMEWORK_OTLP_ENDPOINT" not in os.environ and "AGENT_FRAMEWORK_MONITOR_CONNECTION_STRING" not in os.environ:
|
||||
print("Set AGENT_FRAMEWORK_OTLP_ENDPOINT or AGENT_FRAMEWORK_MONITOR_CONNECTION_STRING to enable telemetry.")
|
||||
|
||||
|
||||
async def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
) -> str:
|
||||
+8
-16
@@ -6,11 +6,10 @@ from contextlib import suppress
|
||||
from random import randint
|
||||
from typing import TYPE_CHECKING, Annotated, Literal
|
||||
|
||||
from agent_framework import __version__, ai_function
|
||||
from agent_framework import ai_function
|
||||
from agent_framework.observability import get_tracer, setup_observability
|
||||
from agent_framework.openai import OpenAIResponsesClient
|
||||
from agent_framework.telemetry import setup_telemetry
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.trace import SpanKind
|
||||
from opentelemetry.trace.span import format_trace_id
|
||||
from pydantic import Field
|
||||
|
||||
@@ -19,8 +18,8 @@ if TYPE_CHECKING:
|
||||
|
||||
"""
|
||||
This sample, show how you can get telemetry from a chat client and tool.
|
||||
it explicitly calls the `setup_telemetry` function to set up telemetry in order to include the overall spans,
|
||||
those are defined in the main and run_* functions.
|
||||
it uses the `tracer` that is configured by agent framework,
|
||||
which also sets up the traces with the configured environment.
|
||||
"""
|
||||
|
||||
|
||||
@@ -60,9 +59,7 @@ async def run_chat_client(client: "ChatClientProtocol", stream: bool = False) ->
|
||||
|
||||
"""
|
||||
scenario_name = "Chat Client Stream" if stream else "Chat Client"
|
||||
|
||||
tracer = trace.get_tracer("agent_framework", __version__)
|
||||
with tracer.start_as_current_span(name=f"Scenario: {scenario_name}", kind=SpanKind.CLIENT):
|
||||
with get_tracer().start_as_current_span(name=f"Scenario: {scenario_name}", kind=trace.SpanKind.CLIENT):
|
||||
print("Running scenario:", scenario_name)
|
||||
message = "What's the weather in Amsterdam and in Paris?"
|
||||
print(f"User: {message}")
|
||||
@@ -87,9 +84,7 @@ async def run_ai_function() -> None:
|
||||
The telemetry will include information about the AI function execution
|
||||
and the AI service execution.
|
||||
"""
|
||||
|
||||
tracer = trace.get_tracer("agent_framework", __version__)
|
||||
with tracer.start_as_current_span("Scenario: AI Function", kind=SpanKind.CLIENT):
|
||||
with get_tracer().start_as_current_span("Scenario: AI Function", kind=trace.SpanKind.CLIENT):
|
||||
print("Running scenario: AI Function")
|
||||
func = ai_function(get_weather)
|
||||
weather = await func.invoke(location="Amsterdam")
|
||||
@@ -98,11 +93,8 @@ async def run_ai_function() -> None:
|
||||
|
||||
async def main(scenario: Literal["chat_client", "chat_client_stream", "ai_function", "all"] = "all"):
|
||||
"""Run the selected scenario(s)."""
|
||||
|
||||
setup_telemetry()
|
||||
|
||||
tracer = trace.get_tracer("My application", __version__)
|
||||
with tracer.start_as_current_span("Sample Scenario's", kind=SpanKind.CLIENT) as current_span:
|
||||
setup_observability()
|
||||
with get_tracer().start_as_current_span("Sample Scenario's", kind=trace.SpanKind.CLIENT) as current_span:
|
||||
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
|
||||
|
||||
client = OpenAIResponsesClient()
|
||||
+10
-10
@@ -6,11 +6,10 @@ from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import HostedCodeInterpreterTool
|
||||
from agent_framework.telemetry import setup_telemetry
|
||||
from agent_framework_foundry import FoundryChatClient
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from agent_framework.observability import get_tracer, setup_observability
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.trace import SpanKind
|
||||
from opentelemetry.trace.span import format_trace_id
|
||||
from pydantic import Field
|
||||
@@ -19,7 +18,7 @@ from pydantic import Field
|
||||
This sample, shows you can leverage the built-in telemetry in Foundry.
|
||||
It uses the Foundry client to setup the telemetry, this calls
|
||||
out to Foundry for a telemetry connection strings,
|
||||
and then call the setup_telemetry function in the agent framework.
|
||||
and then call the setup_observability function in the agent framework.
|
||||
If you want to compare with the trace sent to a generic OTLP endpoint,
|
||||
switch the `use_foundry_telemetry` variable to False.
|
||||
"""
|
||||
@@ -51,7 +50,7 @@ async def main() -> None:
|
||||
In foundry you will also see specific operations happening that are called by the Foundry implementation,
|
||||
such as `create_agent`.
|
||||
"""
|
||||
use_foundry_telemetry = True
|
||||
use_foundry_obs = True
|
||||
questions = [
|
||||
"What's the weather in Amsterdam and in Paris?",
|
||||
"Why is the sky blue?",
|
||||
@@ -63,13 +62,14 @@ async def main() -> None:
|
||||
AIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=credential) as project,
|
||||
FoundryChatClient(client=project, setup_tracing=False) as client,
|
||||
):
|
||||
if use_foundry_telemetry:
|
||||
await client.setup_foundry_telemetry(enable_live_metrics=True)
|
||||
if use_foundry_obs:
|
||||
await client.setup_foundry_observability(enable_live_metrics=True)
|
||||
else:
|
||||
setup_telemetry()
|
||||
setup_observability()
|
||||
|
||||
tracer = trace.get_tracer("agent_framework")
|
||||
with tracer.start_as_current_span(name="Foundry Telemetry from Agent Framework", kind=SpanKind.CLIENT) as span:
|
||||
with get_tracer().start_as_current_span(
|
||||
name="Foundry Telemetry from Agent Framework", kind=SpanKind.CLIENT
|
||||
) as span:
|
||||
for question in questions:
|
||||
print(f"{BLUE}User: {question}{RESET}")
|
||||
print(f"{BLUE}Assistant: {RESET}", end="")
|
||||
+3
-6
@@ -5,9 +5,8 @@ from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework.observability import get_tracer, setup_observability
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.telemetry import setup_telemetry
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.trace import SpanKind
|
||||
from pydantic import Field
|
||||
|
||||
@@ -29,12 +28,10 @@ async def get_weather(
|
||||
|
||||
async def main():
|
||||
# Set up the telemetry
|
||||
setup_telemetry()
|
||||
|
||||
questions = ["What's the weather in Amsterdam?", "and in Paris, and which is better?", "Why is the sky blue?"]
|
||||
|
||||
tracer = trace.get_tracer("agent_framework")
|
||||
with tracer.start_as_current_span("Scenario: Agent Chat", kind=SpanKind.CLIENT):
|
||||
setup_observability()
|
||||
with get_tracer().start_as_current_span("Scenario: Agent Chat", kind=SpanKind.CLIENT):
|
||||
print("Running scenario: Agent Chat")
|
||||
print("Welcome to the chat, type 'exit' to quit.")
|
||||
agent = ChatAgent(
|
||||
+5
-6
@@ -6,16 +6,16 @@ from random import randint
|
||||
from typing import Annotated
|
||||
|
||||
from agent_framework import ChatAgent
|
||||
from agent_framework.observability import get_tracer
|
||||
from agent_framework_foundry import FoundryChatClient
|
||||
from azure.ai.projects.aio import AIProjectClient
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.trace import SpanKind
|
||||
from pydantic import Field
|
||||
|
||||
"""
|
||||
This sample shows you can can setup telemetry with a agent from Foundry.
|
||||
We once again call the `setup_foundry_telemetry` method to set up telemetry in order to include the overall spans.
|
||||
We once again call the `setup_foundry_observability` method to set up telemetry in order to include the overall spans.
|
||||
"""
|
||||
|
||||
|
||||
@@ -35,12 +35,11 @@ async def main():
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
AIProjectClient(endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], credential=credential) as project,
|
||||
# this calls `setup_foundry_telemetry` through the context manager
|
||||
# this calls `setup_foundry_observability` through the context manager
|
||||
FoundryChatClient(client=project) as client,
|
||||
):
|
||||
await client.setup_foundry_telemetry(enable_live_metrics=True)
|
||||
tracer = trace.get_tracer("agent_framework")
|
||||
with tracer.start_as_current_span("Single Agent Chat", kind=SpanKind.CLIENT):
|
||||
await client.setup_foundry_observability(enable_live_metrics=True)
|
||||
with get_tracer().start_as_current_span("Single Agent Chat", kind=SpanKind.CLIENT):
|
||||
print("Running Single Agent Chat")
|
||||
print("Welcome to the chat, type 'exit' to quit.")
|
||||
agent = ChatAgent(
|
||||
+3
-8
@@ -10,8 +10,7 @@ from agent_framework import (
|
||||
WorkflowContext,
|
||||
handler,
|
||||
)
|
||||
from agent_framework.telemetry import setup_telemetry
|
||||
from opentelemetry import trace
|
||||
from agent_framework.observability import get_tracer, setup_observability
|
||||
from opentelemetry.trace import SpanKind
|
||||
from opentelemetry.trace.span import format_trace_id
|
||||
|
||||
@@ -21,6 +20,7 @@ This sample runs a simple sequential workflow with telemetry collection,
|
||||
showing telemetry collection for workflow execution, executor processing,
|
||||
and message publishing between executors.
|
||||
"""
|
||||
tracer = get_tracer("agent_framework.workflow")
|
||||
|
||||
|
||||
# Executors for sequential workflow
|
||||
@@ -65,8 +65,6 @@ async def run_sequential_workflow() -> None:
|
||||
- Message publishing between executors
|
||||
- Workflow completion events
|
||||
"""
|
||||
|
||||
tracer = trace.get_tracer(__name__)
|
||||
with tracer.start_as_current_span("Scenario: Sequential Workflow", kind=SpanKind.CLIENT) as current_span:
|
||||
print("Running scenario: Sequential Workflow")
|
||||
try:
|
||||
@@ -105,10 +103,7 @@ async def run_sequential_workflow() -> None:
|
||||
|
||||
async def main():
|
||||
"""Run the telemetry sample with a simple sequential workflow."""
|
||||
|
||||
setup_telemetry()
|
||||
|
||||
tracer = trace.get_tracer("agent_framework")
|
||||
setup_observability()
|
||||
with tracer.start_as_current_span("Sequential Workflow Scenario", kind=SpanKind.CLIENT) as current_span:
|
||||
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
|
||||
|
||||
+36
-24
@@ -1,10 +1,11 @@
|
||||
# Agent Framework Python Telemetry
|
||||
# Agent Framework Python Observability
|
||||
|
||||
This sample folder shows how a Python application can be configured to send Agent Framework telemetry to the Application Performance Management (APM) vendors of your choice.
|
||||
This sample folder shows how a Python application can be configured to send Agent Framework observability data to the Application Performance Management (APM) vendor(s) of your choice based on the Open Telemetry standard.
|
||||
|
||||
In this sample, we provide options to send telemetry to [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview) and [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash).
|
||||
In this sample, we provide options to send telemetry to [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview), [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview?tabs=bash) and the console.
|
||||
|
||||
> **Quick Start**: For local development without Azure setup, you can use the [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/standalone) which runs locally via Docker and provides an excellent telemetry viewing experience for OpenTelemetry data.
|
||||
Or you can use the built-in tracing module of the [AI Toolkit for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-windows-ai-studio.windows-ai-studio).
|
||||
|
||||
> Note that it is also possible to use other Application Performance Management (APM) vendors. An example is [Prometheus](https://prometheus.io/docs/introduction/overview/). Please refer to this [link](https://opentelemetry.io/docs/languages/python/exporters/) to learn more about exporters.
|
||||
|
||||
@@ -12,12 +13,13 @@ For more information, please refer to the following resources:
|
||||
|
||||
1. [Azure Monitor OpenTelemetry Exporter](https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/monitor/azure-monitor-opentelemetry-exporter)
|
||||
2. [Aspire Dashboard for Python Apps](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/standalone-for-python?tabs=flask%2Cwindows)
|
||||
2. [AI Toolkit for VS Code](https://marketplace.visualstudio.com/items?itemName=ms-windows-ai-studio.windows-ai-studio)
|
||||
3. [Python Logging](https://docs.python.org/3/library/logging.html)
|
||||
4. [Observability in Python](https://www.cncf.io/blog/2022/04/22/opentelemetry-and-python-a-complete-instrumentation-guide/)
|
||||
|
||||
## What to expect
|
||||
|
||||
The Agent Framework Python SDK is designed to efficiently generate comprehensive logs, traces, and metrics throughout the flow of function execution and model invocation. This allows you to effectively monitor your AI application's performance and accurately track token consumption.
|
||||
The Agent Framework Python SDK is designed to efficiently generate comprehensive logs, traces, and metrics throughout the flow of function execution and model invocation. This allows you to effectively monitor your AI application's performance and accurately track token consumption. It does so based on the Semantic Conventions for GenAI defined by OpenTelemetry, and the workflows emit their own spans to provide end-to-end visibility.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -37,17 +39,15 @@ No additional dependencies are required to enable telemetry. The necessary packa
|
||||
### Environment variables
|
||||
The following environment variables can be set to configure telemetry, the first two set the basic configuration:
|
||||
|
||||
- AGENT_FRAMEWORK_ENABLE_OTEL=true
|
||||
- AGENT_FRAMEWORK_ENABLE_SENSITIVE_DATA=true
|
||||
- ENABLE_OTEL=true
|
||||
- ENABLE_SENSITIVE_DATA=true
|
||||
|
||||
Next we need to know where to send the telemetry, for that you can use either a OTLP endpoint or a connection string for Application Insights:
|
||||
- AGENT_FRAMEWORK_OTLP_ENDPOINT="<url to OTLP endpoint>"
|
||||
- OTLP_ENDPOINT="<url to OTLP endpoint>"
|
||||
or
|
||||
- AGENT_FRAMEWORK_MONITOR_CONNECTION_STRING="<connection string>"
|
||||
- APPLICATIONINSIGHTS_CONNECTION_STRING="<connection string>"
|
||||
Finally, you can enable live metrics streaming to Application Insights:
|
||||
- AGENT_FRAMEWORK_MONITOR_LIVE_METRICS=true
|
||||
|
||||
> IMPORTANT - If both OTLP endpoint and connection string are set, the connection string will take precedence and there will be no trace to the OTLP endpoint.
|
||||
- APPLICATIONINSIGHTS_LIVE_METRICS=true
|
||||
|
||||
## Samples
|
||||
This folder contains different samples demonstrating how to use telemetry in various scenarios.
|
||||
@@ -56,11 +56,11 @@ This folder contains different samples demonstrating how to use telemetry in var
|
||||
A simple example showing how to enable telemetry in a zero-touch scenario. When the above environment variables are set, telemetry will be automatically enabled, however since you do not define any overarching tracer, you will only see the spans for the specific calls to the chat client and tools.
|
||||
|
||||
### [02a](./02a-generic_chat_client.py) and [02b](./02b-foundry_chat_client.py) Chat Clients:
|
||||
These two samples show how to first setup the telemetry by manually importing the `setup_telemetry` function from the `agent_framework.telemetry` module and calling it. After this is done, the trace that get's created will live in the same context as the chat client calls, allowing you to see the end-to-end flow of your application. For Foundry, there is a method in the Foundry project client to get the telemetry url for your project, the `.setup_foundry_telemetry()` method in the `FoundryChatClient` class will use this url to configure telemetry and you then do not have to import and call `setup_telemetry()` manually.
|
||||
Because of the way OpenTelemetry works, you can only call `setup_telemetry()` once per application run, so make sure you do that in the right place.
|
||||
These two samples show how to first setup the telemetry by manually importing the `setup_observability` function from the `agent_framework.observability` module and calling it. After this is done, the trace that get's created will live in the same context as the chat client calls, allowing you to see the end-to-end flow of your application. For Foundry, there is a method in the Foundry project client to get the azure monitor connection string for your project, the `.setup_foundry_observability()` method in the `FoundryChatClient` class will use this url to configure telemetry and you then do not have to import and call `setup_observability()` manually.
|
||||
If you or some other process already configure global tracer_providers or metrics_providers, the `setup_observability()` function will not override them, but instead use the existing tracer_provider, if possible. Metrics cannot be setup this way, so if you want to use metrics, you will have to call `setup_observability()` manually, before another process.
|
||||
|
||||
### [03a](./03a-generic_agent.py) and [03b](./03b-foundry_agent.py) Agents:
|
||||
These two samples show how to setup telemetry when using the Agent Framework's agent abstraction layer. They are similar to the chat client samples, but also show how to create an agent and invoke it. The same rules apply for setting up telemetry, you can either call `setup_telemetry()` manually, or use the `setup_foundry_telemetry()` method in the `FoundryChatClient` class.
|
||||
These two samples show how to setup telemetry when using the Agent Framework's agent abstraction layer. They are similar to the chat client samples, but also show how to create an agent and invoke it. The same rules apply for setting up telemetry, you can either call `setup_observability()` manually, or use the `setup_foundry_observability()` method in the `FoundryChatClient` class.
|
||||
|
||||
### [04 - workflow](./04-workflow.py) Workflow:
|
||||
This sample shows how to setup telemetry when using the Agent Framework's workflow execution engine. It demonstrates a simple workflow scenario with telemetry.
|
||||
@@ -68,32 +68,31 @@ This sample shows how to setup telemetry when using the Agent Framework's workfl
|
||||
|
||||
## Running the samples
|
||||
|
||||
1. Open a terminal and navigate to this folder: `python/samples/getting_started/telemetry/`. This is necessary for the `.env` file to be read correctly.
|
||||
1. Open a terminal and navigate to this folder: `python/samples/getting_started/observability/`. This is necessary for the `.env` file to be read correctly.
|
||||
2. Create a `.env` file if one doesn't already exist in this folder. Please refer to the [example file](./.env.example).
|
||||
> Note that `CONNECTION_STRING` and `SAMPLE_OTLP_ENDPOINT` are optional. If you don't configure them, everything will get outputted to the console.
|
||||
> Set `AGENT_FRAMEWORK_ENABLE_OTEL=true` to enable basic telemetry and `AGENT_FRAMEWORK_ENABLE_SENSITIVE_DATA=true` to include sensitive information like prompts and responses.
|
||||
> Note that `APPLICATIONINSIGHTS_CONNECTION_STRING` and `OTLP_ENDPOINT` are optional. If you don't configure them, everything will get outputted to the console.
|
||||
> Set `ENABLE_OTEL=true` to enable telemetry and `ENABLE_SENSITIVE_DATA=true` to include sensitive information like prompts and responses.
|
||||
> Sensitive information should only be enabled in a development or test environment. It is not recommended to enable this in production environments as it may expose sensitive data.
|
||||
> Set `AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL=true` to enable workflow telemetry for the workflow samples.
|
||||
3. Activate your python virtual environment, and then run `python 01-zero_code.py` or others.
|
||||
> This will output the Operation/Trace ID, which can be used later for filtering.
|
||||
> This will also print the Operation/Trace ID, which can be used later for filtering.
|
||||
|
||||
## Application Insights/Azure Monitor
|
||||
|
||||
### Authentication
|
||||
|
||||
You can connect to your Application Insights instance using a connection string. You can also authenticate using Entra ID by passing a [TokenCredential](https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.credentials.tokencredential?view=azure-python) to the `setup_telemetry()` function used in the samples above.
|
||||
You can connect to your Application Insights instance using a connection string. You can also authenticate using Entra ID by passing a [TokenCredential](https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.credentials.tokencredential?view=azure-python) to the `setup_observability()` function used in the samples above.
|
||||
|
||||
```python
|
||||
from azure.identity import DefaultAzureCredential
|
||||
|
||||
setup_telemetry(credential=DefaultAzureCredential())
|
||||
setup_observability(credential=DefaultAzureCredential())
|
||||
```
|
||||
|
||||
It is recommended to use [DefaultAzureCredential](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python) for local development and [ManagedIdentityCredential](https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.managedidentitycredential?view=azure-python) for production environments.
|
||||
|
||||
### Logs and traces
|
||||
|
||||
Go to your Application Insights instance, click on _Transaction search_ on the left menu. Use the operation id output by the program to search for the logs and traces associated with the operation. Click on any of the search result to view the end-to-end transaction details. Read more [here](https://learn.microsoft.com/en-us/azure/azure-monitor/app/transaction-search-and-diagnostics?tabs=transaction-search).
|
||||
Go to your Application Insights instance, click on _Transaction search_ on the left menu. Use the operation id printed by the program to search for the logs and traces associated with the operation. Click on any of the search result to view the end-to-end transaction details. Read more [here](https://learn.microsoft.com/en-us/azure/azure-monitor/app/transaction-search-and-diagnostics?tabs=transaction-search).
|
||||
|
||||
### Metrics
|
||||
|
||||
@@ -103,6 +102,19 @@ Running the application once will only generate one set of measurements (for eac
|
||||
|
||||
Please refer to here on how to analyze metrics in [Azure Monitor](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/analyze-metrics).
|
||||
|
||||
### Adding exporters
|
||||
|
||||
You can also create exporters directly and have those added to the tracer_providers, logger_providers and metrics_providers, this is useful if you want to add a different exporter on the fly, or if you want to customize the exporter. Here is an example of how to create an OTLP exporter and add it to the observability setup:
|
||||
|
||||
```python
|
||||
from grpc import Compression
|
||||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
||||
from agent_framework.observability import setup_observability
|
||||
|
||||
exporter = OTLPSpanExporter(endpoint="your-otlp-endpoint", compression=Compression.Gzip)
|
||||
setup_observability(exporters=[exporter])
|
||||
```
|
||||
|
||||
## Logs
|
||||
|
||||
When you are in Azure Monitor and want to have a overall view of the span, use this query in the logs section:
|
||||
@@ -154,13 +166,13 @@ This will start the dashboard with:
|
||||
Make sure your `.env` file includes the OTLP endpoint:
|
||||
|
||||
```bash
|
||||
AGENT_FRAMEWORK_OTLP_ENDPOINT=http://localhost:4317
|
||||
OTLP_ENDPOINT=http://localhost:4317
|
||||
```
|
||||
|
||||
Or set it as an environment variable when running your samples:
|
||||
|
||||
```bash
|
||||
AGENT_FRAMEWORK_ENABLE_OTEL=true AGENT_FRAMEWORK_OTLP_ENDPOINT=http://localhost:4317 python 01-zero_code.py
|
||||
ENABLE_OTEL=true OTLP_ENDPOINT=http://localhost:4317 python 01-zero_code.py
|
||||
```
|
||||
|
||||
### Viewing telemetry data
|
||||
@@ -0,0 +1,6 @@
|
||||
ENABLE_OTEL=true
|
||||
ENABLE_SENSITIVE_DATA=true
|
||||
OTEL_SERVICE_NAME=agent_framework
|
||||
OTEL_TRACES_EXPORTER=otlp
|
||||
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http://localhost:4317/"
|
||||
# APPLICATIONINSIGHTS_CONNECTION_STRING=""
|
||||
@@ -4,7 +4,7 @@ import asyncio
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Executor, WorkflowBuilder, WorkflowContext, handler
|
||||
from agent_framework import Executor, WorkflowBuilder, WorkflowContext, get_logger, handler
|
||||
|
||||
"""Basic tracing workflow sample.
|
||||
|
||||
@@ -14,7 +14,7 @@ A minimal two executor workflow demonstrates built in OpenTelemetry spans when d
|
||||
The sample raises an error if tracing is not configured.
|
||||
|
||||
Purpose:
|
||||
- Require diagnostics by checking AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL_DIAGNOSTICS and wiring a console exporter.
|
||||
- Require diagnostics by checking ENABLE_OTEL and wiring a console exporter.
|
||||
- Show the span categories produced by a simple graph:
|
||||
- workflow.build (events: build.started, build.validation_completed, build.completed, edge_group.process)
|
||||
- workflow.run (events: workflow.started, workflow.completed or workflow.error)
|
||||
@@ -26,32 +26,26 @@ Prerequisites:
|
||||
- No external services required for the workflow itself.
|
||||
- To print spans to the console, install the OpenTelemetry SDK: pip install opentelemetry-sdk
|
||||
- Enable diagnostics:
|
||||
configure your .env file with `AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL_DIAGNOSTICS=true` or run:
|
||||
export AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL_DIAGNOSTICS=true
|
||||
configure your .env file with `ENABLE_OTEL=true` or run:
|
||||
export ENABLE_OTEL=true
|
||||
"""
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
|
||||
def _ensure_tracing_configured() -> None:
|
||||
"""Fail fast unless diagnostics are enabled and the SDK is present.
|
||||
|
||||
If the env var is set, attach a ConsoleSpanExporter so spans print to stdout.
|
||||
"""
|
||||
env = os.getenv("AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL_DIAGNOSTICS", "").lower()
|
||||
env = os.getenv("ENABLE_OTEL", "").lower()
|
||||
if env not in {"1", "true", "yes"}:
|
||||
raise RuntimeError(
|
||||
"Tracing diagnostics are disabled. Set AGENT_FRAMEWORK_WORKFLOW_ENABLE_OTEL_DIAGNOSTICS=true "
|
||||
"and rerun the sample."
|
||||
)
|
||||
try:
|
||||
from opentelemetry import trace
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
|
||||
except Exception as exc: # pragma: no cover
|
||||
raise RuntimeError("OpenTelemetry SDK not found. Install it with: pip install opentelemetry-sdk") from exc
|
||||
logger.info("Tracing diagnostics are disabled in the env. Setting this manually here.")
|
||||
|
||||
provider = TracerProvider()
|
||||
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
|
||||
trace.set_tracer_provider(provider)
|
||||
from agent_framework.observability import setup_observability
|
||||
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
|
||||
|
||||
setup_observability(exporters=[ConsoleSpanExporter()])
|
||||
|
||||
|
||||
class StartExecutor(Executor):
|
||||
|
||||
Reference in New Issue
Block a user