chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:21:23 +08:00
commit b957a53def
5423 changed files with 863745 additions and 0 deletions
@@ -0,0 +1,4 @@
TELEMETRY_SAMPLE_CONNECTION_STRING="..."
OTLP_ENDPOINT="http://localhost:4317/"
SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS=true
SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE=true
+212
View File
@@ -0,0 +1,212 @@
# Semantic Kernel Python Telemetry
This sample project shows how a Python application can be configured to send Semantic Kernel telemetry to the Application Performance Management (APM) vendors of your choice.
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 console output.
> 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.
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)
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 Semantic Kernel 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.
## Configuration
### Required resources
2. OpenAI or [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource?pivots=web-portal)
### Optional resources
1. [Application Insights](https://learn.microsoft.com/en-us/azure/azure-monitor/app/create-workspace-resource)
2. [Aspire Dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/standalone-for-python?tabs=flask%2Cwindows#start-the-aspire-dashboard)
### Dependencies
You will also need to install the following dependencies to your virtual environment to run this sample:
```
// For Azure ApplicationInsights/AzureMonitor
uv pip install azure-monitor-opentelemetry-exporter==1.0.0b24
// For OTLP endpoint
uv pip install opentelemetry-exporter-otlp-proto-grpc
```
## Running the sample
1. Open a terminal and navigate to this folder: `python/samples/demos/telemetry/`. 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 `TELEMETRY_SAMPLE_CONNECTION_STRING` and `OTLP_ENDPOINT` are optional. If you don't configure them, everything will get outputted to the console.
3. Activate your python virtual environment, and then run `python main.py`.
> This will output the Operation/Trace ID, which can be used later for filtering.
### Scenarios
This sample is organized into scenarios where the kernel will generate useful telemetry data:
- `ai_service`: This is when an AI service/connector is invoked directly (i.e. not via any kernel functions or prompts). **Information about the call to the underlying model will be recorded**.
- `kernel_function`: This is when a kernel function is invoked. **Information about the kernel function and the call to the underlying model will be recorded**.
- `auto_function_invocation`: This is when auto function invocation is triggered. **Information about the auto function invocation loop, the kernel functions that are executed, and calls to the underlying model will be recorded**.
By default, running `python main.py` will run all three scenarios. To run individual scenarios, use the `--scenario` command line argument. For example, `python main.py --scenario ai_service`. For more information, please run `python main.py -h`.
## Application Insights/Azure Monitor
### 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).
### Metrics
Running the application once will only generate one set of measurements (for each metrics). Run the application a couple times to generate more sets of measurements.
> Note: Make sure not to run the program too frequently. Otherwise, you may get throttled.
Please refer to here on how to analyze metrics in [Azure Monitor](https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/analyze-metrics).
## Aspire Dashboard
> Make sure you have the dashboard running to receive telemetry data.
Once the the sample finishes running, navigate to http://localhost:18888 in a web browser to see the telemetry data. Follow the instructions [here](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/explore) to authenticate to the dashboard and start exploring!
## Console output
You won't have to deploy an Application Insights resource or install Docker to run Aspire Dashboard if you choose to inspect telemetry data in a console. However, it is difficult to navigate through all the spans and logs produced, so **this method is only recommended when you are just getting started**.
We recommend you to get started with the `ai_service` scenario as this generates the least amount of telemetry data. Below is similar to what you will see when you run `python main.py --scenario ai_service`:
```Json
{
"name": "chat.completions gpt-4o",
"context": {
"trace_id": "0xbda1d9efcd65435653d18fa37aef7dd3",
"span_id": "0xcd443e1917510385",
"trace_state": "[]"
},
"kind": "SpanKind.INTERNAL",
"parent_id": "0xeca0a2ca7b7a8191",
"start_time": "2024-09-09T23:13:14.625156Z",
"end_time": "2024-09-09T23:13:17.311909Z",
"status": {
"status_code": "UNSET"
},
"attributes": {
"gen_ai.operation.name": "chat.completions",
"gen_ai.system": "openai",
"gen_ai.request.model": "gpt-4o",
"gen_ai.response.id": "chatcmpl-A5hrG13nhtFsOgx4ziuoskjNscHtT",
"gen_ai.response.finish_reason": "FinishReason.STOP",
"gen_ai.response.prompt_tokens": 16,
"gen_ai.response.completion_tokens": 28
},
"events": [
{
"name": "gen_ai.content.prompt",
"timestamp": "2024-09-09T23:13:14.625156Z",
"attributes": {
"gen_ai.prompt": "[{\"role\": \"user\", \"content\": \"Why is the sky blue in one sentence?\"}]"
}
},
{
"name": "gen_ai.content.completion",
"timestamp": "2024-09-09T23:13:17.311909Z",
"attributes": {
"gen_ai.completion": "[{\"role\": \"assistant\", \"content\": \"The sky appears blue because molecules in the Earth's atmosphere scatter shorter wavelengths of sunlight, such as blue, more effectively than longer wavelengths like red.\"}]"
}
}
],
"links": [],
"resource": {
"attributes": {
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": "1.26.0",
"service.name": "TelemetryExample"
},
"schema_url": ""
}
}
{
"name": "Scenario: AI Service",
"context": {
"trace_id": "0xbda1d9efcd65435653d18fa37aef7dd3",
"span_id": "0xeca0a2ca7b7a8191",
"trace_state": "[]"
},
"kind": "SpanKind.INTERNAL",
"parent_id": "0x48af7ad55f2f64b5",
"start_time": "2024-09-09T23:13:14.625156Z",
"end_time": "2024-09-09T23:13:17.312910Z",
"status": {
"status_code": "UNSET"
},
"attributes": {},
"events": [],
"links": [],
"resource": {
"attributes": {
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": "1.26.0",
"service.name": "TelemetryExample"
},
"schema_url": ""
}
}
{
"name": "main",
"context": {
"trace_id": "0xbda1d9efcd65435653d18fa37aef7dd3",
"span_id": "0x48af7ad55f2f64b5",
"trace_state": "[]"
},
"kind": "SpanKind.INTERNAL",
"parent_id": null,
"start_time": "2024-09-09T23:13:13.840481Z",
"end_time": "2024-09-09T23:13:17.312910Z",
"status": {
"status_code": "UNSET"
},
"attributes": {},
"events": [],
"links": [],
"resource": {
"attributes": {
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": "1.26.0",
"service.name": "TelemetryExample"
},
"schema_url": ""
}
}
{
"body": "OpenAI usage: CompletionUsage(completion_tokens=28, prompt_tokens=16, total_tokens=44)",
"severity_number": "<SeverityNumber.INFO: 9>",
"severity_text": "INFO",
"attributes": {
"code.filepath": "C:\\Users\\taochen\\Projects\\semantic-kernel-fork\\python\\semantic_kernel\\connectors\\ai\\open_ai\\services\\open_ai_handler.py",
"code.function": "store_usage",
"code.lineno": 81
},
"dropped_attributes": 0,
"timestamp": "2024-09-09T23:13:17.311909Z",
"observed_timestamp": "2024-09-09T23:13:17.311909Z",
"trace_id": "0xbda1d9efcd65435653d18fa37aef7dd3",
"span_id": "0xcd443e1917510385",
"trace_flags": 1,
"resource": {
"attributes": {
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": "1.26.0",
"service.name": "TelemetryExample"
},
"schema_url": ""
}
}
```
In the output, you will find three spans: `main`, `Scenario: AI Service`, and `chat.completions gpt-4o`, each representing a different layer in the sample. In particular, `chat.completions gpt-4o` is generated by the ai service. Inside it, you will find information about the call, such as the timestamp of the operation, the response id and the finish reason. You will also find sensitive information such as the prompt and response to and from the model (only if you have `SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE` set to true). If you use Application Insights or Aspire Dashboard, these information will be available to you in an interactive UI.
@@ -0,0 +1,34 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Annotated
from semantic_kernel.functions.kernel_function_decorator import kernel_function
###############################
# Plugins for demo purposes ###
###############################
class WeatherPlugin:
"""A demo plugin for getting the weather forecast."""
@kernel_function(name="get_weather", description="Get the weather forecast for a location")
def get_weather(
self,
location: Annotated[str, "The location of interest"],
) -> Annotated[str, "The weather forecast"]:
"""Get the weather forecast for a location.
Args:
location (str): The location.
"""
return f"The weather in {location} is 75°F and sunny."
class LocationPlugin:
"""A demo plugin for getting the location of a place."""
@kernel_function(name="get_current_location", description="Get the current location of the user")
def get_current_location(self) -> Annotated[str, "The current location"]:
"""Get the current location of the user."""
return "Seattle"
+167
View File
@@ -0,0 +1,167 @@
# Copyright (c) Microsoft. All rights reserved.
import argparse
import asyncio
import logging
from typing import Literal
from azure.monitor.opentelemetry.exporter import (
AzureMonitorLogExporter,
AzureMonitorMetricExporter,
AzureMonitorTraceExporter,
)
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.metrics import set_meter_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogExporter
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader
from opentelemetry.sdk.metrics.view import DropAggregation, View
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.semconv.resource import ResourceAttributes
from opentelemetry.trace import set_tracer_provider
from opentelemetry.trace.span import format_trace_id
from samples.demos.telemetry.scenarios import run_ai_service, run_auto_function_invocation, run_kernel_function
from samples.demos.telemetry.telemetry_sample_settings import TelemetrySampleSettings
# Load settings
settings = TelemetrySampleSettings()
# Create a resource to represent the service/sample
resource = Resource.create({ResourceAttributes.SERVICE_NAME: "TelemetryExample"})
# Define the scenarios that can be run
SCENARIOS = ["ai_service", "kernel_function", "auto_function_invocation", "all"]
def set_up_logging():
class KernelFilter(logging.Filter):
"""A filter to not process records from semantic_kernel."""
# These are the namespaces that we want to exclude from logging for the purposes of this demo.
namespaces_to_exclude: list[str] = [
"semantic_kernel.functions.kernel_plugin",
"semantic_kernel.prompt_template.kernel_prompt_template",
]
def filter(self, record):
return not any([record.name.startswith(namespace) for namespace in self.namespaces_to_exclude])
exporters = []
if settings.connection_string:
exporters.append(AzureMonitorLogExporter(connection_string=settings.connection_string))
if settings.otlp_endpoint:
exporters.append(OTLPLogExporter(endpoint=settings.otlp_endpoint))
if not exporters:
exporters.append(ConsoleLogExporter())
# Create and set a global logger provider for the application.
logger_provider = LoggerProvider(resource=resource)
# Log processors are initialized with an exporter which is responsible
# for sending the telemetry data to a particular backend.
for log_exporter in exporters:
logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter))
# Sets the global default logger provider
set_logger_provider(logger_provider)
# Create a logging handler to write logging records, in OTLP format, to the exporter.
handler = LoggingHandler()
# Add filters to the handler to only process records from semantic_kernel.
handler.addFilter(logging.Filter("semantic_kernel"))
handler.addFilter(KernelFilter())
# Attach the handler to the root logger. `getLogger()` with no arguments returns the root logger.
# Events from all child loggers will be processed by this handler.
logger = logging.getLogger()
logger.addHandler(handler)
# Set the logging level to NOTSET to allow all records to be processed by the handler.
logger.setLevel(logging.NOTSET)
def set_up_tracing():
exporters = []
if settings.connection_string:
exporters.append(AzureMonitorTraceExporter(connection_string=settings.connection_string))
if settings.otlp_endpoint:
exporters.append(OTLPSpanExporter(endpoint=settings.otlp_endpoint))
if not exporters:
exporters.append(ConsoleSpanExporter())
# Initialize a trace provider for the application. This is a factory for creating tracers.
tracer_provider = TracerProvider(resource=resource)
# Span processors are initialized with an exporter which is responsible
# for sending the telemetry data to a particular backend.
for exporter in exporters:
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
# Sets the global default tracer provider
set_tracer_provider(tracer_provider)
def set_up_metrics():
exporters = []
if settings.connection_string:
exporters.append(AzureMonitorMetricExporter(connection_string=settings.connection_string))
if settings.otlp_endpoint:
exporters.append(OTLPMetricExporter(endpoint=settings.otlp_endpoint))
if not exporters:
exporters.append(ConsoleMetricExporter())
# Initialize a metric provider for the application. This is a factory for creating meters.
metric_readers = [
PeriodicExportingMetricReader(metric_exporter, export_interval_millis=5000) for metric_exporter in exporters
]
meter_provider = MeterProvider(
metric_readers=metric_readers,
resource=resource,
views=[
# Dropping all instrument names except for those starting with "semantic_kernel"
View(instrument_name="*", aggregation=DropAggregation()),
View(instrument_name="semantic_kernel*"),
],
)
# Sets the global default meter provider
set_meter_provider(meter_provider)
async def main(scenario: Literal["ai_service", "kernel_function", "auto_function_invocation", "all"] = "all"):
# Set up the providers
# This must be done before any other telemetry calls
set_up_logging()
set_up_tracing()
set_up_metrics()
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("main") as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
stream = False
# Scenarios where telemetry is collected in the SDK, from the most basic to the most complex.
if scenario == "ai_service" or scenario == "all":
await run_ai_service(stream)
if scenario == "kernel_function" or scenario == "all":
await run_kernel_function(stream)
if scenario == "auto_function_invocation" or scenario == "all":
await run_auto_function_invocation(stream)
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
"--scenario",
type=str,
choices=SCENARIOS,
default="all",
help="The scenario to run. Default is all.",
)
args = arg_parser.parse_args()
asyncio.run(main(args.scenario))
@@ -0,0 +1,27 @@
# Copyright (c) Microsoft. All rights reserved.
import os
SAMPLE_PLUGIN_FOLDER = "prompt_template_samples"
def get_sample_plugin_path(max_depth: int = 10) -> str | None:
"""Find the path to the sample plugin folder.
Args:
max_depth (int, optional): The maximum depth to search for the sample plugin folder. Defaults to 10.
Returns:
str | None: The path to the sample plugin folder or None if not found.
"""
curr_dir = os.path.dirname(os.path.abspath(__file__))
found = False
for _ in range(max_depth):
if SAMPLE_PLUGIN_FOLDER in os.listdir(curr_dir):
found = True
break
curr_dir = os.path.dirname(curr_dir)
if found:
return os.path.join(curr_dir, SAMPLE_PLUGIN_FOLDER)
return None
+193
View File
@@ -0,0 +1,193 @@
# Copyright (c) Microsoft. All rights reserved.
from opentelemetry import trace
from samples.demos.telemetry.demo_plugins import LocationPlugin, WeatherPlugin
from samples.demos.telemetry.repo_utils import get_sample_plugin_path
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai.services.open_ai_chat_completion import OpenAIChatCompletion
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
from semantic_kernel.connectors.ai.text_completion_client_base import TextCompletionClientBase
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.kernel import Kernel
from semantic_kernel.services.ai_service_client_base import AIServiceClientBase
def set_up_kernel() -> Kernel:
# Create a kernel and add services and plugins
kernel = Kernel()
# All built-in AI services are instrumented with telemetry.
# Select any AI service to see the telemetry in action.
kernel.add_service(OpenAIChatCompletion(service_id="open_ai"))
# kernel.add_service(
# AzureAIInferenceChatCompletion(
# ai_model_id="serverless-deployment",
# service_id="azure-ai-inference",
# )
# )
# kernel.add_service(GoogleAIChatCompletion(service_id="google_ai"))
if (sample_plugin_path := get_sample_plugin_path()) is None:
raise FileNotFoundError("Sample plugin path not found.")
kernel.add_plugin(
plugin_name="WriterPlugin",
parent_directory=sample_plugin_path,
)
kernel.add_plugin(WeatherPlugin(), "WeatherPlugin")
kernel.add_plugin(LocationPlugin(), "LocationPlugin")
return kernel
#############################################################
# Below are scenarios that are instrumented with telemetry. #
#############################################################
async def run_ai_service(stream: bool = False) -> None:
"""Run an AI service.
This function runs an AI service and prints the output.
Telemetry will be collected for the service execution behind the scenes,
and the traces will be sent to the configured telemetry backend.
The telemetry will include information about the AI service execution.
Args:
stream (bool): Whether to use streaming for the plugin
"""
kernel = set_up_kernel()
ai_service: AIServiceClientBase = kernel.get_service()
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("Scenario: AI Service") as current_span:
print("Running scenario: AI Service")
try:
if isinstance(ai_service, ChatCompletionClientBase):
chat_history = ChatHistory()
chat_history.add_user_message("Why is the sky blue in one sentence?")
if not stream:
responses = await ai_service.get_chat_message_contents(chat_history, PromptExecutionSettings())
print(responses[0].content)
else:
async for update in ai_service.get_streaming_chat_message_contents(
chat_history, PromptExecutionSettings()
):
print(update[0].content, end="")
print()
elif isinstance(ai_service, TextCompletionClientBase):
if not stream:
completion = await ai_service.get_text_contents(
"Why is the sky blue in one sentence?", PromptExecutionSettings()
)
print(completion)
else:
async for update in ai_service.get_streaming_text_contents(
"Why is the sky blue?", PromptExecutionSettings()
):
print(update[0].content, end="")
print()
else:
raise ValueError("AI service not recognized.")
except Exception as e:
current_span.record_exception(e)
print(f"Error running AI service: {e}")
async def run_kernel_function(stream: bool = False) -> None:
"""Run a kernel function.
This function runs a kernel function and prints the output.
Telemetry will be collected for the function execution behind the scenes,
and the traces will be sent to the configured telemetry backend.
The telemetry will include information about the kernel function execution
and the AI service execution.
Args:
stream (bool): Whether to use streaming for the plugin invocation.
"""
kernel = set_up_kernel()
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("Scenario: Kernel Plugin") as current_span:
print("Running scenario: Kernel Plugin")
try:
plugin = kernel.get_plugin("WriterPlugin")
if not stream:
poem = await kernel.invoke(
function=plugin["ShortPoem"],
arguments=KernelArguments(
input="Write a poem about John Doe.",
),
)
print(f"Poem:\n{poem}")
else:
print("Poem:")
async for update in kernel.invoke_stream(
function=plugin["ShortPoem"],
arguments=KernelArguments(
input="Write a poem about John Doe.",
),
):
print(update[0].content, end="")
print()
except Exception as e:
current_span.record_exception(e)
print(f"Error running kernel plugin: {e}")
async def run_auto_function_invocation(stream: bool = False) -> None:
"""Run a task with auto function invocation.
This function runs a task with auto function invocation and prints the output.
Telemetry will be collected for the task execution behind the scenes,
and the traces will be sent to the configured telemetry backend.
The telemetry will include information about the auto function invocation loop,
the AI service execution, and the kernel function execution.
Args:
stream (bool): Whether to use streaming for the prompt.
"""
kernel = set_up_kernel()
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("Scenario: Auto Function Invocation") as current_span:
print("Running scenario: Auto Function Invocation")
try:
if not stream:
result = await kernel.invoke_prompt(
"What is the weather like in my location?",
arguments=KernelArguments(
settings=PromptExecutionSettings(
function_choice_behavior=FunctionChoiceBehavior.Auto(
filters={"excluded_plugins": ["WriterPlugin"]}
),
),
),
)
print(result)
else:
async for update in kernel.invoke_prompt_stream(
"What is the weather like in my location?",
arguments=KernelArguments(
settings=PromptExecutionSettings(
function_choice_behavior=FunctionChoiceBehavior.Auto(
filters={"excluded_plugins": ["WriterPlugin"]}
),
),
),
):
print(update[0].content, end="")
print()
except Exception as e:
current_span.record_exception(e)
print(f"Error running auto function invocation: {e}")
@@ -0,0 +1,27 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import ClassVar
from semantic_kernel.kernel_pydantic import KernelBaseSettings
class TelemetrySampleSettings(KernelBaseSettings):
"""Settings for the telemetry sample application.
Optional settings for prefix 'TELEMETRY_SAMPLE_' are:
- connection_string: str - The connection string for the Application Insights resource.
This value can be found in the Overview section when examining
your resource from the Azure portal.
(Env var TELEMETRY_SAMPLE_CONNECTION_STRING)
- otlp_endpoint: str - The OTLP endpoint to send telemetry data to.
Depending on the exporter used, you may find this value in different places.
(Env var TELEMETRY_SAMPLE_OTLP_ENDPOINT)
If no connection string or OTLP endpoint is provided, the telemetry data will be
exported to the console.
"""
env_prefix: ClassVar[str] = "TELEMETRY_SAMPLE_"
connection_string: str | None = None
otlp_endpoint: str | None = None