• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / HashGate / 25220934046

01 May 2026 03:43PM UTC coverage: 64.311% (-8.4%) from 72.756%
25220934046

push

github

pwelter34
Add OpenTelemetry diagnostics and metrics

189 of 398 branches covered (47.49%)

Branch coverage included in aggregate %.

101 of 165 new or added lines in 4 files covered. (61.21%)

539 of 734 relevant lines covered (73.43%)

27.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.48
/src/HashGate.AspNetCore/HashGateDiagnostics.cs
1
// Ignore Spelling: Hmac
2

3
using System.Diagnostics;
4
using System.Diagnostics.Metrics;
5

6
namespace HashGate.AspNetCore;
7

8
/// <summary>
9
/// Provides diagnostic source, meter, metric, and tag names used by HashGate ASP.NET Core instrumentation.
10
/// </summary>
11
public static class HashGateDiagnostics
12
{
13
    /// <summary>
14
    /// The name of the activity source used for HashGate ASP.NET Core tracing.
15
    /// </summary>
16
    public const string ActivitySourceName = "HashGate.AspNetCore";
17

18
    /// <summary>
19
    /// The name of the meter used for HashGate ASP.NET Core metrics.
20
    /// </summary>
21
    public const string MeterName = "HashGate.AspNetCore";
22

23
    /// <summary>
24
    /// The metric name for HMAC authentication request attempts.
25
    /// </summary>
26
    public const string AuthenticationRequestsName = "hashgate.auth.requests";
27

28
    /// <summary>
29
    /// The metric name for failed HMAC authentication attempts.
30
    /// </summary>
31
    public const string AuthenticationFailuresName = "hashgate.auth.failures";
32

33
    /// <summary>
34
    /// The metric name for HMAC authentication duration.
35
    /// </summary>
36
    public const string AuthenticationDurationName = "hashgate.auth.duration";
37

38
    /// <summary>
39
    /// The metric name for HMAC replay protection checks.
40
    /// </summary>
41
    public const string ReplayProtectionChecksName = "hashgate.replay_protection.checks";
42

43
    /// <summary>
44
    /// The metric name for rejected replayed HMAC signatures.
45
    /// </summary>
46
    public const string ReplayProtectionReplaysName = "hashgate.replay_protection.replays";
47

48
    /// <summary>
49
    /// The metric name for rate-limited endpoint requests resolved by HashGate.
50
    /// </summary>
51
    public const string EndpointRequestsName = "hashgate.endpoint.requests";
52

53
    /// <summary>
54
    /// The metric name for requests rejected by HashGate rate limiting.
55
    /// </summary>
56
    public const string RateLimitRejectionsName = "hashgate.rate_limit.rejections";
57

58
    /// <summary>
59
    /// The metric name for per-client rate limit provider lookups.
60
    /// </summary>
61
    public const string RateLimitProviderLookupsName = "hashgate.rate_limit.provider.lookup";
62

63
    /// <summary>
64
    /// The metric name for per-client rate limit provider lookups that used default limits.
65
    /// </summary>
66
    public const string RateLimitProviderMissesName = "hashgate.rate_limit.provider.miss";
67

68

69
    /// <summary>
70
    /// The tag name for the authentication scheme used by a request.
71
    /// </summary>
72
    public const string AuthenticationSchemeTagName = "hashgate.auth.scheme";
73

74
    /// <summary>
75
    /// The tag name for the authentication result.
76
    /// </summary>
77
    public const string AuthenticationResultTagName = "hashgate.auth.result";
78

79
    /// <summary>
80
    /// The tag name for the authentication failure reason.
81
    /// </summary>
82
    public const string AuthenticationFailureReasonTagName = "hashgate.auth.failure_reason";
83

84
    /// <summary>
85
    /// The tag name that indicates whether replay protection is enabled.
86
    /// </summary>
87
    public const string ReplayProtectionEnabledTagName = "hashgate.replay_protection.enabled";
88

89
    /// <summary>
90
    /// The tag name for the replay protection result.
91
    /// </summary>
92
    public const string ReplayProtectionResultTagName = "hashgate.replay_protection.result";
93

94
    /// <summary>
95
    /// The tag name for the HMAC client identifier.
96
    /// </summary>
97
    public const string HmacClientTagName = "hashgate.hmac.client";
98

99
    /// <summary>
100
    /// The tag name for the count of signed HMAC headers.
101
    /// </summary>
102
    public const string HmacSignedHeadersCountTagName = "hashgate.hmac.signed_headers.count";
103

104
    /// <summary>
105
    /// The tag name that indicates whether a request was rejected by rate limiting.
106
    /// </summary>
107
    public const string RateLimitRejectedTagName = "hashgate.rate_limit.rejected";
108

109
    /// <summary>
110
    /// The tag name for the rate limit policy.
111
    /// </summary>
112
    public const string RateLimitPolicyTagName = "hashgate.rate_limit.policy";
113

114
    /// <summary>
115
    /// The tag name for the retry-after duration in milliseconds.
116
    /// </summary>
117
    public const string RateLimitRetryAfterMillisecondsTagName = "hashgate.rate_limit.retry_after_ms";
118

119
    /// <summary>
120
    /// The tag name for the rate limit client identifier.
121
    /// </summary>
122
    public const string RateLimitClientTagName = "hashgate.rate_limit.client";
123

124
    /// <summary>
125
    /// The tag name for the rate-limited endpoint.
126
    /// </summary>
127
    public const string RateLimitEndpointTagName = "hashgate.rate_limit.endpoint";
128

129
    /// <summary>
130
    /// The tag name for the configured requests per rate limit period.
131
    /// </summary>
132
    public const string RateLimitRequestsPerPeriodTagName = "hashgate.rate_limit.requests_per_period";
133

134
    /// <summary>
135
    /// The tag name for the configured rate limit burst factor.
136
    /// </summary>
137
    public const string RateLimitBurstFactorTagName = "hashgate.rate_limit.burst_factor";
138

139
    /// <summary>
140
    /// The tag name for the rate limit partition source.
141
    /// </summary>
142
    public const string RateLimitPartitionSourceTagName = "hashgate.rate_limit.partition_source";
143

144
    /// <summary>
145
    /// The tag name that indicates whether a rate limit provider lookup found client-specific limits.
146
    /// </summary>
147
    public const string RateLimitProviderFoundTagName = "hashgate.rate_limit.provider_found";
148

149
    /// <summary>
150
    /// The tag name for the resolved endpoint.
151
    /// </summary>
152
    public const string EndpointTagName = "hashgate.endpoint";
153

154
    /// <summary>
155
    /// The tag name for the resolved client.
156
    /// </summary>
157
    public const string ClientTagName = "hashgate.client";
158

159
    internal static readonly ActivitySource ActivitySource = new(ActivitySourceName, ThisAssembly.FileVersion);
1✔
160
    internal static readonly Meter Meter = new(MeterName, ThisAssembly.FileVersion);
1✔
161

162
    internal static readonly Counter<long> AuthenticationRequests = Meter.CreateCounter<long>(
1✔
163
        name: AuthenticationRequestsName,
1✔
164
        unit: "{request}",
1✔
165
        description: "Number of HMAC authentication attempts.");
1✔
166

167
    internal static readonly Counter<long> AuthenticationFailures = Meter.CreateCounter<long>(
1✔
168
        name: AuthenticationFailuresName,
1✔
169
        unit: "{failure}",
1✔
170
        description: "Number of failed HMAC authentication attempts.");
1✔
171

172
    internal static readonly Histogram<double> AuthenticationDuration = Meter.CreateHistogram<double>(
1✔
173
        name: AuthenticationDurationName,
1✔
174
        unit: "ms",
1✔
175
        description: "Duration of HMAC authentication attempts.");
1✔
176

177

178
    internal static readonly Counter<long> ReplayProtectionChecks = Meter.CreateCounter<long>(
1✔
179
        name: ReplayProtectionChecksName,
1✔
180
        unit: "{check}",
1✔
181
        description: "Number of HMAC replay protection checks.");
1✔
182

183
    internal static readonly Counter<long> ReplayProtectionReplays = Meter.CreateCounter<long>(
1✔
184
        name: ReplayProtectionReplaysName,
1✔
185
        unit: "{replay}",
1✔
186
        description: "Number of rejected replayed HMAC signatures.");
1✔
187

188

189
    internal static readonly Counter<long> EndpointRequests = Meter.CreateCounter<long>(
1✔
190
        name: EndpointRequestsName,
1✔
191
        unit: "{request}",
1✔
192
        description: "Number of rate-limited endpoint requests resolved by HashGate.");
1✔
193

194

195
    internal static readonly Counter<long> RateLimitRejections = Meter.CreateCounter<long>(
1✔
196
        name: RateLimitRejectionsName,
1✔
197
        unit: "{rejection}",
1✔
198
        description: "Number of requests rejected by HashGate rate limiting.");
1✔
199

200
    internal static readonly Counter<long> RateLimitProviderLookups = Meter.CreateCounter<long>(
1✔
201
        name: RateLimitProviderLookupsName,
1✔
202
        unit: "{lookup}",
1✔
203
        description: "Number of per-client rate limit provider lookups.");
1✔
204

205
    internal static readonly Counter<long> RateLimitProviderMisses = Meter.CreateCounter<long>(
1✔
206
        name: RateLimitProviderMissesName,
1✔
207
        unit: "{miss}",
1✔
208
        description: "Number of per-client rate limit provider lookups that fell back to default limits.");
1✔
209

210

211
    internal static void RecordAuthentication(string scheme, string result, string? failureReason, long elapsedTicks)
212
    {
213
        if (!AuthenticationRequests.Enabled &&
32!
214
            !AuthenticationFailures.Enabled &&
32✔
215
            !AuthenticationDuration.Enabled)
32✔
216
        {
217
            return;
32✔
218
        }
219

NEW
220
        KeyValuePair<string, object?>[] tags = failureReason is null
×
NEW
221
            ?
×
NEW
222
            [
×
NEW
223
                new(AuthenticationSchemeTagName, scheme),
×
NEW
224
                new(AuthenticationResultTagName, result)
×
NEW
225
            ]
×
NEW
226
            :
×
NEW
227
            [
×
NEW
228
                new(AuthenticationSchemeTagName, scheme),
×
NEW
229
                new(AuthenticationResultTagName, result),
×
NEW
230
                new(AuthenticationFailureReasonTagName, failureReason)
×
NEW
231
            ];
×
232

NEW
233
        AuthenticationRequests.Add(1, tags);
×
234

NEW
235
        if (failureReason is not null)
×
NEW
236
            AuthenticationFailures.Add(1, tags);
×
237

NEW
238
        var elapsed = GetElapsedMilliseconds(elapsedTicks);
×
NEW
239
        AuthenticationDuration.Record(elapsed, tags);
×
NEW
240
    }
×
241

242
    internal static void RecordReplayProtectionCheck(string result, double ttlMilliseconds)
243
    {
244
        if (!ReplayProtectionChecks.Enabled
21!
245
            && (result != "replay" || !ReplayProtectionReplays.Enabled))
21✔
246
        {
247
            return;
21✔
248
        }
249

NEW
250
        KeyValuePair<string, object?>[] tags =
×
NEW
251
        [
×
NEW
252
            new(ReplayProtectionResultTagName, result)
×
NEW
253
        ];
×
254

NEW
255
        ReplayProtectionChecks.Add(1, tags);
×
256

NEW
257
        if (result == "replay")
×
NEW
258
            ReplayProtectionReplays.Add(1, tags);
×
NEW
259
    }
×
260

261
    internal static void RecordEndpointRequest(string policy, string endpoint, string client)
262
    {
263
        if (!EndpointRequests.Enabled)
23!
264
            return;
23✔
265

NEW
266
        KeyValuePair<string, object?>[] tags =
×
NEW
267
        [
×
NEW
268
            new(RateLimitPolicyTagName, policy),
×
NEW
269
            new(EndpointTagName, endpoint),
×
NEW
270
            new(ClientTagName, client)
×
NEW
271
        ];
×
272

NEW
273
        EndpointRequests.Add(1, tags);
×
NEW
274
    }
×
275

276
    internal static void RecordRateLimitRejection(string policy, double retryAfterMilliseconds)
277
    {
278
        if (!RateLimitRejections.Enabled)
5!
279
            return;
5✔
280

NEW
281
        KeyValuePair<string, object?>[] tags =
×
NEW
282
        [
×
NEW
283
            new(RateLimitPolicyTagName, policy)
×
NEW
284
        ];
×
285

NEW
286
        RateLimitRejections.Add(1, tags);
×
NEW
287
    }
×
288

289
    internal static void RecordRateLimitProviderLookup(string policy, bool found)
290
    {
291
        if (!RateLimitProviderLookups.Enabled
23!
292
            && (found || !RateLimitProviderMisses.Enabled))
23✔
293
        {
294
            return;
23✔
295
        }
296

NEW
297
        KeyValuePair<string, object?>[] tags =
×
NEW
298
        [
×
NEW
299
            new(RateLimitPolicyTagName, policy),
×
NEW
300
            new(RateLimitProviderFoundTagName, found)
×
NEW
301
        ];
×
302

NEW
303
        RateLimitProviderLookups.Add(1, tags);
×
304

NEW
305
        if (!found)
×
NEW
306
            RateLimitProviderMisses.Add(1, tags);
×
NEW
307
    }
×
308

309
    private static double GetElapsedMilliseconds(long startTimestamp)
NEW
310
        => Stopwatch.GetElapsedTime(startTimestamp).TotalMilliseconds;
×
311
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc