Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este artigo demonstra o suporte ao OpenTelemetry no Azure Function, que permite o rastreamento distribuído em várias chamadas de função usando o suporte integrado ao Application Insights e ao OpenTelemetry. Para ajudá-lo a começar, um modelo do Azure Developer CLI (azd) é usado para criar seu projeto de código, bem como a implantação do Azure na qual você executará seu aplicativo.
Neste tutorial, você usará a azd ferramenta para:
- Inicialize um projeto com suporte a OpenTelemetry a partir de um modelo.
- Examine o código que habilita a integração do OpenTelemetry.
- Execute e verifique seu aplicativo habilitado para OpenTelemetry localmente.
- Crie um aplicativo de funções e recursos relacionados no Azure.
- Implante seu projeto de código no aplicativo de funções no Azure.
- Verifique o rastreamento distribuído no Application Insights.
Os recursos necessários do Azure criados por este modelo seguem as práticas recomendadas atuais para implantações de aplicativos de funções seguras e escalonáveis no Azure. O mesmo azd comando também implanta seu projeto de código em seu novo aplicativo de funções no Azure.
Por padrão, o plano de Consumo Flexível segue um modelo de cobrança pague pelo que usar, o que significa que a conclusão deste início rápido gera um pequeno custo de alguns centavos de dólar ou menos na sua conta do Azure.
Importante
Atualmente, este artigo dá suporte apenas a C#, Python e TypeScript. Para concluir o início rápido, selecione um desses idiomas com suporte na parte superior do artigo.
Pré-requisitos
Uma conta do Azure com uma assinatura ativa. Crie uma conta gratuitamente.
Inicializar o projeto
Use o azd init comando para criar um projeto de código do Azure Functions local a partir de um modelo que inclui o rastreamento distribuído OpenTelemetry.
No seu terminal ou prompt de comando local, execute esse
azd initcomando em uma pasta vazia:azd init --template functions-quickstart-python-azd-otel -e flexquickstart-otelEsse comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O sinalizador
-edefine um nome para o ambiente atual. Emazd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também aparece no nome do grupo de recursos que você cria no Azure.
No seu terminal ou prompt de comando local, execute esse
azd initcomando em uma pasta vazia:azd init --template functions-quickstart-typescript-azd-otel -e flexquickstart-otelEsse comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O sinalizador
-edefine um nome para o ambiente atual. Emazd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também aparece no nome do grupo de recursos que você cria no Azure.
No seu terminal ou prompt de comando local, execute esse
azd initcomando em uma pasta vazia:azd init --template functions-quickstart-dotnet-azd-otel -e flexquickstart-otelEsse comando extrai os arquivos de projeto do repositório de modelos e inicializa o projeto na pasta atual. O sinalizador
-edefine um nome para o ambiente atual. Emazd, o ambiente mantém um contexto de implantação exclusivo para seu aplicativo e você pode definir mais de um. O nome do ambiente também aparece no nome do grupo de recursos que você cria no Azure.
Examine o código
O modelo cria um cenário de rastreamento distribuído completo com três funções que funcionam juntas. Vamos examinar os principais aspectos relacionados ao OpenTelemetry:
Configuração do OpenTelemetry
O src/otel-sample/host.json arquivo habilita o OpenTelemetry para o host do Functions:
{
"version": "2.0",
"telemetryMode": "OpenTelemetry",
"extensions": {
"serviceBus": {
"maxConcurrentCalls": 10
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
A configuração de chave "telemetryMode": "OpenTelemetry" habilita o rastreamento distribuído entre chamadas de função.
O src/OTelSample/host.json arquivo habilita o OpenTelemetry para o host do Functions:
{
"version": "2.0",
"telemetryMode": "OpenTelemetry",
"logging": {
"OpenTelemetry": {
"logLevel": {
"Host.General": "Warning"
}
}
}
}
A configuração chave "telemetryMode": "OpenTelemetry" permite o rastreamento distribuído entre chamadas de função.
Dependências do OpenTelemetry
O src/otel-sample/requirements.txt arquivo inclui os pacotes necessários para a integração do OpenTelemetry:
azure-functions
azure-monitor-opentelemetry
requests
O azure-monitor-opentelemetry pacote fornece a integração do OpenTelemetry com o Application Insights.
O src/otel-sample/package.json arquivo inclui os pacotes necessários para a integração do 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"
}
}
Os pacotes @azure/functions-opentelemetry-instrumentation e @azure/monitor-opentelemetry-exporter fornecem a integração do OpenTelemetry com o Application Insights.
O .csproj arquivo inclui os pacotes necessários para a integração do 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" />
Esses pacotes fornecem a integração do OpenTelemetry com o Application Insights e a instrumentação HTTP para rastreamento distribuído.
Implementação de função
As funções em src/otel-sample/function_app.py demonstram um fluxo de rastreamento distribuído:
Primeira função 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"
)
Segunda função 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
)
Gatilho da Fila do Barramento de Serviço
@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')
A configuração do OpenTelemetry está configurada em 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()],
});
As funções são definidas na src/otel-sample/src/functions pasta:
Primeira função 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" }),
};
}
}
Segunda função 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,
};
}
Gatilho da Fila do Barramento de Serviço
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");
}
A configuração do OpenTelemetry está configurada em 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();
As funções são definidas em arquivos de classe separados:
Primeira função 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}");
}
}
Segunda função 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; }
}
Gatilho da Fila do Barramento de Serviço
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);
}
}
Fluxo de rastreamento distribuído
Essa arquitetura cria um cenário de rastreamento distribuído completo, com esse comportamento:
- A primeira função HTTP recebe uma solicitação HTTP e chama a segunda função HTTP
- A segunda função HTTP responde e envia uma mensagem para o Service Bus
- O gatilho do Service Bus processa a mensagem com um atraso para simular o trabalho de processamento
Principais aspectos da implementação do OpenTelemetry:
-
Integração do OpenTelemetry: o
host.jsonarquivo habilita o OpenTelemetry com"telemetryMode": "OpenTelemetry" - Encadeamento de funções: a primeira função chama a segunda usando solicitações HTTP, criando rastreamentos correlacionados
- Integração com o Barramento de Serviço: a segunda função gera saída para o Barramento de Serviço, que aciona a terceira função
-
Autenticação anônima: as funções HTTP usam
auth_level=func.AuthLevel.ANONYMOUS, portanto, nenhuma chave de função é necessária
Você pode examinar o projeto de modelo completo aqui.
-
Integração do OpenTelemetry: o
index.tsarquivo configura o OpenTelemetry com exportadores do Azure Monitor para rastreamentos e logs - Encadeamento de funções: a primeira função chama a segunda usando o axios com propagação de rastreamento automática
- Integração do Barramento de Serviço: a segunda função envia dados para o Barramento de Serviço usando vínculos de saída, o que aciona a terceira função.
- Identidade gerenciada: Todas as conexões do Barramento de Serviço usam identidade gerenciada em vez de cadeias de conexão
- Simulação de processamento: o atraso de 5 segundos no gatilho do Barramento de Serviço simula o trabalho de processamento de mensagens
Você pode examinar o projeto de modelo completo aqui.
-
Integração do OpenTelemetry: o
Program.csarquivo configura o OpenTelemetry com o exportador do Azure Monitor - Encadeamento de funções: a primeira função chama a segunda usando HttpClient com instrumentação OpenTelemetry
- Integração com o Barramento de Serviço: a segunda função gera saída para o Barramento de Serviço usando associações de saída, que acionam a terceira função
- Identidade gerenciada: Todas as conexões do Service Bus usam identidade gerenciada em vez de cadeias de conexão
- Trabalho Isolado do .NET 8: usa o modelo de trabalho isolado do .NET do Azure Functions mais recente para melhorar o desempenho e a flexibilidade
Você pode examinar o projeto de modelo completo aqui.
Depois de verificar suas funções localmente, é hora de publicá-las no Azure.
Publicar no Azure
Este projeto está configurado para usar o comando azd up para implantar esse projeto em um novo aplicativo de funções em um plano Flex Consumption no Azure com suporte ao OpenTelemetry.
Dica
Este projeto inclui um conjunto de arquivos Bicep que azd usa para criar uma implantação segura em um plano de consumo Flexível que segue as práticas recomendadas, incluindo conexões de identidade gerenciada.
Execute este comando para que
azdcrie os recursos necessários do Azure no Azure e implante seu projeto de código no novo aplicativo de funções:azd upA pasta raiz contém o arquivo de definição
azure.yamlnecessário paraazd.Se você ainda não estiver conectado, será solicitado que você se autentique com sua conta do Azure.
Quando solicitado, forneça esses parâmetros de implantação obrigatórios:
Parâmetro Description Assinatura do Azure Assinatura na qual seus recursos serão criados. Localização do Azure Região do Azure na qual criar o grupo de recursos que contém os novos recursos do Azure. Somente regiões que atualmente dão suporte para o plano de Consumo Flex são mostradas. O comando
azd upusa sua resposta a esses prompts com os arquivos de configuração Bicep para concluir estas tarefas de implantação:Criar e configurar esses recursos do Azure necessários (equivalente a
azd provision):- Plano de Consumo Flexível do Azure Functions e aplicativo de funções com o OpenTelemetry habilitado
- Armazenamento do Microsoft Azure (obrigatório) e Application Insights (recomendado)
- Namespace e fila do Barramento de Serviço para demonstração de rastreamento distribuído
- Políticas de acesso e funções para sua conta
- Conexões de serviço a serviço usando identidades gerenciadas (em vez de cadeias de conexão armazenadas)
Empacotar e implantar seu código para o contêiner de implantação (equivalente a
azd deploy). O aplicativo é então iniciado e executa no pacote implantado.
Após o comando ser concluído com sucesso, você verá links para os recursos que criou.
Testar o rastreamento distribuído
Agora você pode testar a funcionalidade de rastreamento distribuído OpenTelemetry chamando suas funções implantadas e observando a telemetria no Application Insights.
Invocar a função no Azure
Você pode invocar seus endpoints de função no Azure realizando solicitações HTTP para suas URLs. Como as funções HTTP neste modelo são configuradas com acesso anônimo, nenhuma chave de função é necessária.
No terminal local ou no prompt de comando, execute este comando para obter o nome do aplicativo de funções e construir a URL:
APP_NAME=$(azd env get-value AZURE_FUNCTION_NAME) echo "Function URL: https://$APP_NAME.azurewebsites.net/api/first_http_function"O comando
azd env get-valueobtém o nome do seu aplicativo de funções do ambiente local.Teste a função no navegador navegando até a URL:
https://your-function-app.azurewebsites.net/api/first_http_functionSubstitua
your-function-apppelo nome real do aplicativo de funções da etapa anterior. Essa única solicitação cria um rastreamento distribuído que flui pelas três funções.
Exibir rastreamento distribuído no Application Insights
Depois de invocar a função, você pode observar o rastreamento distribuído completo no Application Insights:
Observação
Pode levar alguns minutos para que os dados de telemetria apareçam no Application Insights depois de invocar sua função. Se você não vir dados imediatamente, aguarde alguns minutos e atualize a visualização.
Acesse seu recurso do Application Insights no portal do Azure (você pode encontrá-lo no mesmo grupo de recursos que seu aplicativo de funções).
Abra o mapa do aplicativo para ver o rastreamento distribuído em todas as três funções. Você deverá ver o fluxo da solicitação HTTP por meio das funções e até o Barramento de Serviço.
Verifique a busca de transações para encontrar sua solicitação e ver o cronograma completo de rastreamento. Pesquise transações do aplicativo de funções.
Selecione uma transação específica para ver o rastreamento de ponta a ponta que mostra:
- A solicitação HTTP para
first_http_function - A chamada HTTP interna para
second_http_function - A mensagem do Barramento de Serviço que está sendo enviada
- O
servicebus_queue_triggerque está processando a mensagem do Barramento de Serviço
- A solicitação HTTP para
Nos detalhes do rastreamento, você pode ver:
- Informações de tempo: quanto tempo cada etapa demorou
- Dependências: as conexões entre funções
- Logs: registros de aplicação correlacionados com o rastreamento
- Métricas de desempenho: tempos de resposta e taxa de transferência
Este exemplo demonstra o rastreamento distribuído de ponta a ponta em várias funções do Azure com a integração do OpenTelemetry, fornecendo visibilidade completa sobre o comportamento e o desempenho do aplicativo.
Reimplantar seu código
Execute o azd up comando quantas vezes precisar para provisionar seus recursos do Azure e implantar atualizações de código em seu aplicativo de funções.
Observação
O pacote de implantação mais recente sempre substitui arquivos de código que já foram implantados.
Suas respostas iniciais aos prompts azd e quaisquer variáveis de ambiente geradas por azd são armazenadas localmente no seu ambiente nomeado. Use o azd env get-values comando para examinar todas as variáveis em seu ambiente que o comando usa ao criar recursos do Azure.
Limpar os recursos
Quando terminar de trabalhar com seu aplicativo de funções e recursos relacionados, use este comando para excluir o aplicativo de funções e seus recursos relacionados do Azure e evitar incorrer em custos adicionais:
azd down --no-prompt
Observação
A opção --no-prompt instrui azd a excluir seu grupo de recursos sem uma confirmação sua.
Este comando não afeta seu projeto de código local.