sentry-vir 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  import { type JsonCompatibleObject, type PartialWithUndefined } from '@augment-vir/common';
2
2
  import { type Attachment, type ScopeContext, type setTags } from '@sentry/core';
3
+ import { type RequireOneOrNone } from 'type-fest';
3
4
  import { type EventSeverityEnum } from './event-severity.js';
4
5
  export type { Attachment } from '@sentry/core';
5
6
  /**
@@ -17,12 +18,31 @@ export type EventContextAndTags = PartialWithUndefined<{
17
18
  context: EventExtraContext;
18
19
  tags: EventTags;
19
20
  attachments: ReadonlyArray<Attachment>;
21
+ /**
22
+ * Per-event throttle override. At most one of `threshold` / `disabled` may be set: `threshold`
23
+ * tightens throttling for this event, `disabled` bypasses it entirely.
24
+ */
25
+ throttle: ThrottleOverride;
26
+ }>;
27
+ /**
28
+ * Per-event throttle override carried alongside an event. At most one of `threshold` / `disabled`
29
+ * may be set on a single override.
30
+ *
31
+ * @category Internal
32
+ */
33
+ export type ThrottleOverride = RequireOneOrNone<{
20
34
  /**
21
35
  * Per-event throttle threshold override. When set, throttling for this event uses the minimum
22
36
  * of this value and the globally-configured `throttleThreshold`, allowing individual log calls
23
37
  * to be throttled more aggressively than the global default.
24
38
  */
25
- throttleThreshold: number;
39
+ threshold: number;
40
+ /**
41
+ * When `true`, this event bypasses the throttle check entirely — it is always forwarded to
42
+ * Sentry and does not count against its cluster's interval bucket. Useful for important events
43
+ * that should never be dropped (e.g. critical alerts).
44
+ */
45
+ disabled: boolean;
26
46
  }>;
27
47
  /** Function that generates extra event context. */
28
48
  export type EventExtraContextCreator = () => EventExtraContext;
@@ -1,6 +1,6 @@
1
1
  import { type Attachment } from '@sentry/core';
