-
-
Notifications
You must be signed in to change notification settings - Fork 207
/
Program.cs
181 lines (152 loc) · 7.12 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
using System;
using System.Reflection;
using System.Threading.Tasks;
using Sentry;
using Sentry.Extensibility;
using Sentry.Protocol;
using Sentry.Samples.Console.Customized;
// One of the ways to set your DSN is via an attribute:
// It could be set via AssemblyInfo.cs and patched via CI.
// Other ways are via environment variable, configuration files and explictly via parameter to Init
[assembly: Dsn(Program.DefaultDsn)]
// Tracks the release which sent the event and enables more features: https://docs.sentry.io/learn/releases/
// Much like the DSN above, this is only one of the ways to define the release.
// If not set here, it can also be defined via appsettings.json, environment variable 'SENTRY_RELEASE' and AssemblyVersion
// STANDARD_CI_SOURCE_REVISION_ID -> TeamCity: %build.vcs.number%, VSTS: BUILD_SOURCEVERSION, Travis-CI: TRAVIS_COMMIT, AppVeyor: APPVEYOR_REPO_COMMIT, CircleCI: CIRCLE_SHA1
[assembly: AssemblyInformationalVersion("e386dfd")]
namespace Sentry.Samples.Console.Customized
{
internal static class Program
{
public const string DefaultDsn = "https://5fd7a6cda8444965bade9ccfd3df9882@sentry.io/1188141";
// A different DSN for a section of the app (i.e: admin)
public const string AdminDsn = "https://f670c444cca14cf2bb4bfc403525b6a3@sentry.io/259314";
private static async Task Main(string[] args)
{
// When the SDK is disabled, no callback is executed:
await SentrySdk.ConfigureScopeAsync(async scope =>
{
// Never executed:
// This could be any async I/O operation, like a DB query
await Task.Yield();
scope.SetExtra("Key", "Value");
});
// Enable the SDK
using (SentrySdk.Init(o =>
{
o.AddEventProcessor(new SomeEventProcessor());
o.AddExceptionProcessor(new ArgumentExceptionProcessor());
// Modifications to event before it goes out. Could replace the event altogether
o.BeforeSend = @event =>
{
// Drop an event altogether:
if (@event.Tags.ContainsKey("SomeTag"))
{
return null;
}
return @event;
};
// Configure the background worker which sends events to sentry:
o.Worker(w =>
{
// Wait up to 5 seconds before shutdown while there are events to send.
w.ShutdownTimeout = TimeSpan.FromSeconds(5);
});
o.Http(h =>
{
// Using a proxy:
h.Proxy = null; //new WebProxy("https://localhost:3128");
});
}))
{
await SentrySdk.ConfigureScopeAsync(async scope =>
{
// This could be any async I/O operation, like a DB query
await Task.Yield();
scope.SetExtra("SomeExtraInfo",
new
{
Data = "Value fetched asynchronously",
ManaLevel = 199
});
});
SentrySdk.CaptureMessage("Some warning!", SentryLevel.Warning);
var error = new Exception("Attempting to send this multiple times");
// Only the first capture will be sent to Sentry
for (int i = 0; i < 100; i++)
{
// The SDK is able to detect duplicate events:
// This is useful, for example, when multiple loggers log the same exception. Or exception is re-thrown and recaptured.
SentrySdk.CaptureException(error);
}
// -------------------------
// A custom made client, that could be registered with DI,
// would get disposed by the container on app shutdown
SentrySdk.CaptureMessage("Starting new client");
// Using a different DSN:
var adminDsn = new Dsn(AdminDsn);
using (var adminClient = new SentryClient(new SentryOptions { Dsn = adminDsn }))
{
// Make believe web framework middleware
var middleware = new AdminPartMiddleware(adminClient, null);
var request = new { Path = "/admin" }; // made up request
middleware.Invoke(request);
} // Dispose the client which flushes any queued events
SentrySdk.CaptureException(
new Exception("Error outside of the admin section: Goes to the default DSN"));
} // On Dispose: SDK closed, events queued are flushed/sent to Sentry
}
private class AdminPartMiddleware
{
private readonly ISentryClient _adminClient;
private readonly dynamic _middleware;
public AdminPartMiddleware(ISentryClient adminClient, dynamic middleware)
{
_adminClient = adminClient;
_middleware = middleware;
}
public void Invoke(dynamic request)
{
using (SentrySdk.PushScope())
{
SentrySdk.AddBreadcrumb(request.Path, "request-path");
// Change the SentryClient in case the request is to the admin part:
if (request.Path.StartsWith("/admin"))
{
// Within this scope, the _adminClient will be used instead of whatever
// client was defined before this point:
SentrySdk.BindClient(_adminClient);
}
SentrySdk.CaptureException(new Exception("Error at the admin section"));
// Else it uses the default client
_middleware?.Invoke(request);
} // Scope is disposed.
}
}
private class SomeEventProcessor : ISentryEventProcessor
{
public SentryEvent Process(SentryEvent @event)
{
// Here you can modify the event as you need
if (@event.Level > SentryLevel.Info)
{
@event.AddBreadcrumb("Processed by " + nameof(SomeEventProcessor));
@event.User = new User
{
Username = Environment.UserName
};
@event.ServerName = Environment.MachineName;
}
return @event;
}
}
private class ArgumentExceptionProcessor : SentryEventExceptionProcessor<ArgumentException>
{
protected override void ProcessException(ArgumentException exception, SentryEvent sentryEvent)
{
// Handle specific types of exceptions and add more data to the event
sentryEvent.SetTag("parameter-name", exception.ParamName);
}
}
}
}