Compartilhar via


Habilitar a telemetria do navegador

O painel de .NET.NET Aspire pode ser configurado para receber telemetria enviada de aplicativos do navegador. Esse recurso é útil para monitorar o desempenho do lado cliente as interações do usuário. A telemetria do navegador requer uma configuração de painel adicional e que o do SDK OTEL do JavaScript seja adicionado aos aplicativos do navegador.

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

Configuração do painel

A telemetria do navegador requer o painel para habilitar esses recursos:

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

Configuração do OTLP

O painel .NET.NET Aspire recebe telemetria por meio de endpoints OTLP. pontos de extremidade HTTP OTLP e pontos de extremidade OTLP gRPC são compatíveis com o painel. Os aplicativos de navegador devem usar HTTP OLTP para enviar telemetria para o painel porque os aplicativos do navegador não dão suporte a gRPC.

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

  • DOTNET_DASHBOARD_OTLP_ENDPOINT_URL: o endpoint gRPC ao qual o painel se conecta para obter dados.
  • DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL: o endpoint HTTP ao qual o dashboard se conecta para os seus dados.

A configuração do ponto de extremidade HTTP OTLP depende se o painel é iniciado pelo host do aplicativo ou é executado de forma autônoma.

Configurar o HTTP OTLP com o host do aplicativo

Se o painel e seu aplicativo forem iniciados pelo host do aplicativo, os pontos de extremidade OTLP do painel serão configurados no launchSettings do host do aplicativo.json arquivo.

Considere o seguinte exemplo de arquivo 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"
      }
    }
  }
}

As configurações de inicialização anteriores do arquivo JSON configuram todos os perfis para incluir a variável de ambiente DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL.

Configurar HTTP OTLP com painel autônomo

Se o painel for usado isoladamente, sem o rest de .NET Aspire, o endpoint HTTP OTLP será ativado por padrão na porta 18890. No entanto, é necessário mapear a porta ao iniciar o contêiner do painel.

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 a porta 4317 e HTTP OTLP para a porta 4318.

Configuração do CORS

Por padrão, os aplicativos do navegador são impedidos de fazer chamadas à 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 .NET.NET Aspire remove a restrição.

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

Se o painel for usado de forma autônoma, o CORS deverá 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írgulas. 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 dashboard: .NET.NET Aspire OTLP CORS.

Segurança do ponto de extremidade OTLP

Os endpoints OTLP do painel podem ser protegidos com autenticação de chave de API. Quando habilitadas, as solicitações HTTP OTLP para o painel devem incluir a chave de 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 é habilitada automaticamente quando o painel é executado no host do aplicativo. A autenticação do painel pode ser desabilitada definindo DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS para true no launchSettings do host do aplicativo.json arquivo.

Os endpoints OTLP não são seguros por padrão no painel autônomo.

Configuração de aplicativo do navegador

Um aplicativo de navegador usa o SDK OTEL JavaScript para enviar telemetria para o painel. Enviar telemetria com êxito 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, exportar rastreamento distribuído com o OTLP utiliza o pacote @opentelemetry/exporter-trace-otlp-proto.

Quando o OTLP é adicionado ao SDK, as opções OTLP devem ser especificadas. As opções OTLP incluem:

  • url: o endereço para o qual as solicitações HTTP OTLP são feitas. O endereço deve ser o endpoint HTTP OTLP do painel e o caminho para a API OTLP HTTP. Por exemplo, https://localhost:4318/v1/traces para o exportador OTLP de rastreamento. Se o host do aplicativo iniciar o aplicativo do navegador, o endpoint HTTP OTLP estará disponível a partir da variável de ambiente OTEL_EXPORTER_OTLP_ENDPOINT.

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

Metadados do navegador

Quando um aplicativo de navegador é configurado para coletar rastreamentos distribuídos, o aplicativo do navegador pode definir os intervalos pai do rastreamento de um navegador usando o elemento meta no HTML. O valor do meta elemento name="traceparent" deve corresponder ao rastreamento atual.

Em um aplicativo .NET, por exemplo, o valor do pai do rastreamento provavelmente seria atribuído a partir do Activity.Current, passando o valor do Activity.Id como 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 meta elemento traceparent para a ID da atividade atual.

Exemplo de código de telemetria do navegador

O código JavaScript a seguir demonstra a inicialização do SDK OpenTelemetry JavaScript 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 de consumo 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

O agrupamento e a minificação do código JavaScript estão além do escopo deste artigo.

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

Consulte também