Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье демонстрируется поддержка OpenTelemetry в функции Azure, которая обеспечивает распределенную трассировку между несколькими вызовами функций с помощью встроенной поддержки Application Insights и OpenTelemetry. Чтобы помочь вам начать работу, используется шаблон Azure Developer CLI azd для создания вашего проекта и развертывания Azure, в котором будет работать ваше приложение.
В этом руководстве вы будете использовать инструмент azd для:
- Инициализировать проект с поддержкой OpenTelemetry из шаблона.
- Просмотрите код, который включает интеграцию OpenTelemetry.
- Запустите и проверьте локальное приложение с поддержкой OpenTelemetry.
- Создайте приложение-функцию и связанные ресурсы в Azure.
- Разверните проект кода в приложении-функции в Azure.
- Проверьте распределенную трассировку в Application Insights.
Необходимые ресурсы Azure, созданные этим шаблоном, соответствуют текущим рекомендациям по безопасным и масштабируемым развертываниям приложений-функций в Azure. Эта же azd команда также развертывает проект кода в новом функциональном приложении в Azure.
По умолчанию, план потребления Flex следует модели выставления счетов с оплатой по факту использования, что означает, что выполнение этого краткого руководства может стоить вам всего несколько центов США или меньше в вашей учетной записи Azure.
Это важно
В настоящее время эта статья не поддерживает PowerShell.
Предпосылки
Учетная запись Azure с активной подпиской. Создайте учетную запись бесплатно .
- Пакет разработчиков Java (JDK), версия 11 или более поздняя
- Apache Maven, версия 3.0 или более поздняя
Инициализируйте проект
Используйте команду azd init для создания кода локального проекта Azure Functions из шаблона, включающего распределенную трассировку OpenTelemetry.
В локальном терминале или командной строке выполните следующую
azd initкоманду в пустой папке:azd init --template functions-quickstart-python-azd-otel -e flexquickstart-otelЭта команда извлекает файлы проекта из репозитория шаблонов и инициализирует проект в текущей папке. Флаг
-eзадает имя текущей среды. Вazdсреде поддерживается уникальный контекст развертывания для вашего приложения, и вы можете определить более одного контекста. Имя среды также отображается в имени группы ресурсов, создаваемой в Azure.
В локальном терминале или командной строке выполните следующую
azd initкоманду в пустой папке:azd init --template functions-quickstart-typescript-azd-otel -e flexquickstart-otelЭта команда извлекает файлы проекта из репозитория шаблонов и инициализирует проект в текущей папке. Флаг
-eзадает имя текущей среды. Вazdсреде поддерживается уникальный контекст развертывания для вашего приложения, и вы можете определить более одного контекста. Имя среды также отображается в имени группы ресурсов, создаваемой в Azure.
В локальном терминале или командной строке выполните следующую
azd initкоманду в пустой папке:azd init --template functions-quickstart-javascript-azd-otel -e flexquickstart-otelЭта команда извлекает файлы проекта из репозитория шаблонов и инициализирует проект в текущей папке. Флаг
-eзадает имя текущей среды. Вazdсреде поддерживается уникальный контекст развертывания для вашего приложения, и вы можете определить более одного контекста. Имя среды также отображается в имени группы ресурсов, создаваемой в Azure.
В локальном терминале или командной строке выполните следующую
azd initкоманду в пустой папке:azd init --template functions-quickstart-dotnet-azd-otel -e flexquickstart-otelЭта команда извлекает файлы проекта из репозитория шаблонов и инициализирует проект в текущей папке. Флаг
-eзадает имя текущей среды. Вazdсреде поддерживается уникальный контекст развертывания для вашего приложения, и вы можете определить более одного контекста. Имя среды также отображается в имени группы ресурсов, создаваемой в Azure.
В локальном терминале или командной строке выполните следующую
azd initкоманду в пустой папке:azd init --template functions-quickstart-java-azd-otel -e flexquickstart-otelЭта команда извлекает файлы проекта из репозитория шаблонов и инициализирует проект в текущей папке. Флаг
-eзадает имя текущей среды. Вazdсреде поддерживается уникальный контекст развертывания для вашего приложения, и вы можете определить более одного контекста. Имя среды также отображается в имени группы ресурсов, создаваемой в Azure.
Просмотр кода
Шаблон создает полный сценарий распределенной трассировки с тремя функциями, которые работают вместе. Просмотрите ключевые аспекты, связанные с OpenTelemetry.
Конфигурация OpenTelemetry
Файл src/otel-sample/host.json включает OpenTelemetry для узла функций:
{
"version": "2.0",
"telemetryMode": "OpenTelemetry",
"extensions": {
"serviceBus": {
"maxConcurrentCalls": 10
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
Параметр ключа "telemetryMode": "OpenTelemetry" включает распределенную трассировку между вызовами функций.
Файл host.json включает OpenTelemetry для узла функций:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
},
"telemetryMode": "OpenTelemetry"
}
Параметр ключа "telemetryMode": "OpenTelemetry" включает распределенную трассировку между вызовами функций.
Файл src/OTelSample/host.json включает OpenTelemetry для узла функций:
{
"version": "2.0",
"telemetryMode": "OpenTelemetry",
"logging": {
"OpenTelemetry": {
"logLevel": {
"Host.General": "Warning"
}
}
}
}
Параметр ключа "telemetryMode": "OpenTelemetry" включает распределенную трассировку между вызовами функций.
Зависимости для OpenTelemetry
Файл src/otel-sample/requirements.txt содержит необходимые пакеты для интеграции OpenTelemetry:
azure-functions
azure-monitor-opentelemetry
requests
Пакет azure-monitor-opentelemetry предоставляет интеграцию OpenTelemetry с Application Insights.
Файл src/otel-sample/package.json содержит необходимые пакеты для интеграции OpenTelemetry:
{
"dependencies": {
"@azure/functions": "^4.0.0",
"@azure/functions-opentelemetry-instrumentation": "^0.1.0",
"@azure/monitor-opentelemetry-exporter": "^1.0.0",
"axios": "^1.6.0"
}
}
@azure/functions-opentelemetry-instrumentation и @azure/monitor-opentelemetry-exporter пакеты обеспечивают интеграцию OpenTelemetry с Application Insights.
Файл src/otel-sample/package.json содержит необходимые пакеты для интеграции OpenTelemetry:
{
"dependencies": {
"@azure/functions": "4.7.0",
"@azure/functions-opentelemetry-instrumentation": "^0.2.0",
"@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.32",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.67.0",
"axios": "^1.12.0"
}
}
@azure/functions-opentelemetry-instrumentation и @azure/monitor-opentelemetry-exporter пакеты обеспечивают интеграцию OpenTelemetry с Application Insights. Пакет обеспечивает автоматическую инструментализацию для библиотек Node.js.
Файл .csproj содержит необходимые пакеты для интеграции OpenTelemetry:
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.OpenTelemetry" Version="1.4.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
Эти пакеты обеспечивают интеграцию OpenTelemetry с Application Insights и инструментированием HTTP для распределенной трассировки.
Файл pom.xml включает необходимые зависимости для интеграции OpenTelemetry:
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-opentelemetry</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>1.49.0</version>
</dependency>
Пакет azure-functions-java-opentelemetry предоставляет интеграцию OpenTelemetry, а opentelemetry-api пакет предоставляет основной API OpenTelemetry для распределенной трассировки.
Проект также использует плагин зависимостей Maven для скачивания Java-агента OpenTelemetry в процессе сборки.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>copy-otel-agent</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>io.opentelemetry.javaagent</groupId>
<artifactId>opentelemetry-javaagent</artifactId>
<version>2.11.0</version>
<type>jar</type>
<outputDirectory>${project.build.directory}/azure-functions/${functionAppName}</outputDirectory>
<destFileName>opentelemetry-javaagent.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
Этот агент автоматически присоединяется к среде выполнения Java для инструментирования распределенной трассировки.
Реализация функции
Функции в src/otel-sample/function_app.py демонстрируют процесс распределенного трассирования.
Первая функция HTTP
@app.function_name("first_http_function")
@app.route(route="first_http_function", auth_level=func.AuthLevel.ANONYMOUS)
def first_http_function(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function (first) processed a request.')
# Call the second function
base_url = f"{req.url.split('/api/')[0]}/api"
second_function_url = f"{base_url}/second_http_function"
response = requests.get(second_function_url)
second_function_result = response.text
result = {
"message": "Hello from the first function!",
"second_function_response": second_function_result
}
return func.HttpResponse(
json.dumps(result),
status_code=200,
mimetype="application/json"
)
Вторая функция HTTP
@app.function_name("second_http_function")
@app.route(route="second_http_function", auth_level=func.AuthLevel.ANONYMOUS)
@app.service_bus_queue_output(arg_name="outputsbmsg", queue_name="%ServiceBusQueueName%",
connection="ServiceBusConnection")
def second_http_function(req: func.HttpRequest, outputsbmsg: func.Out[str]) -> func.HttpResponse:
logging.info('Python HTTP trigger function (second) processed a request.')
message = "This is the second function responding."
# Send a message to the Service Bus queue
queue_message = "Message from second HTTP function to trigger ServiceBus queue processing"
outputsbmsg.set(queue_message)
logging.info('Sent message to ServiceBus queue: %s', queue_message)
return func.HttpResponse(
message,
status_code=200
)
Триггер очереди сервисной шины
@app.service_bus_queue_trigger(arg_name="azservicebus", queue_name="%ServiceBusQueueName%",
connection="ServiceBusConnection")
def servicebus_queue_trigger(azservicebus: func.ServiceBusMessage):
logging.info('Python ServiceBus Queue trigger start processing a message: %s',
azservicebus.get_body().decode('utf-8'))
time.sleep(5) # Simulate processing work
logging.info('Python ServiceBus Queue trigger end processing a message')
Конфигурация OpenTelemetry настроена в src/otel-sample/index.ts:
import { AzureFunctionsInstrumentation } from '@azure/functions-opentelemetry-instrumentation';
import { AzureMonitorTraceExporter, AzureMonitorLogExporter } from '@azure/monitor-opentelemetry-exporter';
import { getNodeAutoInstrumentations, getResourceDetectors } from '@opentelemetry/auto-instrumentations-node';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { detectResources } from '@opentelemetry/resources';
import { LoggerProvider, SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { NodeTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node';
const resource = detectResources({ detectors: getResourceDetectors() });
const tracerProvider = new NodeTracerProvider({
resource,
spanProcessors: [new SimpleSpanProcessor(new AzureMonitorTraceExporter())]
});
tracerProvider.register();
const loggerProvider = new LoggerProvider({
resource,
processors: [new SimpleLogRecordProcessor(new AzureMonitorLogExporter())],
});
registerInstrumentations({
tracerProvider,
loggerProvider,
instrumentations: [getNodeAutoInstrumentations(), new AzureFunctionsInstrumentation()],
});
Функции определяются в папке src/otel-sample/src/functions :
Первая функция HTTP
export async function firstHttpFunction(
request: HttpRequest,
context: InvocationContext
): Promise<HttpResponseInit> {
context.log("TypeScript HTTP trigger function (first) processed a request.");
try {
// Call the second function
const baseUrl = request.url.split("/api/")[0];
const secondFunctionUrl = `${baseUrl}/api/second_http_function`;
const response = await axios.get(secondFunctionUrl);
const secondFunctionResult = response.data;
const result = {
message: "Hello from the first function!",
second_function_response: secondFunctionResult,
};
return {
status: 200,
body: JSON.stringify(result),
headers: { "Content-Type": "application/json" },
};
} catch (error) {
return {
status: 500,
body: JSON.stringify({ error: "Failed to process request" }),
};
}
}
Вторая функция HTTP
export async function secondHttpFunction(
request: HttpRequest,
context: InvocationContext
): Promise<HttpResponseInit> {
context.log("TypeScript HTTP trigger function (second) processed a request.");
const message = "This is the second function responding.";
// Send a message to the Service Bus queue
const queueMessage =
"Message from second HTTP function to trigger ServiceBus queue processing";
context.extraOutputs.set(serviceBusOutput, queueMessage);
context.log("Sent message to ServiceBus queue:", queueMessage);
return {
status: 200,
body: message,
};
}
Триггер очереди сервисной шины
export async function serviceBusQueueTrigger(
message: unknown,
context: InvocationContext
): Promise<void> {
context.log("TypeScript ServiceBus Queue trigger start processing a message:", message);
// Simulate processing time
await new Promise((resolve) => setTimeout(resolve, 5000));
context.log("TypeScript ServiceBus Queue trigger end processing a message");
}
Конфигурация OpenTelemetry настроена в src/otel-sample/src/index.js:
const { AzureFunctionsInstrumentation } = require('@azure/functions-opentelemetry-instrumentation');
const { AzureMonitorLogExporter, AzureMonitorTraceExporter } = require('@azure/monitor-opentelemetry-exporter');
const { getNodeAutoInstrumentations, getResourceDetectors } = require('@opentelemetry/auto-instrumentations-node');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { detectResources } = require('@opentelemetry/resources');
const { LoggerProvider, SimpleLogRecordProcessor } = require('@opentelemetry/sdk-logs');
const { NodeTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-node');
const resource = detectResources({ detectors: getResourceDetectors() });
const tracerProvider = new NodeTracerProvider({
resource,
spanProcessors: [new SimpleSpanProcessor(new AzureMonitorTraceExporter())]
});
tracerProvider.register();
const loggerProvider = new LoggerProvider({
resource,
processors: [new SimpleLogRecordProcessor(new AzureMonitorLogExporter())],
});
registerInstrumentations({
tracerProvider,
loggerProvider,
instrumentations: [getNodeAutoInstrumentations(), new AzureFunctionsInstrumentation()],
});
Функции определяются в папке src/otel-sample/src/functions :
Первая функция HTTP
const { app } = require("@azure/functions");
const axios = require("axios");
async function firstHttpFunction(request, context) {
context.log("JavaScript HTTP trigger function (first) processed a request.");
try {
// Call the second function
const baseUrl = request.url.split("/api/")[0];
const secondFunctionUrl = `${baseUrl}/api/second_http_function`;
const response = await axios.get(secondFunctionUrl);
const secondFunctionResult = response.data;
const result = {
message: "Hello from the first function!",
second_function_response: secondFunctionResult,
};
context.log("Successfully called second function");
return {
status: 200,
body: JSON.stringify(result),
headers: { "Content-Type": "application/json" },
};
} catch (error) {
context.log("Error occurred:", error);
return {
status: 500,
body: JSON.stringify({ error: "Failed to process request" }),
};
}
}
app.http("first_http_function", {
methods: ["GET", "POST"],
authLevel: "anonymous",
handler: firstHttpFunction,
});
Вторая функция HTTP
const { app, output } = require("@azure/functions");
const serviceBusOutput = output.serviceBusQueue({
queueName: "%ServiceBusQueueName%",
connection: "ServiceBusConnection",
});
async function secondHttpFunction(request, context) {
context.log("JavaScript HTTP trigger function (second) processed a request.");
const message = "This is the second function responding.";
// Send a message to the Service Bus queue
const queueMessage =
"Message from second HTTP function to trigger ServiceBus queue processing";
context.extraOutputs.set(serviceBusOutput, queueMessage);
context.log("Sent message to ServiceBus queue:", queueMessage);
return {
status: 200,
body: message,
};
}
app.http("second_http_function", {
methods: ["GET", "POST"],
authLevel: "anonymous",
extraOutputs: [serviceBusOutput],
handler: secondHttpFunction,
});
Триггер очереди сервисной шины
const { app } = require("@azure/functions");
async function serviceBusQueueTrigger(message, context) {
context.log(
"JavaScript ServiceBus Queue trigger start processing a message:",
message
);
// Simulate processing time
await new Promise((resolve) => setTimeout(resolve, 5000));
context.log("JavaScript ServiceBus Queue trigger end processing a message");
}
app.serviceBusQueue("servicebus_queue_trigger", {
queueName: "%ServiceBusQueueName%",
connection: "ServiceBusConnection",
handler: serviceBusQueueTrigger,
});
Конфигурация OpenTelemetry настроена в src/OTelSample/Program.cs:
using Azure.Monitor.OpenTelemetry.Exporter;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.OpenTelemetry;
using OpenTelemetry.Trace;
var builder = FunctionsApplication.CreateBuilder(args);
builder.ConfigureFunctionsWebApplication();
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.AddHttpClientInstrumentation();
});
builder.Services.AddOpenTelemetry().UseAzureMonitorExporter();
builder.Services.AddOpenTelemetry().UseFunctionsWorkerDefaults();
builder.Services.AddHttpClient();
builder.Build().Run();
Функции определяются в отдельных файлах классов:
Первая функция HTTP
public class FirstHttpTrigger
{
private readonly ILogger<FirstHttpTrigger> _logger;
private readonly IHttpClientFactory _httpClientFactory;
public FirstHttpTrigger(ILogger<FirstHttpTrigger> logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
[Function("first_http_function")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
_logger.LogInformation("first_http_function function processed a request.");
var baseUrl = $"{req.Url.AbsoluteUri.Split("/api/")[0]}/api";
var targetUri = $"{baseUrl}/second_http_function";
var client = _httpClientFactory.CreateClient();
var response = await client.GetAsync(targetUri);
var content = await response.Content.ReadAsStringAsync();
return new OkObjectResult($"Called second_http_function, status: {response.StatusCode}, content: {content}");
}
}
Вторая функция HTTP
public class SecondHttpTrigger
{
private readonly ILogger<SecondHttpTrigger> _logger;
public SecondHttpTrigger(ILogger<SecondHttpTrigger> logger)
{
_logger = logger;
}
[Function("second_http_function")]
public MultiResponse Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
_logger.LogInformation("second_http_function function processed a request.");
return new MultiResponse
{
Messages = new string[] { "Hello" },
HttpResponse = req.CreateResponse(System.Net.HttpStatusCode.OK)
};
}
}
public class MultiResponse
{
[ServiceBusOutput("%ServiceBusQueueName%", Connection = "ServiceBusConnection")]
public string[]? Messages { get; set; }
[HttpResult]
public HttpResponseData? HttpResponse { get; set; }
}
Триггер очереди сервисной шины
public class ServiceBusQueueTrigger
{
private readonly ILogger<ServiceBusQueueTrigger> _logger;
public ServiceBusQueueTrigger(ILogger<ServiceBusQueueTrigger> logger)
{
_logger = logger;
}
[Function("servicebus_queue_trigger")]
public async Task Run(
[ServiceBusTrigger("%ServiceBusQueueName%", Connection = "ServiceBusConnection")]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions)
{
_logger.LogInformation("Message ID: {id}", message.MessageId);
_logger.LogInformation("Message Body: {body}", message.Body);
// Complete the message
await messageActions.CompleteMessageAsync(message);
}
}
Функции определяются в отдельных файлах классов Java в разделе src/main/java/com/function:
Первая функция HTTP
public class FirstHttpTrigger {
@FunctionName("first_http_function")
public HttpResponseMessage run(
@HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<String> request,
final ExecutionContext context) {
context.getLogger().info("first_http_function function processed a request.");
// Build base URI from the incoming request
URI requestUri = request.getUri();
String incomingUrl = requestUri.toString();
String baseUrl = incomingUrl.split("/api/")[0] + "/api";
String targetUri = baseUrl + "/second_http_function";
try {
var client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build();
var requestBuilder = HttpRequest.newBuilder(URI.create(targetUri))
.timeout(Duration.ofSeconds(60))
.GET();
// Get trace context from ExecutionContext and propagate it
TraceContext traceContext = context.getTraceContext();
if (traceContext != null) {
String traceparent = traceContext.getTraceparent();
String tracestate = traceContext.getTracestate();
if (traceparent != null && !traceparent.isEmpty()) {
context.getLogger().info("Propagating traceparent: " + traceparent);
requestBuilder.header("traceparent", traceparent);
}
if (tracestate != null && !tracestate.isEmpty()) {
requestBuilder.header("tracestate", tracestate);
}
}
var httpReq = requestBuilder.build();
var resp = client.send(httpReq, HttpResponse.BodyHandlers.ofString());
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "text/plain")
.body("Called second_http_function, status: " + resp.statusCode() + ", content: " + resp.body())
.build();
} catch (Exception e) {
context.getLogger().severe("Call to second_http_function failed: " + e);
return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to call second_http_function: " + e.getMessage())
.build();
}
}
}
Вторая функция HTTP
public class SecondHttpTrigger {
@FunctionName("second_http_function")
public HttpResponseMessage run(
@HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<String> request,
@ServiceBusQueueOutput(
name = "message",
queueName = "%ServiceBusQueueName%",
connection = "ServiceBusConnection")
OutputBinding<String[]> serviceBusMessages,
final ExecutionContext context) {
context.getLogger().info("second_http_function function processed a request.");
// Send message to Service Bus queue
serviceBusMessages.setValue(new String[] { "Hello" });
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "text/plain")
.body("Hello from second_http_function!")
.build();
}
}
Триггер очереди сервисной шины
public class ServiceBusQueueTriggerFunction {
@FunctionName("servicebus_queue_trigger")
public void run(
@ServiceBusQueueTrigger(
name = "message",
queueName = "%ServiceBusQueueName%",
connection = "ServiceBusConnection")
String message,
final ExecutionContext context
) {
context.getLogger().info("Message Body: " + message);
}
}
Распределенный поток трассировки
Эта архитектура создает полный сценарий распределенной трассировки с таким поведением:
- Первая функция HTTP получает HTTP-запрос и вызывает вторую функцию HTTP
- Вторая функция HTTP отвечает и отправляет сообщение в служебную шину
- Триггер служебной шины обрабатывает сообщение с задержкой для имитации работы обработки
Ключевые аспекты реализации OpenTelemetry:
-
Интеграция OpenTelemetry:
index.jsфайл настраивает OpenTelemetry с экспортерами Azure Monitor для трассировок и журналов. - Цепочка функций: первая функция вызывает вторую с помощью axios с автоматическим распространением трассировки.
- Интеграция служебной шины: вторая функция выводится в служебную шину с помощью выходных привязок, которая активирует третью функцию.
- Управляемое удостоверение: все подключения к служебной шине используют управляемое удостоверение вместо строк подключения
- Моделирование обработки: 5-секундная задержка в триггере служебной шины имитирует работу обработки сообщений
Вы можете просмотреть полный проект шаблона здесь.
-
Интеграция OpenTelemetry:
host.jsonфайл активирует OpenTelemetry с"telemetryMode": "OpenTelemetry" - Цепочка функций: первая функция вызывает вторую с помощью HTTP-запросов, создавая коррелированные трассировки.
- Интеграция служебной шины: вторая функция выводится в служебную шину, которая активирует третью функцию.
-
Анонимная проверка подлинности: используются
auth_level=func.AuthLevel.ANONYMOUSфункции HTTP, поэтому ключи функций не требуются
Вы можете просмотреть полный проект шаблона здесь.
-
Интеграция OpenTelemetry:
index.tsфайл настраивает OpenTelemetry с экспортерами Azure Monitor для трассировок и журналов. - Цепочка функций: первая функция вызывает вторую с помощью axios с автоматическим распространением трассировки.
- Интеграция служебной шины: вторая функция выводится в служебную шину с помощью выходных привязок, которая активирует третью функцию.
- Управляемое удостоверение: все подключения к служебной шине используют управляемое удостоверение вместо строк подключения
- Моделирование обработки: 5-секундная задержка в триггере служебной шины имитирует работу обработки сообщений
Вы можете просмотреть полный проект шаблона здесь.
-
Интеграция OpenTelemetry:
Program.csфайл настраивает OpenTelemetry с помощью экспортера Azure Monitor - Цепочка функций: первая функция вызывает вторую через HttpClient с инструментированием OpenTelemetry
- Интеграция служебной шины: вторая функция выводится в служебную шину с помощью выходных привязок, которая активирует третью функцию.
- Управляемое удостоверение: все подключения к служебной шине используют управляемое удостоверение вместо строк подключения
- Изолированная рабочая модель .NET 8. Использует последнюю изолированную модель рабочего процесса Azure Functions .NET для повышения производительности и гибкости.
Вы можете просмотреть полный проект шаблона здесь.
-
Интеграция OpenTelemetry:
host.jsonфайл включает OpenTelemetry и"telemetryMode": "OpenTelemetry"агент Java OpenTelemetry упаковается с развертыванием. - Цепочка функций: первая функция вызывает вторую, используя встроенный в Java HttpClient с ручной передачей контекста трассировки.
-
Распространение контекста трассировки:
ExecutionContextизTraceContextпредоставляет заголовкиtraceparentиtracestateдля распространения контекста трассировки W3C - Интеграция служебной шины: вторая функция выводится в служебную шину с помощью выходных привязок, которая активирует третью функцию.
Вы можете просмотреть полный проект шаблона здесь.
После локальной проверки функций пора опубликовать их в Azure.
Развертывание в Azure
Этот проект сконфигурирован для развертывания в новом функциональном приложении в плане Flex Consumption в Azure с поддержкой OpenTelemetry.
Подсказка
Этот проект включает набор файлов Bicep, которые azd используются для создания безопасного развертывания в плане потребления Flex, следуя передовым практикам, включая интеграцию с управляемыми удостоверениями.
Выполните команду, чтобы
azdсоздать необходимые ресурсы Azure в Azure и развернуть проект кода в новом приложении-функции:azd upКорневая папка содержит файл определения, необходимый
azure.yamlazd.Если вы еще не вошли, вам будет предложено пройти проверку подлинности с помощью учетной записи Azure.
При появлении запроса укажите следующие необходимые параметры развертывания:
Параметр Description Подписка Azure Подписка, в которой создаются ресурсы. Расположение Azure Регион Azure, в котором создается группа ресурсов, содержащая новые ресурсы Azure. Отображаются только регионы, поддерживающие план потребления Flex. Команда
azd upиспользует ответ на эти запросы с файлами конфигурации Bicep для выполнения следующих задач развертывания:Создайте и настройте эти необходимые ресурсы Azure (эквивалентно
azd provision):- Приложение функции Azure с планом Flex Consumption и поддержкой OpenTelemetry
- служба хранилища Azure (обязательно) и Application Insights (рекомендуется)
- Пространство имен и очередь Service Bus для демонстрации распределенной трассировки
- Политики и роли доступа для учетной записи
- Подключения между службами с помощью управляемых удостоверений (вместо хранимых строка подключения)
Упаковайте и разверните код в контейнере развертывания (эквивалентно
azd deploy). Затем приложение запускается и запускается в развернутом пакете.
После успешного завершения команды вы увидите ссылки на созданные ресурсы.
Тестирование распределенной трассировки
Теперь вы можете протестировать возможности распределенной трассировки OpenTelemetry, вызывая развернутые функции и наблюдая телеметрию в Application Insights.
Вызов функции в Azure
Вы можете вызвать конечные точки функций в Azure, выполнив HTTP-запросы к их URL-адресам. Так как функции HTTP в этом шаблоне настроены с анонимным доступом, вам не нужны ключи функций.
В локальном терминале или командной строке выполните следующую команду, чтобы получить имя приложения-функции и создать URL-адрес:
APP_NAME=$(azd env get-value AZURE_FUNCTION_NAME) echo "Function URL: https://$APP_NAME.azurewebsites.net/api/first_http_function"Команда
azd env get-valueполучает имя приложения-функции из локальной среды.Проверьте функцию в браузере, перейдя по URL-адресу:
https://your-function-app.azurewebsites.net/api/first_http_functionЗамените
your-function-appфактическим именем приложения-функции на предыдущем шаге. Этот один запрос создает распределенную трассировку, которая проходит через все три функции.
Просмотр распределенной трассировки в Application Insights
После вызова функции можно наблюдать полную распределенную трассировку в Application Insights:
Замечание
Может потребоваться несколько минут, чтобы данные телеметрии отображались в Application Insights после вызова функции. Если данные не отображаются немедленно, подождите несколько минут и обновите представление.
Перейдите к ресурсу Application Insights на портале Azure (его можно найти в той же группе ресурсов, что и приложение-функция).
Откройте карту приложения , чтобы увидеть распределенную трассировку во всех трех функциях. Вы должны увидеть поток от HTTP-запроса через ваши функции и до Service Bus.
Проверьте поиск транзакций , чтобы найти запрос и просмотреть полную временную шкалу трассировки. Выполните поиск транзакций в функциональном приложении.
Выберите определенную транзакцию, чтобы увидеть сквозную трассировку, которая показывает:
- HTTP-запрос на
first_http_function - Внутренний HTTP-вызов
second_http_function - Сообщение служебной шины, которое отправляется
- Обработка
servicebus_queue_triggerсообщения из Service Bus
- HTTP-запрос на
В сведениях о трассировке можно увидеть следующее:
- Сведения о времени: как долго каждый шаг занял
- Зависимости: соединения между функциями
- Логи: журналы приложений, связанные с трассировкой
- Метрики производительности: время отклика и пропускная способность
В этом примере демонстрируется сквозная распределенная трассировка для нескольких функций Azure с интеграцией OpenTelemetry, обеспечивающая полную видимость поведения и производительности приложения.
Повторное развертывание кода
Выполните команду azd up столько раз, сколько потребуется, чтобы развернуть обновления кода в функции-приложении и настроить ресурсы Azure.
Замечание
Последний пакет развертывания всегда перезаписывает развернутые файлы кода.
Ваши начальные ответы на azd запросы и любые переменные среды, которые azd генерирует, хранятся локально в вашей именованной среде.
azd env get-values Используйте команду, чтобы просмотреть все переменные в вашей среде, которые команда использует при создании ресурсов Azure.
Очистите ресурсы
Когда вы закончите работу с приложением-функцией и связанными ресурсами, используйте эту команду, чтобы удалить приложение-функцию и связанные с ним ресурсы из Azure и избежать дополнительных затрат:
azd down --no-prompt
Замечание
Параметр --no-prompt указывает azd удалить группу ресурсов без подтверждения.
Эта команда не влияет на локальный проект кода.