.NET SDK
Install the ErrTap NuGet package for ASP.NET Core — middleware for unhandled exceptions plus manual capture and structured logs. Includes a snippet for classic ASP.NET Framework.
Install
dotnet add package ErrTapTargets .NET 8 (net8.0) and uses the ASP.NET Core shared framework, with no other dependencies.
ASP.NET Core setup
// Program.cs
using ErrTap;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddErrTap(o =>
{
o.Dsn = builder.Configuration["ErrTap:Dsn"] ?? ""; // https://et_<key>@<host>/<project>
o.Environment = builder.Environment.EnvironmentName;
o.Release = builder.Configuration["ErrTap:Release"];
});
var app = builder.Build();
app.UseErrTap(); // report unhandled exceptions, then rethrow
app.Run();// appsettings.json
{
"ErrTap": {
"Dsn": "https://et_<key>@<host>/<project>"
}
}UseErrTap() adds middleware that reports any unhandled exception and rethrows it, so your
existing error pages and logging keep working. Reports include the request path and query as
url, and the method and status: 500 as tags. If you use UseExceptionHandler or the
developer exception page, add UseErrTap() after them so exceptions reach ErrTap first.
Manual capture & logs
Inject ErrTapClient, or use the static ErrTap.ErrTap facade anywhere after setup. The
class and its namespace share a name, so qualify it (a bare ErrTap.CaptureException
resolves to the namespace and doesn't compile):
try { /* … */ }
catch (Exception ex)
{
ErrTap.ErrTap.CaptureException(ex, new Dictionary<string, object?>
{
["tags"] = new Dictionary<string, object?> { ["flow"] = "checkout" },
["user"] = new Dictionary<string, object?> { ["id"] = userId },
});
throw;
}
ErrTap.ErrTap.Info("checkout started", new Dictionary<string, object?> { ["orderId"] = id });
// also: Debug / Warning / Error / CaptureMessage
// Without DI (console apps, workers):
ErrTap.ErrTap.Init(new ErrTapOptions { Dsn = Environment.GetEnvironmentVariable("ERRTAP_DSN") ?? "" });
// Before a short-lived worker exits:
await ErrTap.ErrTap.FlushAsync();The extra dictionary accepts tags, context, user, level, fingerprint, url,
release and environment. A tags entry replaces the configured Tags for that event.
Options
| Field | Type | Description |
|---|---|---|
Dsn | string | URL DSN (https://et_<key>@<host>/<project>) or bare key (requires Endpoint) |
Endpoint | string? | Override for /ingest/error; required when Dsn is a bare key |
Environment | string | Defaults to production |
Release | string? | Ties errors to a deploy |
Tags | IDictionary<string, object?>? | Attached to events and logs that don't set their own tags |
Classic ASP.NET (Framework)
There's no NuGet package for System.Web — post directly to the ingest API from
Application_Error:
// Global.asax.cs — Application_Error (.NET Framework / System.Web)
using System;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
protected void Application_Error(object sender, EventArgs e)
{
var ex = Server.GetLastError()?.GetBaseException();
if (ex == null) return;
var json = new JavaScriptSerializer().Serialize(new
{
message = ex.Message,
type = ex.GetType().FullName,
stacktrace = ex.ToString(),
environment = "production",
});
try
{
using (var client = new HttpClient())
using (var req = new HttpRequestMessage(HttpMethod.Post, "https://your-host/ingest/error"))
{
client.Timeout = TimeSpan.FromSeconds(5);
req.Headers.TryAddWithoutValidation("Authorization", "DSN et_<your-key>");
req.Content = new StringContent(json, Encoding.UTF8, "application/json");
using (var response = client.SendAsync(req).GetAwaiter().GetResult()) { }
}
}
catch { /* telemetry must not replace the application error */ }
}See the Ingest API reference for the full payload shape.