Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra il supporto di OpenTelemetry nella funzione di Azure, che consente la traccia distribuita tra più chiamate di funzione usando il supporto integrato di Application Insights e OpenTelemetry. Per iniziare, viene usato un modello dell'interfaccia della riga di comando per sviluppatori di Azure (azd) per creare il progetto di codice e la distribuzione di Azure in cui eseguire l'app.
In questa esercitazione si usa lo azd strumento per:
- Inizializzare un progetto abilitato per OpenTelemetry da un modello.
- Esaminare il codice che abilita l'integrazione di OpenTelemetry.
- Eseguire e verificare l'app abilitata per OpenTelemetry in locale.
- Creare un'app per le funzioni e le risorse correlate in Azure.
- Distribuire il progetto di codice nell'app per le funzioni in Azure.
- Verificare la traccia distribuita in Application Insights.
Le risorse di Azure necessarie create da questo modello seguono le procedure consigliate correnti per le distribuzioni di app per le funzioni sicure e scalabili in Azure. Lo stesso comando azd distribuisce anche il progetto di codice nella nuova app per le funzioni in Azure.
Per impostazione predefinita, il piano Flex Consumption segue un modello di fatturazione con pagamento in base al consumo, il che significa che il completamento di questa guida introduttiva comporta un costo ridotto di pochi centesimi di USD o inferiore nell'account Azure.
Importante
Questo articolo supporta attualmente solo C#, Python e TypeScript. Per completare la guida introduttiva, selezionare una di queste lingue supportate nella parte superiore dell'articolo.
Prerequisiti
Un account Azure con una sottoscrizione attiva. Creare un account gratuito.
Inizializzare il progetto
Usare il azd init comando per creare un progetto di codice di Funzioni di Azure locale da un modello che include la traccia distribuita OpenTelemetry.
Nel terminale locale o nel prompt dei comandi eseguire questo comando
azd initin una cartella vuota:azd init --template functions-quickstart-python-azd-otel -e flexquickstart-otelQuesto comando esegue il pull dei file di progetto dal repository dei modelli e inizializza il progetto nella cartella corrente. Il flag
-eimposta un nome per l'ambiente corrente. Inazdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene visualizzato anche nel nome del gruppo di risorse creato in Azure.
Nel terminale locale o nel prompt dei comandi eseguire questo comando
azd initin una cartella vuota:azd init --template functions-quickstart-typescript-azd-otel -e flexquickstart-otelQuesto comando esegue il pull dei file di progetto dal repository dei modelli e inizializza il progetto nella cartella corrente. Il flag
-eimposta un nome per l'ambiente corrente. Inazdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene visualizzato anche nel nome del gruppo di risorse creato in Azure.
Nel terminale locale o nel prompt dei comandi eseguire questo comando
azd initin una cartella vuota:azd init --template functions-quickstart-dotnet-azd-otel -e flexquickstart-otelQuesto comando esegue il pull dei file di progetto dal repository dei modelli e inizializza il progetto nella cartella corrente. Il flag
-eimposta un nome per l'ambiente corrente. Inazdl'ambiente mantiene un contesto di distribuzione univoco per l'app ed è possibile definire più di uno. Il nome dell'ambiente viene visualizzato anche nel nome del gruppo di risorse creato in Azure.
Esaminare il codice
Il modello crea uno scenario di traccia distribuito completo con tre funzioni che interagiscono. Esaminiamo ora i principali aspetti correlati a OpenTelemetry:
Configurazione di OpenTelemetry
Il file src/otel-sample/host.json abilita OpenTelemetry per l'host di Funzioni:
{
"version": "2.0",
"telemetryMode": "OpenTelemetry",
"extensions": {
"serviceBus": {
"maxConcurrentCalls": 10
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
L'impostazione chiave "telemetryMode": "OpenTelemetry" abilita la traccia distribuita tra le chiamate di funzione.
Il src/OTelSample/host.json file abilita OpenTelemetry per l'host di Functions.
{
"version": "2.0",
"telemetryMode": "OpenTelemetry",
"logging": {
"OpenTelemetry": {
"logLevel": {
"Host.General": "Warning"
}
}
}
}
L'impostazione chiave "telemetryMode": "OpenTelemetry" abilita la tracciatura distribuita nelle chiamate di funzione.
Dipendenze per OpenTelemetry
Il src/otel-sample/requirements.txt file include i pacchetti necessari per l'integrazione di OpenTelemetry:
azure-functions
azure-monitor-opentelemetry
requests
Il azure-monitor-opentelemetry pacchetto fornisce l'integrazione di OpenTelemetry con Application Insights.
Il src/otel-sample/package.json file include i pacchetti necessari per l'integrazione di 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"
}
}
I @azure/functions-opentelemetry-instrumentation pacchetti e @azure/monitor-opentelemetry-exporter forniscono l'integrazione di OpenTelemetry con Application Insights.
Il .csproj file include i pacchetti necessari per l'integrazione di 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" />
Questi pacchetti forniscono l'integrazione di OpenTelemetry con Application Insights e la strumentazione HTTP per la traccia distribuita.
Implementazione della funzione
Le funzioni in src/otel-sample/function_app.py illustrano un flusso di traccia distribuita:
Prima Funzione 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"
)
Seconda funzione 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
)
Trigger coda bus di servizio
@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')
La configurazione di OpenTelemetry è configurata in 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()],
});
Le funzioni sono definite nella src/otel-sample/src/functions cartella :
Prima Funzione 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" }),
};
}
}
Seconda funzione 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,
};
}
Trigger coda bus di servizio
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");
}
La configurazione di OpenTelemetry è configurata in 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();
Le funzioni sono definite in file di classe separati:
Prima funzione 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}");
}
}
Seconda funzione 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; }
}
Trigger coda bus di servizio
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);
}
}
Flusso di tracciamento distribuito
Questa architettura crea uno scenario di traccia distribuito completo, con questo comportamento:
- La prima funzione HTTP riceve una richiesta HTTP e chiama la seconda funzione HTTP
- La seconda funzione HTTP risponde e invia un messaggio al bus di servizio
- Il trigger del bus di servizio elabora il messaggio con un ritardo per simulare il lavoro di elaborazione
Aspetti chiave dell'implementazione di OpenTelemetry:
-
Integrazione di OpenTelemetry: il
host.jsonfile abilita OpenTelemetry con"telemetryMode": "OpenTelemetry" - Concatenamento delle funzioni: la prima funzione chiama la seconda usando le richieste HTTP, creando tracce correlate
- Integrazione di Service Bus: la seconda funzione invia al Service Bus, che attiva la terza funzione
-
Autenticazione anonima: le funzioni HTTP usano
auth_level=func.AuthLevel.ANONYMOUS, quindi non sono necessarie chiavi di funzione
È possibile esaminare il progetto di modello completo qui.
-
Integrazione di OpenTelemetry: il
index.tsfile configura OpenTelemetry con gli esportatori di Azure Monitor per tracce e registri - Concatenamento delle funzioni: la prima funzione chiama il secondo usando axios con propagazione automatica della traccia
- Integrazione del bus di servizio: la seconda funzione restituisce al bus di servizio tramite associazioni di output, che attiva la terza funzione
- Identità gestita: tutte le connessioni del bus di servizio usano l'identità gestita anziché le stringhe di connessione
- Simulazione dell'elaborazione: il ritardo di 5 secondi nel trigger del Service Bus simula l'elaborazione dei messaggi
È possibile esaminare il progetto di modello completo qui.
-
Integrazione di OpenTelemetry: il file
Program.csconfigura OpenTelemetry con l'utilità di esportazione di Monitoraggio di Azure - Concatenamento delle funzioni: la prima funzione chiama il secondo usando HttpClient con la strumentazione OpenTelemetry
- Integrazione del Service Bus: la seconda funzione esporta al Service Bus tramite collegamenti di output, che attiva la terza funzione
- Identità gestita: tutte le connessioni del bus di servizio usano l'identità gestita anziché le stringhe di connessione
- Lavoro isolato .NET 8: usa il modello di lavoro isolato .NET di Funzioni di Azure più recente per migliorare le prestazioni e la flessibilità
È possibile esaminare il progetto di modello completo qui.
Dopo aver verificato le funzioni in locale, è possibile pubblicarle in Azure.
Distribuzione su Azure
Questo progetto è configurato per l'uso del comando azd up al fine di distribuire questo progetto in una nuova app per le funzioni in un piano a Consumo Flessibile con supporto OpenTelemetry in Azure.
Suggerimento
Questo progetto include un set di file Bicep che azd usa per creare una distribuzione sicura in un piano a Consumo Flessibile che segue le procedure consigliate, incluse le connessioni di identità gestite.
Eseguire questo comando affinché
azdpossa creare le risorse di Azure necessarie in Azure e distribuire il progetto di codice nella nuova app per le funzioni:azd upLa cartella radice contiene il file di definizione
azure.yamlrichiesto daazd.Se non è già stato eseguito l'accesso, viene chiesto di eseguire l'autenticazione con l'account Azure.
Quando richiesto, specificare questi parametri di distribuzione obbligatori:
Parametro Description Sottoscrizione di Azure Sottoscrizione in cui vengono create le risorse. Località di Azure Area di Azure in cui creare il gruppo di risorse che contiene le nuove risorse di Azure. Vengono visualizzate solo le aree che attualmente supportano il piano a consumo Flex. Il comando
azd upusa la risposta a queste richieste con i file di configurazione Bicep per completare queste attività di distribuzione:Creare e configurare queste risorse di Azure necessarie (equivalenti a
azd provision):- Piano a Consumo Flessibile di Funzioni di Azure e app per le funzioni con OpenTelemetry abilitato
- Archiviazione di Azure (richiesta) e Application Insights (scelta consigliata)
- Spazio dei nomi e coda del bus di servizio per la dimostrazione di traccia distribuita
- Criteri di accesso e ruoli per l'account
- Connessioni da servizio a servizio che usano identità gestite (anziché stringhe di connessione archiviate)
Creare un pacchetto e distribuire il codice nel contenitore di distribuzione (equivalente a
azd deploy). L'app viene quindi avviata ed eseguita nel pacchetto distribuito.
Al termine del comando, vengono visualizzati i collegamenti alle risorse create.
Testare il tracciamento distribuito
È ora possibile testare la funzionalità di traccia distribuita OpenTelemetry chiamando le funzioni distribuite e osservando i dati di telemetria in Application Insights.
Richiamare la funzione in Azure
È possibile richiamare gli endpoint di funzione in Azure effettuando richieste HTTP agli URL. Poiché le funzioni HTTP in questo modello sono configurate con accesso anonimo, non sono necessarie chiavi di funzione.
Nel terminale locale o nel prompt dei comandi eseguire questo comando per ottenere il nome dell'app per le funzioni e costruire l'URL:
APP_NAME=$(azd env get-value AZURE_FUNCTION_NAME) echo "Function URL: https://$APP_NAME.azurewebsites.net/api/first_http_function"Il comando
azd env get-valueottiene il nome dell'app per le funzioni dall'ambiente locale.Testare la funzione nel browser passando all'URL:
https://your-function-app.azurewebsites.net/api/first_http_functionSostituire
your-function-appcon il nome effettivo dell'app per le funzioni del passaggio precedente. Questa singola richiesta crea una traccia distribuita che scorre tutte e tre le funzioni.
Visualizzare la traccia distribuita in Application Insights
Dopo aver richiamato la funzione, è possibile osservare la traccia distribuita completa in Application Insights:
Annotazioni
La visualizzazione dei dati di telemetria in Application Insights potrebbe richiedere alcuni minuti dopo aver richiamato la funzione. Se i dati non vengono visualizzati immediatamente, attendere alcuni minuti e aggiornare la visualizzazione.
Passare alla risorsa di Application Insights nel portale di Azure (è possibile trovarla nello stesso gruppo di risorse dell'app per le funzioni).
Aprire la mappa dell'applicazione per visualizzare la traccia distribuita in tutte e tre le funzioni. Dovresti vedere il flusso dalla richiesta HTTP attraverso le tue funzioni e al Service Bus.
Controllare la ricerca transazioni per trovare la richiesta e visualizzare la sequenza temporale di traccia completa. Cercare le transazioni dall'app per le funzioni.
Selezionare una transazione specifica per visualizzare la traccia end-to-end che mostra:
- Richiesta HTTP a
first_http_function - Chiamata HTTP interna a
second_http_function - Messaggio del Service Bus in corso di invio
- L'elaborazione
servicebus_queue_triggerdel messaggio dal bus di servizio
- Richiesta HTTP a
Nei dettagli della traccia è possibile visualizzare:
- Informazioni sulla tempistica: durata di ogni passaggio
- Dipendenze: connessioni tra le funzioni
- Log: log dell'applicazione correlati alla traccia
- Metriche delle prestazioni: tempi di risposta e velocità effettiva
Questo esempio illustra la traccia distribuita end-to-end in più Funzioni di Azure con l'integrazione OpenTelemetry, offrendo visibilità completa sul comportamento e sulle prestazioni dell'applicazione.
Ridistribuire il codice
Eseguire il comando azd up quante volte è necessario per effettuare il provisioning delle risorse di Azure e distribuire gli aggiornamenti del codice nell'app per le funzioni.
Annotazioni
Il pacchetto di distribuzione più recente sovrascrive sempre i file di codice distribuiti.
Le risposte iniziali alle richieste di azd e a tutte le variabili di ambiente generate da azd, vengono archiviate localmente nell'ambiente denominato. Usare il azd env get-values comando per esaminare tutte le variabili nell'ambiente usato dal comando durante la creazione di risorse di Azure.
Pulire le risorse
Al termine dell'uso dell'app per le funzioni e delle risorse correlate, usare questo comando per eliminare l'app per le funzioni e le relative risorse da Azure ed evitare di sostenere ulteriori costi:
azd down --no-prompt
Annotazioni
L'opzione --no-prompt indica a azd di eliminare il gruppo di risorse senza conferma.
Questo comando non influisce sul progetto di codice locale.