2
- import { type EventContextAndTags, type EventExtraContext, type EventTags } from './event-context.js';
3
- import { extraEventAttachmentsSymbol, extraEventContextSymbol, extraEventTagsSymbol, extraEventThrottleThresholdSymbol } from './extra-event-context.js';
2
+ import { type EventContextAndTags, type EventExtraContext, type EventTags, type ThrottleOverride } from './event-context.js';
3
+ import { extraEventAttachmentsSymbol, extraEventContextSymbol, extraEventTagsSymbol, extraEventThrottleSymbol } from './extra-event-context.js';
4
4
  /**
5
5
  * Constructs an error with extra event context attached to it in the same way that
6
6
  * throwWithExtraContext attaches data.
@@ -16,7 +16,7 @@ export declare class ExtraContextError extends Error {
16
16
  readonly [extraEventContextSymbol]: EventExtraContext | undefined;
17
17
  readonly [extraEventTagsSymbol]: EventTags | undefined;
18
18
  readonly [extraEventAttachmentsSymbol]: ReadonlyArray<Attachment> | undefined;
19
- readonly [extraEventThrottleThresholdSymbol]: number | undefined;
19
+ readonly [extraEventThrottleSymbol]: ThrottleOverride | undefined;
20
20
  constructor(message: string, extraData: EventContextAndTags);
21
21
  }
22
22
  /**
@@ -1,5 +1,5 @@
1
1
  import { ensureError } from '@augment-vir/common';
2
- import { extraEventAttachmentsSymbol, extraEventContextSymbol, extraEventTagsSymbol, extraEventThrottleThresholdSymbol, } from './extra-event-context.js';
2
+ import { extraEventAttachmentsSymbol, extraEventContextSymbol, extraEventTagsSymbol, extraEventThrottleSymbol, } from './extra-event-context.js';
3
3
  /**
4
4
  * Constructs an error with extra event context attached to it in the same way that
5
5
  * throwWithExtraContext attaches data.
@@ -15,7 +15,7 @@ export class ExtraContextError extends Error {
15
15
  [extraEventContextSymbol];
16
16
  [extraEventTagsSymbol];
17
17
  [extraEventAttachmentsSymbol];
18
- [extraEventThrottleThresholdSymbol];
18
+ [extraEventThrottleSymbol];
19
19
  constructor(message, extraData) {
20
20
  super(message);
21
21
  if (extraData.context) {
@@ -27,8 +27,8 @@ export class ExtraContextError extends Error {
27
27
  if (extraData.attachments) {
28
28
  this[extraEventAttachmentsSymbol] = extraData.attachments;
29
29
  }
30
- if (extraData.throttleThreshold != undefined) {
31
- this[extraEventThrottleThresholdSymbol] = extraData.throttleThreshold;
30
+ if (extraData.throttle) {
31
+ this[extraEventThrottleSymbol] = extraData.throttle;
32
32
  }
33
33
  }
34
34
  }
@@ -47,8 +47,8 @@ export function throwWithExtraContext(originalError, extraData) {
47
47
  if (extraData.attachments) {
48
48
  error[extraEventAttachmentsSymbol] = extraData.attachments;
49
49
  }
50
- if (extraData.throttleThreshold != undefined) {
51
- error[extraEventThrottleThresholdSymbol] = extraData.throttleThreshold;
50
+ if (extraData.throttle) {
51
+ error[extraEventThrottleSymbol] = extraData.throttle;
52
52
  }
53
53
  throw error;
54
54
  }
@@ -1,5 +1,5 @@
1
1
  import { type Attachment, type Event, type EventHint } from '@sentry/core';
2
- import { type EventExtraContext, type EventTags } from './event-context.js';
2
+ import { type EventExtraContext, type EventTags, type ThrottleOverride } from './event-context.js';
3
3
  /**
4
4
  * Symbol used to attach extra event context to events. This is particularly useful for errors so
5
5
  * they can be thrown while attaching this extra context to them.
@@ -16,10 +16,11 @@ export declare const extraEventTagsSymbol: unique symbol;
16
16
  */
17
17
  export declare const extraEventAttachmentsSymbol: unique symbol;
18
18
  /**
19
- * Symbol used to attach a per-event throttle threshold override. When present, throttling uses the
20
- * minimum of this value and the globally-configured `throttleThreshold`.
19
+ * Symbol used to attach a per-event throttle override to an event or error. The attached value is a
20
+ * {@link ThrottleOverride}: at most one of `threshold` (tighten throttling for this event) or
21
+ * `disabled` (bypass throttling entirely) may be set.
21
22
  */
22
- export declare const extraEventThrottleThresholdSymbol: unique symbol;
23
+ export declare const extraEventThrottleSymbol: unique symbol;
23
24
  /** Simply describes an object that has extra event context. */
