Skip to main content

Bring Your Own Telemetry

Endatix ships no vendor exporters. It exports OTLP and nothing else — Endatix is distributed as NuGet packages, and which APM a host reports to is the host's decision.

Adding your own backend takes three lines.

The hook

endatix.Logging.Configure(...) takes an ILoggingBuilder and runs after Endatix has set up its own providers. That ordering is the contract.

Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureEndatixWithDefaults(endatix =>
{
endatix.Logging.Configure(logging => logging.AddAzureWebAppDiagnostics());
});

var app = builder.Build();
app.UseEndatix();
app.Run();

Repeated calls compose, applying in call order.

:::warning Why not just builder.Logging.AddX()? Because it will not survive. Endatix registers logging inside IHostBuilder.ConfigureServices, which runs at Build() — and it calls ClearProviders() first, since WebApplication.CreateBuilder has already added Console, Debug, EventSource and EventLog and leaving them produces duplicated output.

Anything you add to builder.Logging before Build() is therefore discarded. The provider silently never runs; nothing errors. endatix.Logging.Configure(...) exists to give you a hook on the far side of that clear. :::

Azure Monitor / Application Insights

dotnet add package Azure.Monitor.OpenTelemetry.AspNetCore
Program.cs
builder.Host.ConfigureEndatixWithDefaults(endatix =>
{
endatix.Services.AddOpenTelemetry().UseAzureMonitor();
});

UseAzureMonitor() takes no argument. It reads APPLICATIONINSIGHTS_CONNECTION_STRING from configuration or the environment:

APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=…;IngestionEndpoint=…"

There is no Endatix key for the connection string, and you should not invent one — the Azure SDK's own resolution already covers environment variables, appsettings.json and Key Vault.

This composes with Endatix's registration rather than replacing it. Both exporters receive the same resource and the same instrumentation; if you also set OTEL_EXPORTER_OTLP_ENDPOINT, telemetry goes to both destinations.

What Application Insights costs

This is the page where you decide to switch it on, so the billing model matters more than the wiring.

Workspace-based Application Insights bills per GB ingested into its Log Analytics workspace. Analytics Logs include 31 days of retention in that price; billed size runs roughly 25% below raw JSON because some envelope fields are not charged. Live Metrics is free.

Volume is dominated by traces, not logs — and for a database-heavy API, by dependency telemetry in particular. Every EF Core query becomes a billable record. That is the line item to watch, and the reason a cost estimate based on log volume alone will be badly wrong.

Sampling is the control:

endatix.Services.AddOpenTelemetry().UseAzureMonitor(o => o.SamplingRatio = 0.1f);

or, equivalently and with higher precedence, the standard environment variables:

OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1

Environment variables win over code, so a deployment can always dial sampling down without a rebuild.

:::danger Sampling silently drops logs too By default, log records belonging to unsampled traces are dropped. A naive SamplingRatio = 0.1 therefore discards roughly 90% of your log records as well as 90% of traces — including, quite possibly, the error you are trying to diagnose.

If you want full logs with sampled traces, opt logs out of trace-based sampling explicitly. Metrics are never sampled and are unaffected. :::

Set a daily cap on the workspace as a hard ceiling. Sampling controls the average; a cap is what stops an incident-driven log storm from producing a surprise invoice.

An OTLP collector

If your backend speaks OTLP — Grafana Alloy, Datadog's OTLP endpoint, Honeycomb, Grafana Cloud, New Relic — no code is needed at all. Endatix already exports OTLP:

OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.example.com:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_SERVICE_NAME=endatix-api

For a backend needing authentication headers:

OTEL_EXPORTER_OTLP_HEADERS="api-key=…"

See Observability for a self-hosted collector configuration.

A second OTLP destination in code

To export to somewhere in addition to the endpoint Endatix already resolves:

builder.Host.ConfigureEndatixWithDefaults(endatix =>
{
endatix.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing.AddOtlpExporter(o =>
{
o.Endpoint = new Uri("https://second-backend.example.com:4317");
}));
});

AddOpenTelemetry() is additive: calling it again returns the same underlying builder, so this adds an exporter rather than replacing Endatix's. There is no duplicate registration and no resource conflict.

Choosing

You wantDo thisCost shape
Self-hosted, full controlOTLP → your own collectorInfrastructure you already run
Azure App Service logs onlyLogging.Configure(l => l.AddAzureWebAppDiagnostics())No ingestion charge
Full APM on AzureUseAzureMonitor()Per GB ingested; dependencies dominate
A SaaS APM vendorOTLP env vars, no codeVendor's per-GB or per-span pricing

If all you need is readable logs on Azure App Service, AddAzureWebAppDiagnostics() is the cheap answer: Microsoft-shipped, a plain ILogger provider, portal-configurable with no redeploy, inert outside Azure, and it incurs no Application Insights ingestion cost.

  • Observability — the OTLP contract, log levels, file logging and the local dashboard