CGS.Monitor 1.1.0
CGS.Monitor for .NET
Reports errors from an ASP.NET Core application to CGS Monitor. Supports .NET 6 and later.
Install
From the CGS NuGet feed (see nuget-server/README.md to deploy it, and publish.ps1 to publish a release):
dotnet nuget add source https://<feed-host>/v3/index.json --name cgs
dotnet add package CGS.Monitor
Without the feed, build it and add the folder as a local source:
dotnet pack src/CGS.Monitor -c Release -o artifacts
dotnet nuget add source <absolute-path-to>/artifacts --name cgs-local
dotnet add package CGS.Monitor
Use an absolute path: a relative one is resolved against the NuGet config file it is saved in, and
would break every restore on the machine. The source is registered by name, so dotnet add package
needs no --source.
Use
using CGS.Monitor;
builder.Services.AddCgsMonitor(builder.Configuration); // reads the "CgsMonitor" section
// or: builder.Services.AddCgsMonitor(o => { o.Key = ...; o.Endpoint = ...; });
var app = builder.Build();
app.UseCgsMonitor(); // first is recommended; capture works before or after UseExceptionHandler
Capture by hand with ICgsMonitor:
monitor.CaptureException(ex, new CaptureOptions { Tags = new Dictionary<string, string> { ["plan"] = "pro" } });
monitor.CaptureMessage("Nightly import finished", "info");
Configuration
Keep the key out of source control: use user secrets or environment variables
(CgsMonitor__Key, CgsMonitor__Endpoint).
| Setting | Default | Meaning |
|---|---|---|
Key |
none | Secret API key of the environment. Without it nothing is sent. |
Endpoint |
none | Base address of the service, for example https://monitor.example.com. |
Release |
entry assembly version | Release shown with each event. |
Enabled |
true |
false turns every call into a no-op. |
QueueCapacity |
256 | Events waiting to be sent. When full, new events are dropped. |
BatchSize |
20 | Most events in one request. |
MaxRetries |
3 | Retries of a failed send after the first try. |
RequestTimeout |
5 s | Time limit of one request. |
ShutdownTimeout |
2 s | How long shutdown waits to send what is queued. |
IncludeSourceContext |
true |
Send the 5 lines before and after the failing line of your code's frames. |
What is sent
For an unhandled exception: the exception type, message and stack frames, its InnerException chain
(up to 5, each with its type, message and frames), the HTTP method, the
route pattern when the request matched one (never the raw path, which may hold ids or tokens, and never the query string), the response status code, the host
environment name, and the release.
Each frame has the method, the assembly, and, when the .pdb is next to the DLL, the file, line and
column. Publish the .pdb with the app (the default for dotnet publish), or embed it with
<DebugType>embedded</DebugType> in the project: without it frames still name the method, but not
the file or the line. For your own code's frames (at most 5 per exception), the 5 lines before and
after the failing line go too, read from the source file the .pdb names. That is the build
machine's path, so they appear where the source is on disk (a developer's machine, a server that
builds in place); elsewhere frames go without them. Source lines are scrubbed like any other text.
Turn them off with IncludeSourceContext = false.
Never sent: request or response headers, cookies, query strings, or bodies. Context you add by hand is scrubbed first: keys that look like secrets (password, token, api key, cookie, authorization, session and similar) are redacted, and card numbers in text are masked.
Context takes simple values (text, numbers, booleans, dates, GUIDs, enums), lists, and
dictionaries. Any other object arrives as its type name, for example [type: Order]: the client
never calls code of yours while reading it. Pass parsed values, not live objects. Reading
Request.Form itself can block on a stalled body, in your code before the SDK runs, so read it
yourself with a cancellation token and pass the values you want.
An exception's own Message is read as it is, because reporting it is the point: an override of
Message that throws loses only the message, but one that blocks would block the call, as it
would block any logger in your app first.
Failure behavior
The client never changes what your application does. Sending happens in the background, so a
slow, hanging or unreachable service does not slow requests. A full queue drops new events. No
call throws. A missing or wrong key logs a warning and the app runs on; a rejected key (401)
pauses sending for 5 minutes. Shutdown waits at most ShutdownTimeout and drops what remains.
An unhandled exception is reported and then rethrown, so your error handling and status code are
unchanged. A request cancelled by the client is not reported.
Sample
samples/CGS.Monitor.Sample has GET /health, GET /boom (throws) and POST /report.
cd samples/CGS.Monitor.Sample
dotnet user-secrets init
dotnet user-secrets set CgsMonitor:Key <your key>
dotnet user-secrets set CgsMonitor:Endpoint https://monitor.example.com
dotnet run
The sample ships Properties/launchSettings.json, which runs it as Development on
http://localhost:5187, because user secrets load only in Development. Without that profile
(for example when published), set the key with the CgsMonitor__Key environment variable instead.
No packages depend on CGS.Monitor.
.NET 6.0
- No dependencies.
| Version | Downloads | Last updated |
|---|---|---|
| 1.1.0 | 2 | 11/14/2026 |