Skip to main content

Telemetry & Monitoring

Overview​

ControlR can export telemetry via OpenTelemetry (OTLP). You can send data to an OpenTelemetry collector or the Aspire Dashboard, and it can export to Azure Monitor (Application Insights).

Both the server and the agent set up the same OpenTelemetry pipeline independently. Nothing is sent off the machine unless you configure an exporter. With no exporter configured, the instrumentation runs but no data leaves the process.

What is collected​

When an exporter is enabled, the same signals flow to whichever destination you configured.

SignalWhat is instrumented
TracesInbound ASP.NET Core HTTP requests (paths under /health are excluded), outbound HTTP client calls, and one application activity named remote_access_session, reported by the activity source ControlR.Web.Server. The viewer hub starts it when a Device Access session begins. There is no general SignalR, Entity Framework, or background-service tracing
MetricsASP.NET Core request metrics, HTTP client metrics, and .NET runtime metrics (process, GC, thread pool, CPU, memory)
LogsAnything written through Microsoft.Extensions.Logging, which includes application code and framework logs, including logs from background services

The OpenTelemetry resource carries service.name of controlr for the server and controlr-agent for the agent, with service namespace controlr. The agent also sets a host.id attribute to its device id.

Choosing a destination​

Two switches, read independently. Set either, both, or neither.

  • An OTLP endpoint. The value must be an absolute URI. When present, an OTLP gRPC exporter is registered. Only gRPC is wired up. The code does not add an OTLP HTTP exporter.
  • An Azure Monitor connection string. When present, the Azure Monitor OpenTelemetry exporter is registered.

If neither is set, no exporter is registered and no telemetry is exported.

Which endpoint variable wins​

The code reads the generic OTLP variable first and falls back to the project one:

  1. OTEL_EXPORTER_OTLP_ENDPOINT
  2. OTLP_ENDPOINT_URL (used only when OTEL_EXPORTER_OTLP_ENDPOINT is empty or unset)

So if both are set, OTEL_EXPORTER_OTLP_ENDPOINT wins. Because the exporter is only created when one of these resolves to an absolute URI, the OpenTelemetry SDK's own environment scanning is not what enables export here. These keys drive it.

Server keys versus agent keys​

The server and the agent read the same configuration keys, but through different environment providers.

  • The server reads environment variables from two providers. One carries the ControlR_ prefix, and the other is the ASP.NET Core default provider with no prefix. Set ControlR_OTLP_ENDPOINT_URL, ControlR_OTEL_EXPORTER_OTLP_ENDPOINT, and ControlR_AzureMonitor__ConnectionString. The bare forms work too, since the default provider is registered as well. The ControlR_ form wins when both are set for the same key.
  • The agent loads environment variables with no prefix. Set OTLP_ENDPOINT_URL, OTEL_EXPORTER_OTLP_ENDPOINT, and AzureMonitor__ConnectionString on the agent, or put them in the agent's appsettings.json.

Aspire Dashboard​

The Aspire Dashboard shows traces, logs, and metrics in a web UI. It is included in the Docker Compose setup. The agent exports to the same collector if you give the agent an OTLP endpoint pointing at it.

Configuration​

The bundled Compose file already enables OTLP export from the server to the Aspire container.

# docker-compose.yml
ControlR_OTLP_ENDPOINT_URL: "http://aspire:18889"
VariableDescription
ControlR_OTLP_ENDPOINT_URLOTLP gRPC endpoint. http://aspire:18889 is the Aspire container's collector port
ControlR_OTEL_EXPORTER_OTLP_ENDPOINTOverrides the value above when set
ControlR_AspireDashboard__PublicWebUrlPublic URL where the dashboard web UI is reachable, for example through your reverse proxy
ControlR_AspireDashboard__TokenThe dashboard's browser access token

The server exposes a link that opens the dashboard already signed in. The supported route is GET /api/v1/server-logs/get-aspire-url. It requires the server.telemetry.read permission.

curl https://your-server/api/v1/server-logs/get-aspire-url \
-H "x-personal-token: <tokenId>:<secret>"

Response:

{
"isConfigured": true,
"aspireUrl": "http://localhost:18888/login?t=abc123"
}

The response is a flat object with isConfigured and aspireUrl. When both ControlR_AspireDashboard__PublicWebUrl and ControlR_AspireDashboard__Token are set, aspireUrl is PublicWebUrl plus /login?t=<token>. Open it in a browser to reach the live dashboard. When either is unset, outside of Development the endpoint returns isConfigured: false and aspireUrl: null.

Azure Monitor (Application Insights)​

Set the Application Insights connection string to export the same traces, metrics, and logs to Azure Monitor.

ControlR_AzureMonitor__ConnectionString: "InstrumentationKey=...;IngestionEndpoint=https://..."

For the agent, use the unprefixed key AzureMonitor__ConnectionString.

Then explore the data in the Application Insights resource. Use Transaction Search for individual request traces, Metrics for aggregates, and Log Analytics for custom queries.

Configuration Reference​

Server keys, all read with the ControlR_ prefix.

VariableTypeDescription
ControlR_OTEL_EXPORTER_OTLP_ENDPOINTstring?Preferred OTLP gRPC endpoint. Checked first
ControlR_OTLP_ENDPOINT_URLstring?Fallback OTLP gRPC endpoint, used when the one above is unset
ControlR_AzureMonitor__ConnectionStringstring?Azure Monitor / Application Insights connection string
ControlR_AspireDashboard__PublicWebUrlUri?Public URL for the Aspire Dashboard web UI
ControlR_AspireDashboard__Tokenstring?Browser access token for the Aspire Dashboard

The agent uses the same keys without the prefix: OTEL_EXPORTER_OTLP_ENDPOINT, OTLP_ENDPOINT_URL, and AzureMonitor__ConnectionString.

Data Privacy​

Nothing is sent to a third party by default. The only destinations are the OTLP endpoint and the Azure Monitor connection string you supply.

The bundled Compose file points the server's OTLP export at the local Aspire container. That traffic stays on your infrastructure. Point the endpoint at an external collector, or set the Azure Monitor connection string, when you want data to leave the box.

Next​