启用浏览器遥测
可以将 .NET.NET Aspire 仪表板配置为接收从浏览器应用发送的遥测数据。 此功能可用于监视客户端性能和用户交互。 浏览器遥测需要额外的仪表板配置,并且需要将 JavaScript OTEL SDK 添加到浏览器应用中。
本文讨论如何在 .NET.NET Aspire 仪表板中启用浏览器遥测。
仪表板配置
浏览器遥测需要仪表板才能启用这些功能:
- OTLP HTTP 终结点。 仪表板使用此终结点从浏览器应用接收遥测数据。
- 跨域资源共享 (CORS)。 CORS 允许浏览器应用向仪表板发出请求。
OTLP 配置
.NET .NET Aspire 仪表板通过 OTLP 端点接收遥测数据。 仪表板支持 HTTP OTLP 终结点 和 gRPC OTLP 终结点。 浏览器应用必须使用 HTTP OLTP 将遥测数据发送到仪表板,因为浏览器应用不支持 gRPC。
若要配置 gPRC 或 HTTP 终结点,请指定以下环境变量:
-
DOTNET_DASHBOARD_OTLP_ENDPOINT_URL
:仪表板连接到其数据的 gRPC 终结点。 -
DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL
:仪表板用于连接其数据的 HTTP 终结点。
HTTP OTLP 终结点的配置取决于仪表板是由应用主机启动还是独立运行。
使用应用主机配置 OTLP HTTP
如果仪表板和应用由应用主机启动,则仪表板 OTLP 终结点在应用主机的 launchSettings.json 文件中配置。
请考虑以下示例 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"
}
}
}
}
上述启动设置 JSON 文件将所有配置文件配置为包括 DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL
环境变量。
使用独立仪表板配置 OTLP HTTP
如果仪表板是独立使用的,而不使用其余 .NET.NET Aspire,则默认情况下在端口 18890
上启用 OTLP HTTP 终结点。 但是,在启动仪表板容器时,必须映射端口:
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
上述命令运行仪表板容器并将 gRPC OTLP 映射到端口 4317
,将 HTTP OTLP 映射到端口 4318
。
CORS 配置
默认情况下,浏览器应用被限制为进行跨域 API 调用。 这会影响将遥测数据发送到仪表板,因为仪表板和浏览器应用始终位于不同的域中。 在 .NET.NET Aspire 仪表板中配置 CORS 会消除限制。
如果仪表板和应用由应用主机启动,则无需 CORS 配置。 .NET .NET Aspire 自动配置仪表板以允许所有资源的来源。
如果独立使用仪表板,则必须手动配置 CORS。 用于查看浏览器应用的域必须配置为允许的源,方法是在启动仪表板容器时指定 DASHBOARD__OTLP__CORS__ALLOWEDORIGINS
环境变量:
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
上述命令运行仪表板容器,并将 https://localhost:8080
配置为允许的源。 这意味着使用 https://localhost:8080
访问的浏览器应用有权发送仪表板遥测数据。
可以使用逗号分隔值允许多个源。 或者,可以使用 *
通配符允许所有源。 例如,DASHBOARD__OTLP__CORS__ALLOWEDORIGINS=*
。
有关详细信息,请参阅 .NET.NET Aspire 仪表板配置:OTLP CORS。
OTLP 终结点安全性
仪表板 OTLP 终结点可以使用 API 密钥身份验证进行保护。 启用后,向仪表板发出的 HTTP OTLP 请求必须包含 API 密钥作为 x-otlp-api-key
标头。 默认情况下,每次运行仪表板时都会生成新的 API 密钥。
从应用主机运行仪表板时,会自动启用 API 密钥身份验证。 可以通过在应用主机的 launchSettings.json 文件中将 DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS
设置为 true
来禁用仪表板身份验证。
OTLP 端点在独立仪表板中默认是不安全的。
浏览器应用配置
浏览器应用使用 JavaScript OTEL SDK 将遥测数据发送到仪表板。 成功将遥测数据发送到仪表板需要正确配置 SDK。
OTLP 导出器
OTLP 导出程序必须包含在浏览器应用中,并使用 SDK 进行配置。 例如,使用 OTLP 导出分布式跟踪时,可以使用 @opentelemetry/exporter-trace-otlp-proto 包。
将 OTLP 添加到 SDK 时,必须指定 OTLP 选项。 OTLP 选项包括:
url
:HTTP OTLP 请求的地址。 该地址应是仪表板 HTTP OTLP 终结点和 OTLP HTTP API 的路径。 例如,https://localhost:4318/v1/traces
是用于跟踪的 OTLP 导出程序。 如果浏览器应用由应用主机启动,则可从OTEL_EXPORTER_OTLP_ENDPOINT
环境变量获取 HTTP OTLP 终结点。headers
:随请求一起发送的标头。 如果启用了 OTLP 终结点 API 密钥身份验证,则必须在 OTLP 请求中发送x-otlp-api-key
标头。 如果浏览器应用由应用主机启动,则 API 密钥可从OTEL_EXPORTER_OTLP_HEADERS
环境变量获取。
浏览器元数据
当浏览器应用配置为收集分布式追踪时,浏览器应用可以通过 HTML 中的 meta
元素设置浏览器跨度的追踪父节点。
name="traceparent"
元数据元素的值应对应于当前跟踪。
例如,在 .NET 应用中,跟踪父值可能从 Activity.Current 分配,并将其 Activity.Id 值作为 content
传递。 例如,请考虑以下 Razor 代码:
<head>
@if (Activity.Current is { } currentActivity)
{
<meta name="traceparent" content="@currentActivity.Id" />
}
<!-- Other elements omitted for brevity... -->
</head>
前面的代码将 traceparent
元元素设置为当前活动 ID。
浏览器遥测代码示例
以下 JavaScript 代码演示了 OpenTelemetry JavaScript SDK 的初始化,并将遥测数据发送到仪表板:
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;
}
前面的 JavaScript 代码定义一个 initializeTelemetry
函数,该函数需要 OTLP 终结点 URL、标头和资源属性。 这些参数由使用的浏览器应用提供,该应用从应用主机设定的环境变量中提取这些参数。 请考虑以下 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>
提示
JavaScript 代码的捆绑和缩小超出了本文的范围。
有关如何将 JavaScript OTEL SDK 配置为将遥测数据发送到仪表板的完整工作示例,请参阅 浏览器遥测示例。