ErrorDock.Core
0.1.0-rc.1
dotnet add package ErrorDock.Core --version 0.1.0-rc.1
NuGet\Install-Package ErrorDock.Core -Version 0.1.0-rc.1
<PackageReference Include="ErrorDock.Core" Version="0.1.0-rc.1" />
<PackageVersion Include="ErrorDock.Core" Version="0.1.0-rc.1" />
<PackageReference Include="ErrorDock.Core" />
paket add ErrorDock.Core --version 0.1.0-rc.1
#r "nuget: ErrorDock.Core, 0.1.0-rc.1"
#:package ErrorDock.Core@0.1.0-rc.1
#addin nuget:?package=ErrorDock.Core&version=0.1.0-rc.1&prerelease
#tool nuget:?package=ErrorDock.Core&version=0.1.0-rc.1&prerelease
ErrorDock.Core
The framework-neutral core of the ErrorDock SDK for .NET. Capture, feature tracking, queueing, batching and durable delivery, sent to ErrorDock.
dotnet add package ErrorDock.Core
Targets netstandard2.0 and net8.0, so it runs on .NET Framework 4.7.2 and on .NET 8, 9
and 10 alike.
Which package do you want?
| Your application | Install |
|---|---|
| ASP.NET Core | ErrorDock.AspNetCore |
| Worker service, or a console app on the generic host | ErrorDock.Extensions.Logging |
| WinForms | ErrorDock.WinForms |
| WPF | ErrorDock.Wpf |
| Anything else — a plain console app, a plug-in, Avalonia, MAUI | this package |
Each of those depends on this one and adds the wiring for its framework. You only install
ErrorDock.Core directly when there is no such package for what you are building.
Getting started
using ErrorDock;
ErrorDockSdk.Init(options =>
{
options.ApiKey = "ed_app_…";
options.Endpoint = "https://api.errordock.com";
options.Release = typeof(Program).Assembly.GetName().Version?.ToString();
});
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
{
ErrorDockSdk.Client.CaptureException(e.ExceptionObject as Exception, level: LogEventLevel.Fatal);
ErrorDockSdk.Shutdown();
};
Init starts the flush loop, the configuration poller and the offline queue. Shutdown
sends what it can and keeps what it cannot. ErrorDockSdk.Client is safe to call before
Init and after Shutdown — it is never null and never throws.
Use an application key (ed_app_) in anything you ship to somebody else's machine. A
server key (ed_live_) is a secret, and a secret inside an installer is a secret your
customers hold.
Reporting
ErrorDockSdk.Client.CaptureException(ex, "Order could not be paid");
ErrorDockSdk.Client.CaptureMessage("Nightly run failed to reach the bank", LogEventLevel.Warning);
// A timed execution with an outcome — the denominator of the feature error rate.
var receipt = ErrorDockSdk.Client.RunFeature("checkout", () => _payments.Charge(order));
CaptureMessage obeys MinimumLogLevel — Warning by default — exactly as the ILogger
bridge does, so a message at Information is dropped unless you lower the threshold.
Exceptions are never subject to it.
using (ErrorDockScope.SetUser(user.Id))
using (ErrorDockScope.SetTag("tenant", tenant.Slug))
{
// Everything reported in here carries the user and the tag.
}
// The same two on the client, for code that holds an IErrorDockClient rather than a static.
using (client.SetUser(user.Id))
using (client.SetTag("tenant", tenant.Slug))
{
}
User identifiers are not sent unless SendUserIdentifier is turned on. Without it the
server sees a hash, which is enough to count affected people and not enough to name them.
Breadcrumbs
client.AddBreadcrumb("Coupon applied", category: "cart");
client.AddBreadcrumb("GET /prices → 503", category: "http", data: new Dictionary<string, string>
{
["provider"] = "primary",
});
The last fifty (MaxBreadcrumbs) ride along with the next error and with nothing else. One
trail for the process, not one per request: on a server the fifty most recent things that
happened anywhere are the ones that explain a crash.
The last look before it leaves
options.BeforeSend = e =>
{
if (e.Message?.Contains("card number", StringComparison.OrdinalIgnoreCase) == true)
{
return null; // drop it
}
e.Tags?.Remove("debug"); // or change it
return e;
};
BeforeSend runs after the SDK has filled in everything it can — environment, release, the
scope, the session, the breadcrumbs — and before the project's remote configuration, so it
sees the event as it would be sent and cannot get one past a rule set in the dashboard. A
hook that throws drops the event and is reported through OnInternalError.
Every event carries sdk.name and sdk.version tags, and every request a
User-Agent: errordock-dotnet/<version> header, so a bug in one SDK release is findable.
Batches are gzipped on the way out (CompressRequests, on by default); the server sniffs
the magic bytes, so nothing else changes.
The offline queue
A batch that cannot be delivered — no network, a 5xx, a quota that will reset, a process being killed — is written to disk and replayed on a later run, with its original id and timestamp intact so the server recognises it rather than storing it twice.
options.OfflineQueueEnabled = true; // the default
options.StoragePath = @"C:\ProgramData\MyApp\errordock";
options.MaxOfflineQueueBytes = 5 * 1024 * 1024;
options.OfflineQueueHorizon = TimeSpan.FromHours(24);
The default location is under the user's local application data. Set StoragePath
explicitly in a Windows Service or a container, where the account's profile directory is not
somewhere anybody would look — or is thrown away with the container.
Events older than OfflineQueueHorizon are dropped rather than sent. The server replaces
any timestamp more than 24 hours old with the time it arrived, so a crash replayed three days
late would be filed under today's date and today's release. Dropping it is the honest
outcome; sending it is a quiet lie about when it happened. Nothing is encrypted at rest: the
queue holds what was about to be sent anyway, and a key stored beside the file it protects is
decoration.
Feature flags
if (ErrorDockSdk.FeatureFlags.IsEnabled("new-checkout", userId, defaultValue: false))
{
// New implementation
}
Evaluation is local. The call reads one immutable in-memory snapshot: no network, no disk, no lock. It returns in roughly a quarter of a microsecond and it cannot throw.
The snapshot is refreshed in the background every thirty seconds with a conditional request, and every validated version is written to disk. So an application that restarts while ErrorDock is unreachable loads its last-known-good configuration before it serves its first request, and one that has never reached ErrorDock at all falls back to the default you passed in.
options.FeatureFlags.Enabled = true; // the default
options.FeatureFlags.RefreshInterval = TimeSpan.FromSeconds(30); // the default
options.FeatureFlags.PersistentCache.Enabled = true; // the default
options.FeatureFlags.PersistentCache.Path = @"C:\ProgramData\MyApp\errordock\flags";
Ask why, when the answer surprises you:
var result = ErrorDockSdk.FeatureFlags.Evaluate("new-checkout", context, defaultValue: false);
result.Reason; // percentage_rollout, explicit_target_off, flag_disabled, …
result.ConfigurationAge; // how old the configuration behind it is
result.IsUsingCachedConfiguration; // restored from disk, not fetched in this process
A change cannot reach an application that cannot reach ErrorDock. A disconnected SDK keeps its last-known-good configuration until connectivity returns — including through a kill switch. That is the trade: your application's availability comes before your configuration's freshness.
Under dependency injection, inject IErrorDockFeatureFlags rather than using the static. For
testing your own branches, ErrorDockFeatureFlags.FromSnapshot(...) hands back the real
evaluator over a snapshot you write, so there is no mock to keep in step.
What it guarantees
- It never throws. Every entry point swallows its own failures; a monitoring SDK that
breaks a customer's application is worse than no SDK at all.
OnInternalErroris there if you want to see what it swallowed. - It never blocks. Events go on a bounded queue and are sent in batches by a background sender. A full queue drops the oldest event rather than waiting.
- It gives up on purpose. A circuit breaker opens after repeated failures, so an ErrorDock outage costs you nothing but the telemetry from it.
- It brings almost no dependencies. None at all on
net8.0. Onnetstandard2.0it takesSystem.Text.Json,Microsoft.Bcl.TimeProviderandSystem.Diagnostics.DiagnosticSource, because .NET Framework has none of the three. - It follows the dashboard. With
RemoteConfigurationon, toggling data collection in your project settings changes what this SDK sends within five minutes and without a deploy. - It never makes ErrorDock a dependency of your application. Feature flags evaluate from memory, start from disk, and fall back to the default you passed in. Nothing this SDK does can stop your application starting or serving a request.
Licence
MIT. The ErrorDock service itself is proprietary; this SDK is not.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.TimeProvider (>= 8.0.1)
- System.Diagnostics.DiagnosticSource (>= 8.0.1)
- System.Text.Json (>= 8.0.6)
-
net8.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on ErrorDock.Core:
| Package | Downloads |
|---|---|
|
ErrorDock.Extensions.Logging
ErrorDock for applications built on the .NET generic host: worker services, console applications and Windows Services. Adds AddErrorDock() and an ILogger provider. For ASP.NET Core use ErrorDock.AspNetCore, which builds on this. |
|
|
ErrorDock.WinForms
ErrorDock for Windows Forms: unhandled UI-thread exceptions, crashes, sessions and feature usage, with a queue that survives a machine with no network. |
|
|
ErrorDock.Wpf
ErrorDock for WPF: unhandled dispatcher exceptions, crashes, sessions and feature usage, with a queue that survives a machine with no network. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-rc.1 | 202 | 9/9/2026 |