Partilhar via


Ativar telemetria do navegador

O painel .NET.NET Aspire pode ser configurado para receber telemetria enviada a partir de aplicações do navegador. Esse recurso é útil para monitorizar o desempenho do lado cliente as interações com o utilizador. A telemetria do navegador requer configuração adicional do painel e que o JavaScript OTEL SDK seja adicionado aos aplicativos do navegador.

Este artigo descreve como habilitar a telemetria do navegador no painel .NET.NET Aspire.

Configuração do painel

A telemetria do navegador requer que o painel habilite esses recursos:

  • Ponto de extremidade HTTP OTLP. Este endpoint é usado pelo dashboard para receber telemetria de aplicações de navegador.
  • Partilha de recursos entre origens (CORS). O CORS permite que os aplicativos do navegador façam solicitações ao painel.

Configuração OTLP

O painel .NET.NET Aspire recebe telemetria através de endpoints OTLP. pontos de extremidade OTLP HTTP e pontos de extremidade OTLP gRPC são suportados pelo painel. Os aplicativos de navegador devem usar HTTP OLTP para enviar telemetria para o painel porque os aplicativos de navegador não suportam gRPC.

Para configurar os pontos de extremidade gPRC ou HTTP, especifique as seguintes variáveis de ambiente:

  • DOTNET_DASHBOARD_OTLP_ENDPOINT_URL: O ponto de extremidade gRPC ao qual o painel se conecta para os seus dados.
  • DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL: O ponto de extremidade HTTP ao qual o painel se conecta para seus dados.

A configuração do ponto de extremidade OTLP HTTP depende de o painel ser iniciado pelo servidor da aplicação ou ser executado de forma autônoma.

Configurar HTTP OTLP com o host da aplicação

Se o dashboard e a sua aplicação forem executados pelo host da aplicação, os endpoints OTLP do dashboard serão configurados no arquivo launchSettings do host da aplicação.json.

Considere o seguinte arquivo de exemplo JSON:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:15887;http://localhost:15888",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "DOTNET_ENVIRONMENT": "Development",
        "DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL": "https://localhost:16175",
        "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17037",
        "DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
      }
    },
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:15888",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "DOTNET_ENVIRONMENT": "Development",
        "DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL": "http://localhost:16175",
        "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17037",
        "DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true",
        "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
      }
    },
    "generate-manifest": {
      "commandName": "Project",
      "launchBrowser": true,
      "dotnetRunMessages": true,
      "commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
      "applicationUrl": "http://localhost:15888",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "DOTNET_ENVIRONMENT": "Development"
      }
    }
  }
}

O arquivo de configurações de inicialização anterior JSON configura todos os perfis para incluir a variável de ambiente DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL.

Configurar OTLP HTTP com painel autônomo

Se o painel for usado de forma autónoma, sem o rest de .NET Aspire, o endpoint HTTP OTLP está habilitado por padrão na porta 18890. No entanto, a porta deve ser mapeada quando o contêiner do painel é iniciado:

docker run --rm -it -d \
    -p 18888:18888 \
    -p 4317:18889 \
    -p 4318:18890 \
    --name aspire-dashboard \
    mcr.microsoft.com/dotnet/aspire-dashboard:9.0

O comando anterior executa o contêiner do painel e mapeia gRPC OTLP para porta 4317 e HTTP OTLP para porta 4318.

Configuração do CORS

Por padrão, os aplicativos do navegador são impedidos de fazer chamadas de API entre domínios. Isso afeta o envio de telemetria para o painel porque o painel e o aplicativo do navegador estão sempre em domínios diferentes. Configurar o CORS no painel do .NET.NET Aspire remove a restrição.

Se o painel e seu aplicativo forem iniciados pelo host do aplicativo, nenhuma configuração de CORS será necessária. .NET .NET Aspire configura automaticamente o painel para permitir todas as origens de recursos.

Se o painel for usado em modo standalone, o CORS deve ser configurado manualmente. O domínio usado para exibir o aplicativo do navegador deve ser configurado como uma origem permitida, especificando a variável de ambiente DASHBOARD__OTLP__CORS__ALLOWEDORIGINS quando o contêiner do painel é iniciado:

docker run --rm -it -d \
    -p 18888:18888 \
    -p 4317:18889 \
    -p 4318:18890 \
    -e DASHBOARD__OTLP__CORS__ALLOWEDORIGINS=https://localhost:8080 \
    --name aspire-dashboard \
    mcr.microsoft.com/dotnet/aspire-dashboard:9.0

O comando anterior executa o contêiner do painel e configura https://localhost:8080 como uma origem permitida. Isso significa que um aplicativo de navegador que é acessado usando https://localhost:8080 tem permissão para enviar a telemetria do painel.

Várias origens podem ser permitidas com um valor separado por vírgula. Ou todas as origens podem ser permitidas com o curinga *. Por exemplo, DASHBOARD__OTLP__CORS__ALLOWEDORIGINS=*.

Para obter mais informações, consulte a configuração do painel .NET.NET Aspire: OTLP CORS.

Segurança de ponto final OTLP

Os pontos de extremidade OTLP do painel de controlo podem ser protegidos com autenticação de chave de API. Quando habilitada, as solicitações HTTP OTLP para o painel devem incluir a chave da API como o cabeçalho x-otlp-api-key. Por padrão, uma nova chave de API é gerada sempre que o painel é executado.