24
25
  export type HasExtraContext = {
25
26
  [extraEventContextSymbol]: EventExtraContext;
@@ -32,9 +33,9 @@ export type HasExtraTags = {
32
33
  export type HasExtraAttachments = {
33
34
  [extraEventAttachmentsSymbol]: ReadonlyArray<Attachment>;
34
35
  };
35
- /** Simply describes an object that has a per-event throttle threshold override. */
36
- export type HasExtraThrottleThreshold = {
37
- [extraEventThrottleThresholdSymbol]: number;
36
+ /** Simply describes an object that carries a per-event throttle override. */
37
+ export type HasExtraThrottle = {
38
+ [extraEventThrottleSymbol]: ThrottleOverride;
38
39
  };
39
40
  /** Type guard for whether any given input has extra event context. */
40
41
  export declare function hasExtraEventContext(input: unknown): input is HasExtraContext;
@@ -42,8 +43,8 @@ export declare function hasExtraEventContext(input: unknown): input is HasExtraC
42
43
  export declare function hasExtraEventTags(input: unknown): input is HasExtraTags;
43
44
  /** Type guard for whether any given input has extra event attachments. */
44
45
  export declare function hasExtraEventAttachments(input: unknown): input is HasExtraAttachments;
45
- /** Type guard for whether any given input carries a per-event throttle threshold override. */
46
- export declare function hasExtraEventThrottleThreshold(input: unknown): input is HasExtraThrottleThreshold;
46
+ /** Type guard for whether any given input carries a per-event throttle override. */
47
+ export declare function hasExtraEventThrottle(input: unknown): input is HasExtraThrottle;
47
48
  /**
48
49
  * Checks if extra event context has been injected into the input via extraEventContextSymbol and,
49
50
  * if so, extracts it.
@@ -75,7 +76,7 @@ export declare function extractExtraEventTags(event: EventHint | Event): EventTa
75
76
  */
76
77
  export declare function extractExtraEventAttachments(event: EventHint | Event): ReadonlyArray<Attachment> | undefined;
77
78
  /**
78
- * Tries to extract a per-event throttle threshold via extraEventThrottleThresholdSymbol from the
79
- * input itself or its originalException. Returns undefined if none is set.
79
+ * Tries to extract a per-event {@link ThrottleOverride} via extraEventThrottleSymbol from the input
80
+ * itself or its originalException. Returns `undefined` if none is set.
80
81
  */
81
- export declare function extractExtraEventThrottleThreshold(event: EventHint | Event): number | undefined;
82
+ export declare function extractExtraEventThrottle(event: EventHint | Event): ThrottleOverride | undefined;
@@ -15,10 +15,11 @@ export const extraEventTagsSymbol = Symbol('extra-event-tags');
15
15
  */
16
16
  export const extraEventAttachmentsSymbol = Symbol('extra-event-attachments');
17
17
  /**
18
- * Symbol used to attach a per-event throttle threshold override. When present, throttling uses the
19
- * minimum of this value and the globally-configured `throttleThreshold`.
18
+ * Symbol used to attach a per-event throttle override to an event or error. The attached value is a
19
+ * {@link ThrottleOverride}: at most one of `threshold` (tighten throttling for this event) or
20
+ * `disabled` (bypass throttling entirely) may be set.
20
21
  */
21
- export const extraEventThrottleThresholdSymbol = Symbol('extra-event-throttle-threshold');
22
+ export const extraEventThrottleSymbol = Symbol('extra-event-throttle');
22
23
  /** Type guard for whether any given input has extra event context. */
23
24
  export function hasExtraEventContext(input) {
24
25
  return check.hasKey(input, extraEventContextSymbol) && !!input[extraEventContextSymbol];
@@ -31,10 +32,9 @@ export function hasExtraEventTags(input) {
31
32
  export function hasExtraEventAttachments(input) {
32
33
  return check.hasKey(input, extraEventAttachmentsSymbol) && !!input[extraEventAttachmentsSymbol];
33
34
  }
34
- /** Type guard for whether any given input carries a per-event throttle threshold override. */
35
- export function hasExtraEventThrottleThreshold(input) {
36
- return (check.hasKey(input, extraEventThrottleThresholdSymbol) &&
37
- check.isNumber(input[extraEventThrottleThresholdSymbol]));
35
+ /** Type guard for whether any given input carries a per-event throttle override. */
36
+ export function hasExtraEventThrottle(input) {
37
+ return check.hasKey(input, extraEventThrottleSymbol) && !!input[extraEventThrottleSymbol];
38
38
  }
39
39
  /**
40
40
  * Checks if extra event context has been injected into the input via extraEventContextSymbol and,
@@ -133,15 +133,13 @@ export function extractExtraEventAttachments(event) {
133
133
  }
134
134
  }
135
135
  /**
136
- * Tries to extract a per-event throttle threshold via extraEventThrottleThresholdSymbol from the
137
- * input itself or its originalException. Returns undefined if none is set.
136
+ * Tries to extract a per-event {@link ThrottleOverride} via extraEventThrottleSymbol from the input
137
+ * itself or its originalException. Returns `undefined` if none is set.
138
138
  */
139
- export function extractExtraEventThrottleThreshold(event) {
140
- const fromRoot = hasExtraEventThrottleThreshold(event)
141
- ? event[extraEventThrottleThresholdSymbol]
142
- : undefined;
143
- const fromException = 'originalException' in event && hasExtraEventThrottleThreshold(event.originalException)
144
- ? event.originalException[extraEventThrottleThresholdSymbol]
139
+ export function extractExtraEventThrottle(event) {
140
+ const fromRoot = hasExtraEventThrottle(event) ? event[extraEventThrottleSymbol] : undefined;
141
+ const fromException = 'originalException' in event && hasExtraEventThrottle(event.originalException)
142
+ ? event.originalException[extraEventThrottleSymbol]
145
143
  : undefined;
146
144
  return fromRoot ?? fromException;
147
145
  }
@@ -1,7 +1,7 @@
1
1
  import { extractErrorMessage } from '@augment-vir/common';
2
2
  import { convertEventDetailsToSentryContext, } from '../event-context/event-context.js';
3
3
  import { EventSeverityEnum } from '../event-context/event-severity.js';
4
- import { extractExtraAttachmentsFromSymbol, extractExtraEventThrottleThreshold, } from '../event-context/extra-event-context.js';
4
+ import { extractExtraAttachmentsFromSymbol, extractExtraEventThrottle, extractExtraTagsFromSymbol, } from '../event-context/extra-event-context.js';
5
5
  import { LoggingState, logToConsoleWithoutSentry } from '../processing/log-to-console.js';
6
6
  import { skipBeforeSendThrottleContextKey } from '../processing/throttling.js';
7
7
  import { addPrematureEvent } from './premature-events.js';
@@ -32,21 +32,37 @@ function internalHandleError(error, eventOptions, options) {
32
32
  ]);
33
33
  return undefined;
34
34
  }
35
- const perCallThresholdCandidates = [
36
- extractExtraEventThrottleThreshold({
37
- originalException: error,
38
- }),
39
- eventOptions?.throttleThreshold,
40
- ].filter((value) => value != undefined);
41
- const perCallThrottleThreshold = perCallThresholdCandidates.length
42
- ? Math.min(...perCallThresholdCandidates)
43
- : undefined;
44
- if (checkActiveThrottle({
45
- message: extractErrorMessage(error),
46
- }, {
35
+ const errorThrottleOverride = extractExtraEventThrottle({
47
36
  originalException: error,
48
- }, perCallThrottleThreshold)) {
49
- return undefined;
37
+ });
38
+ const disableThrottling = eventOptions?.throttle?.disabled === true || errorThrottleOverride?.disabled === true;
39
+ if (!disableThrottling) {
40
+ const perCallThresholdCandidates = [
41
+ errorThrottleOverride?.threshold,
42
+ eventOptions?.throttle?.threshold,
43
+ ].filter((value) => value != undefined);
44
+ const perCallThrottleThreshold = perCallThresholdCandidates.length
45
+ ? Math.min(...perCallThresholdCandidates)
46
+ : undefined;
47
+ const symbolTags = extractExtraTagsFromSymbol(error);
48
+ const combinedTags = symbolTags == undefined && eventOptions?.tags == undefined
49
+ ? undefined
50
+ : {
51
+ ...symbolTags,
52
+ ...eventOptions?.tags,
53
+ };
54
+ if (checkActiveThrottle({
55
+ message: extractErrorMessage(error),
56
+ ...(combinedTags
57
+ ? {
58
+ tags: combinedTags,
59
+ }
60
+ : {}),
61
+ }, {
62
+ originalException: error,
63
+ }, perCallThrottleThreshold)) {
64
+ return undefined;
65
+ }
50
66
  }
51
67
  const scopeContext = convertEventDetailsToSentryContext({
52
68
  extraContext: eventOptions?.context,
@@ -1,6 +1,6 @@
1
1
  import { type PartialWithUndefined } from '@augment-vir/common';
2
2
  import { type ErrorEvent, type EventHint, type Event as SentryEvent, type TransactionEvent } from '@sentry/core';
3
- import { type ContextOptions, type EventContextAndTags, type EventDetails } from '../event-context/event-context.js';
3
+ import { type ContextOptions, type EventContextAndTags, type EventDetails, type ThrottleOverride } from '../event-context/event-context.js';
4
4
  import { type ThrottleOptions } from '../processing/throttling.js';
5
5
  /** A Sentry event object without the fields that are set by the logging context. */
6
6
  export type SendLogEvent = Omit<SentryEvent, 'extra' | 'level'>;
@@ -23,7 +23,7 @@ export declare const sendLog: {
23
23
  *
24
24
  * @category Internal
25
25
  */
26
- export declare function throttleEventWithLogging(event: Pick<TransactionEvent | ErrorEvent, 'message'>, hint: Readonly<Pick<EventHint, 'originalException'>> | undefined, options: Readonly<PartialWithUndefined<ThrottleOptions>>): boolean;
26
+ export declare function throttleEventWithLogging(event: Pick<TransactionEvent | ErrorEvent, 'message' | 'tags'>, hint: Readonly<Pick<EventHint, 'originalException'>> | undefined, options: Readonly<PartialWithUndefined<ThrottleOptions>>): boolean;
27
27
  /**
28
28
  * Synchronous pre-capture throttle check used by `sendLog` and `handleError`. Returns `true` when
29
29
  * the event should be dropped. Returns `false` (i.e. "send it") when no active throttle options
@@ -31,6 +31,6 @@ export declare function throttleEventWithLogging(event: Pick<TransactionEvent |
31
31
  *
32
32
  * @category Internal
33
33
  */
34
- export declare function checkActiveThrottle(event: Pick<TransactionEvent | ErrorEvent, 'message'>, hint: Readonly<Pick<EventHint, 'originalException'>> | undefined, perCallThreshold: number | undefined): boolean;
35
- declare function sendLogToSentry(logInfo: SendLogInfo, eventDetails: EventDetails, options: ContextOptions, perCallThrottleThreshold: number | undefined): string | undefined;
34
+ export declare function checkActiveThrottle(event: Pick<TransactionEvent | ErrorEvent, 'message' | 'tags'>, hint: Readonly<Pick<EventHint, 'originalException'>> | undefined, perCallThreshold: number | undefined): boolean;
35
+ declare function sendLogToSentry(logInfo: SendLogInfo, eventDetails: EventDetails, options: ContextOptions, perCallThrottle: ThrottleOverride | undefined): string | undefined;
36
36
  export {};
@@ -28,14 +28,16 @@ export function throttleEventWithLogging(event, hint, options) {
28
28
  const result = shouldThrottleEvent(event, hint, options);
29
29
  const disableLog = options.disableThrottleLog ?? defaultThrottleOptions.disableThrottleLog;
30
30
  if (!disableLog && result.errorKey != undefined) {
31
+ const inheritedTags = {
32
+ ...event.tags,
33
+ suppressedErrorKey: result.errorKey,
34
+ };
31
35
  if (result.transition.kind === 'started') {
32
36
  sendLog.warning(`Throttling started: ${result.errorKey}`, {
33
37
  context: {
34
38
  suppressedErrorKey: result.errorKey,
35
39
  },
36
- tags: {
37
- suppressedErrorKey: result.errorKey,
38
- },
40
+ tags: inheritedTags,
39
41
  });
40
42
  }
41
43
  else if (result.transition.kind === 'ended') {
@@ -44,9 +46,7 @@ export function throttleEventWithLogging(event, hint, options) {
44
46
  suppressedErrorKey: result.errorKey,
45
47
  suppressedCount: result.transition.suppressedCount,
46
48
  },
47
- tags: {
48
- suppressedErrorKey: result.errorKey,
49
- },
49
+ tags: inheritedTags,
50
50
  });
51
51
  }
52
52
  }
@@ -75,10 +75,10 @@ function wrapLogWithSeverity(severity) {
75
75
  severity,
76
76
  }, {
77
77
  wasSentPrematurely: false,
78
- }, eventOptions?.throttleThreshold);
78
+ }, eventOptions?.throttle);
79
79
  };
80
80
  }
81
- function sendLogToSentry(logInfo, eventDetails, options, perCallThrottleThreshold) {
81
+ function sendLogToSentry(logInfo, eventDetails, options, perCallThrottle) {
82
82
  try {
83
83
  /**
84
84
  * `Error.message` is not enumerable, so spreading an `Error` into `captureEvent` would lose
@@ -102,17 +102,24 @@ function sendLogToSentry(logInfo, eventDetails, options, perCallThrottleThreshol
102
102
  {
103
103
  wasSentPrematurely: true,
104
104
  },
105
- perCallThrottleThreshold,
105
+ perCallThrottle,
106
106
  ]);
107
107
  return undefined;
108
108
  }
109
- const throttleMessage = check.isString(resolvedLogInfo)
110
- ? resolvedLogInfo
111
- : extractOriginalMessage(resolvedLogInfo, undefined);
112
- if (checkActiveThrottle({
113
- message: throttleMessage,
114
- }, undefined, perCallThrottleThreshold)) {
115
- return undefined;
109
+ if (perCallThrottle?.disabled !== true) {
110
+ const throttleMessage = check.isString(resolvedLogInfo)
111
+ ? resolvedLogInfo
112
+ : extractOriginalMessage(resolvedLogInfo, undefined);
113
+ if (checkActiveThrottle({
114
+ message: throttleMessage,
115
+ ...(eventDetails.tags
116
+ ? {
117
+ tags: eventDetails.tags,
118
+ }
119
+ : {}),
120
+ }, undefined, perCallThrottle?.threshold)) {
121
+ return undefined;
122
+ }
116
123
  }
117
124
  const scopeContext = convertEventDetailsToSentryContext(eventDetails, options);
118
125
  const client = sentryClientForLogging;
@@ -1,4 +1,4 @@
1
- import { extractExtraEventThrottleThreshold } from '../event-context/extra-event-context.js';
1
+ import { extractExtraEventThrottle } from '../event-context/extra-event-context.js';
2
2
  import { throttleEventWithLogging } from '../logging/send-log.js';
3
3
  import { LoggingState, logToConsoleFromSentry } from './log-to-console.js';
4
4
  import { combineThrottleThreshold, skipBeforeSendThrottleContextKey, } from './throttling.js';
@@ -14,11 +14,11 @@ export function createSentryHandler({ isDev, isSilent, throttleOptions, }) {
14
14
  if (event.contexts && skipBeforeSendThrottleContextKey in event.contexts) {
15
15
  delete event.contexts[skipBeforeSendThrottleContextKey];
16
16
  }
17
- if (!wasPreThrottled) {
18
- const perEventThreshold = extractExtraEventThrottleThreshold(hint);
19
- if (throttleEventWithLogging(event, hint, combineThrottleThreshold(throttleOptions, perEventThreshold))) {
20
- return null;
21
- }
17
+ const eventThrottleOverride = extractExtraEventThrottle(hint);
18
+ if (!wasPreThrottled &&
19
+ eventThrottleOverride?.disabled !== true &&
20
+ throttleEventWithLogging(event, hint, combineThrottleThreshold(throttleOptions, eventThrottleOverride?.threshold))) {
21
+ return null;
22
22
  }
23
23
  if (!event.extra?.wasSentPrematurely) {
24
24
  logToConsoleFromSentry(event, hint, isDev ? LoggingState.Dev : LoggingState.Prod, isSilent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentry-vir",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "Easily use Sentry.",
5
5
  "keywords": [
6
6
  "config",