Debugging Application Insights without a cloud subscription | Topaz
Skip to main content<br>Application Insights bugs tend to fall into one of two categories. Either the SDK sends something and you never see it in the portal - wrong connection string, wrong environment variable, telemetry initializer stripping the data - or it sends something you did not intend, and you only find out a week later when billing shows an unexpected spike. Both categories share one root cause: there is no fast, local feedback loop.
The standard debugging advice is to enable DiagnosticsTelemetryModule, or to tail the Fiddler capture, or to deploy to a dev environment and wait for the portal to ingest the data. All of those paths are slow. Some require a cloud subscription you might not have access to from the machine you are debugging on.
Topaz emulates the Application Insights ingestion API (/v2/track) and the query API (/v1/apps/{ikey}/query) locally. The SDK points at localhost, sends telemetry as it normally would, and you can query the ingested data immediately - from code, from the Topaz Portal, or from a KQL query in your terminal.
Try it yourself<br>All examples in this post work against the current stable release of Topaz.brew tap thecloudtheory/topaz && brew install topaz # macOS
curl -fsSL https://raw.githubusercontent.com/TheCloudTheory/Topaz/main/install/get-topaz.sh | bash # Linux
Application Insights docs → · Star on GitHub →
A concrete scenario
Imagine an e-commerce order service. It tracks requests, logs exceptions from the payment gateway, records a CheckoutCompleted event, and emits a PaymentLatencyMs metric. At some point someone reports that the exceptions are not appearing in the portal. The request telemetry looks fine. The metric is there. But exceptions returns nothing.
The usual investigation path involves deploying a test build to a staging environment, triggering the path that should produce an exception, waiting several minutes for the portal to ingest, and then deciding whether the absence of data means the SDK is not sending or the portal is filtering. None of that is fast, and it only works if you have credentials for staging.
With Topaz you can reproduce and fix this in one session on a laptop.
Setting up the local component
Start Topaz, create a resource group and a component:
topaz run
topaz group create --name my-rg --location eastus
topaz insights create \
--name order-service \
--resource-group my-rg \
--location eastus
Get the connection string:
topaz insights component show \
--name order-service \
--resource-group my-rg
The command returns the full component JSON. Copy the connectionString field from the properties object.
The connection string looks like a real Azure one:
InstrumentationKey=;IngestionEndpoint=https://order-service.applicationinsights.topaz.local.dev:8899/
Set it as an environment variable:
export APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=...;IngestionEndpoint=..."
Your application code reads APPLICATIONINSIGHTS_CONNECTION_STRING the same way it does in production. No code changes required.
What the SDK sends
With the standard Microsoft.ApplicationInsights NuGet package the setup is identical to production:
var config = new TelemetryConfiguration
ConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING")
};
var telemetry = new TelemetryClient(config);
// Request telemetry
telemetry.TrackRequest(
"POST /api/orders/checkout",
DateTimeOffset.UtcNow,
TimeSpan.FromMilliseconds(312),
"200",
success: true);
// Custom event
telemetry.TrackEvent("CheckoutCompleted", new Dictionary
["orderId"] = "ord-8821",
["paymentMethod"] = "card"
});
// Metric
telemetry.TrackMetric("PaymentLatencyMs", 87.4);
// Dependency - the call to the payment gateway
telemetry.TrackDependency("HTTP", "POST /charge", "payment-gateway",
DateTimeOffset.UtcNow, TimeSpan.FromMilliseconds(87), success: true);
// Exception - this is the one that was missing
try
throw new InvalidOperationException("Payment gateway timeout");
catch (Exception ex)
telemetry.TrackException(ex, new Dictionary
["orderId"] = "ord-8822",
["stage"] = "capture"
});
telemetry.Flush();
The same code works against real Azure and against Topaz. The only change is the value of APPLICATIONINSIGHTS_CONNECTION_STRING.
Querying the ingested data
Once the SDK has flushed, the data is queryable immediately. No ingestion delay, no portal caching.
From code, the query API accepts standard KQL:
var ingestionEndpoint = "https://order-service.applicationinsights.topaz.local.dev:8899";
var ikey = "";
var url = $"{ingestionEndpoint}/v1/apps/{ikey}/query";
var body = new StringContent(
"""{"query": "exceptions | order by timestamp desc | take 10"}""",
Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(url, body);
var json = await response.Content.ReadAsStringAsync();
The response schema is the same as the real...