A autenticação de chave de API é ativada automaticamente quando o painel é executado a partir do host do aplicativo. A autenticação do painel pode ser desativada alterando DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS para true no arquivo launchSettings do host do aplicativo.json.

Os pontos de extremidade OTLP não são protegidos por padrão no painel autônomo.

Configuração do aplicativo do navegador

Um aplicativo de navegador usa o JavaScript OTEL SDK para enviar telemetria para o painel. O envio bem-sucedido de telemetria para o painel requer que o SDK seja configurado corretamente.

Exportador OTLP

Os exportadores OTLP devem ser incluídos no aplicativo do navegador e configurados com o SDK. Por exemplo, a exportação de rastreamento distribuído com OTLP usa o pacote @opentelemetry/exporter-trace-otlp-proto.

Quando a OTLP é adicionada ao SDK, as opções de OTLP devem ser especificadas. As opções de OTLP incluem:

  • url: O endereço para o qual as solicitações HTTP OTLP são feitas. O endereço deve ser o ponto de extremidade HTTP OTLP do painel de controlo e incluir o caminho para a API HTTP OTLP. Por exemplo, https://localhost:4318/v1/traces para o exportador de traço OTLP. Se a aplicação do navegador for iniciada pelo host da aplicação, o ponto de extremidade HTTP OTLP estará disponível na variável de ambiente OTEL_EXPORTER_OTLP_ENDPOINT.

  • headers: Os cabeçalhos enviados com requisições. Se a autenticação de chave da API do ponto de extremidade OTLP estiver habilitada, o cabeçalho x-otlp-api-key deve ser enviado com as solicitações OTLP. Se o aplicativo do navegador for iniciado pelo host do aplicativo, a chave da API estará disponível na variável de ambiente OTEL_EXPORTER_OTLP_HEADERS.

Metadados do navegador

Quando uma aplicação de navegador é configurada para coletar rastreios distribuídos, a aplicação pode definir o "trace parent" dos spans de um navegador usando o elemento meta no HTML. O valor do elemento meta name="traceparent" deve corresponder ao rastreamento atual.

Em uma aplicação .NET, por exemplo, o valor de origem do rastreamento provavelmente seria atribuído a partir do Activity.Current e o seu valor Activity.Id seria passado como o content. Por exemplo, considere o seguinte código Razor:

<head>
    @if (Activity.Current is { } currentActivity)
    {
        <meta name="traceparent" content="@currentActivity.Id" />
    }
    <!-- Other elements omitted for brevity... -->
</head>

O código anterior define o elemento meta traceparent para o ID de atividade atual.

Exemplo de código de telemetria do navegador

O código JavaScript a seguir demonstra a inicialização do OpenTelemetry JavaScript SDK e o envio de dados de telemetria para o painel:

import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import { ZoneContextManager } from '@opentelemetry/context-zone';

export function initializeTelemetry(otlpUrl, headers, resourceAttributes) {
    const otlpOptions = {
        url: `${otlpUrl}/v1/traces`,
        headers: parseDelimitedValues(headers)
    };

    const attributes = parseDelimitedValues(resourceAttributes);
    attributes[SemanticResourceAttributes.SERVICE_NAME] = 'browser';

    const provider = new WebTracerProvider({
        resource: new Resource(attributes),
    });
    provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
    provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter(otlpOptions)));

    provider.register({
        // Prefer ZoneContextManager: supports asynchronous operations
        contextManager: new ZoneContextManager(),
    });

    // Registering instrumentations
    registerInstrumentations({
        instrumentations: [new DocumentLoadInstrumentation()],
    });
}

function parseDelimitedValues(s) {
    const headers = s.split(','); // Split by comma
    const result = {};

    headers.forEach(header => {
        const [key, value] = header.split('='); // Split by equal sign
        result[key.trim()] = value.trim(); // Add to the object, trimming spaces
    });

    return result;
}

O código JavaScript anterior define uma função initializeTelemetry que espera a URL do ponto de extremidade OTLP, os cabeçalhos e os atributos de recurso. Esses parâmetros são fornecidos pelo aplicativo de navegador consumidor que os extrai das variáveis de ambiente definidas pelo host do aplicativo. Considere o seguinte código Razor:

@using System.Diagnostics
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - BrowserTelemetry</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />

    @if (Activity.Current is { } currentActivity)
    {
        <meta name="traceparent" content="@currentActivity.Id" />
    }
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">BrowserTelemetry</a>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>
    @await RenderSectionAsync("Scripts", required: false)
    <script src="scripts/bundle.js"></script>
    @if (Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") is { Length: > 0 } endpointUrl)
    {
        var headers = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_HEADERS");
        var attributes = Environment.GetEnvironmentVariable("OTEL_RESOURCE_ATTRIBUTES");
        <script>
            BrowserTelemetry.initializeTelemetry('@endpointUrl', '@headers', '@attributes');
        </script>
    }
</body>
</html>

Dica

A agregação e minificação do código JavaScript está além do escopo deste artigo.

Para obter o exemplo de trabalho completo de como configurar o JavaScript OTEL SDK para enviar telemetria para o painel, consulte o exemplo de telemetria do navegador .

Ver também