@loglayer/mixin-wide-events 1.0.1 → 1.1.1

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.
package/README.md CHANGED
@@ -1,9 +1,19 @@
1
- # @loglayer/mixin-wide-events
1
+ # wide-events mixin for LogLayer
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@loglayer/mixin-wide-events.svg)](https://www.npmjs.com/package/@loglayer/mixin-wide-events)
4
- [![npm downloads](https://img.shields.io/npm/dm/@loglayer/mixin-wide-events.svg)](https://www.npmjs.com/package/@loglayer/mixin-wide-events)
3
+ [![NPM Version](https://img.shields.io/npm/v/%40loglayer%2Fmixin-wide-events)](https://www.npmjs.com/package/@loglayer/mixin-wide-events)
4
+ [![NPM Downloads](https://img.shields.io/npm/dm/%40loglayer%2Fmixin-wide-events)](https://www.npmjs.com/package/@loglayer/mixin-wide-events)
5
5
  [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
6
6
 
7
- Adds wide event logging functionality to LogLayer for comprehensive, self-contained log entries.
7
+ Adds wide event logging functionality to the [LogLayer](https://loglayer.dev) logging library, enabling comprehensive, self-contained log entries that capture an entire operation's context using Node.js `AsyncLocalStorage`.
8
8
 
9
- [Documentation](https://loglayer.dev/mixins/wide-events) | [API Reference](https://loglayer.dev/mixins/wide-events)
9
+ The mixin provides methods to accumulate data across async boundaries and emit it as a single log entry, along with built-in sampling support.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install loglayer @loglayer/mixin-wide-events
15
+ ```
16
+
17
+ ## Documentation
18
+
19
+ For more details, visit [https://loglayer.dev/mixins/wide-events](https://loglayer.dev/mixins/wide-events).
package/dist/index.cjs CHANGED
@@ -37,6 +37,45 @@ let LogLayerMixinAugmentType = /* @__PURE__ */ function(LogLayerMixinAugmentType
37
37
  //#endregion
38
38
  //#region src/mixin.ts
39
39
  /**
40
+ * Log levels that default to rate=1 (error/fatal) — can be overridden via `perLevel` or callback.
41
+ */
42
+ const EXEMPT_LEVELS = new Set(["error", "fatal"]);
43
+ /**
44
+ * Normalize a boolean or numeric rate to a number in [0, 1].
45
+ * `true` becomes 1, `false` becomes 0, numbers are clamped to [0, 1].
46
+ * `NaN`, `Infinity`, and `-Infinity` are treated as 0 (drop all).
47
+ */
48
+ function toRate(value) {
49
+ if (value === void 0) return 1;
50
+ if (typeof value === "boolean") return value ? 1 : 0;
51
+ if (typeof value !== "number" || !Number.isFinite(value)) return 0;
52
+ return Math.max(0, Math.min(1, value));
53
+ }
54
+ /**
55
+ * Run rate-based sampling (default or per_level strategy).
56
+ * Returns true if the rate check passes, false if dropped.
57
+ * Returns true for error/fatal by default, unless their rate is explicitly set in `perLevel`.
58
+ */
59
+ function runRateSampling(level, strategy, rate, perLevel) {
60
+ if (EXEMPT_LEVELS.has(level) && perLevel?.[level] === void 0) return true;
61
+ if (strategy === "per_level" && perLevel) {
62
+ const perRate = toRate(perLevel[level]);
63
+ if (perLevel[level] === void 0) {
64
+ const r = toRate(rate);
65
+ if (r === 1) return true;
66
+ if (r === 0) return false;
67
+ return Math.random() < r;
68
+ }
69
+ if (perRate === 1) return true;
70
+ if (perRate === 0) return false;
71
+ return Math.random() < perRate;
72
+ }
73
+ const r = toRate(rate);
74
+ if (r === 1) return true;
75
+ if (r === 0) return false;
76
+ return Math.random() < r;
77
+ }
78
+ /**
40
79
  * Creates a LogLayer mixin that adds wide event logging functionality.
41
80
  *
42
81
  * Wide events are comprehensive, self-contained log entries that capture an entire
@@ -48,7 +87,6 @@ let LogLayerMixinAugmentType = /* @__PURE__ */ function(LogLayerMixinAugmentType
48
87
  * wide event data across async boundaries. For Node.js, use `new AsyncLocalStorage()`
49
88
  * from `async_hooks`. For browser environments, provide your own compatible implementation.
50
89
  * @param options.includeContext - Whether to include withContext() data in emitted wide events (default: true)
51
-
52
90
  *
53
91
  * @returns A LogLayer mixin registration object
54
92
  *
@@ -85,6 +123,14 @@ function createWideEventMixin(options) {
85
123
  const wideEventField = options.wideEventField;
86
124
  const errorsAsArray = options.errorsAsArray ?? false;
87
125
  const errorField = options.errorField ?? (errorsAsArray ? "errors" : "error");
126
+ const snapshotPerLevel = options.sampling?.perLevel ? { ...options.sampling.perLevel } : void 0;
127
+ const samplingConfig = options.sampling ? {
128
+ strategy: options.sampling.strategy ?? "default",
129
+ rate: options.sampling.rate,
130
+ perLevel: snapshotPerLevel,
131
+ emitLevel: options.sampling.emitLevel,
132
+ shouldEmit: options.sampling.shouldEmit
133
+ } : void 0;
88
134
  function defaultErrorSerializer(err) {
89
135
  if (err instanceof Error) return {
90
136
  name: err.name,
@@ -181,11 +227,20 @@ function createWideEventMixin(options) {
181
227
  * Implementation for emitWideEvent
182
228
  */
183
229
  function emitWideEventImpl(config, self) {
230
+ const defaultLevel = samplingConfig?.emitLevel ?? "info";
231
+ const level = config.level ?? defaultLevel;
232
+ if (samplingConfig && !samplingConfig.shouldEmit && !runRateSampling(level, samplingConfig.strategy, samplingConfig.rate, samplingConfig.perLevel)) return;
184
233
  const store = asyncContext.getStore();
185
234
  const wideEventData = {};
186
235
  if (includeContext && store?._llContext) Object.assign(wideEventData, store._llContext);
187
236
  if (store?._llWideEvents) Object.assign(wideEventData, store._llWideEvents);
188
- const level = config.level ?? "info";
237
+ if (samplingConfig?.shouldEmit) try {
238
+ const callbackOk = samplingConfig.shouldEmit({
239
+ wideData: wideEventData,
240
+ level
241
+ });
242
+ if (!runRateSampling(level, samplingConfig.strategy, samplingConfig.rate, samplingConfig.perLevel) || !callbackOk) return;
243
+ } catch {}
189
244
  const metadataToEmit = wideEventField ? { [wideEventField]: wideEventData } : wideEventData;
190
245
  self.withMetadata(metadataToEmit)[level](config.message);
191
246
  }
package/dist/index.d.cts CHANGED
@@ -2060,6 +2060,121 @@ declare class LogBuilder implements ILogBuilder<LogBuilder, boolean> {
2060
2060
  */
2061
2061
  //#endregion
2062
2062
  //#region src/types.d.ts
2063
+ /**
2064
+ * Parameters passed to a custom `shouldEmit` sampling callback.
2065
+ * Provides the accumulated wide event data and the log level so the
2066
+ * callback can make an informed keep/drop decision.
2067
+ */
2068
+ interface WideEventSamplingParams {
2069
+ /**
2070
+ * The accumulated wide event data (wide events + optional context).
2071
+ * Contains the merged data that would be emitted if kept.
2072
+ */
2073
+ wideData: Record<string, any>;
2074
+ /**
2075
+ * The log level that would be used for the emission.
2076
+ */
2077
+ level: LogLevelType;
2078
+ }
2079
+ /**
2080
+ * Sampling strategy for wide events.
2081
+ *
2082
+ * - `"default"` — a single `rate` applies to all non-error/fatal levels.
2083
+ * - `"per_level"` — per-level rates keyed by LogLevelType; levels not in the
2084
+ * map use `rate` as a fallback.
2085
+ */
2086
+ type WideEventSamplingStrategy = "default" | "per_level";
2087
+ /**
2088
+ * Configuration for sampling wide event emissions.
2089
+ *
2090
+ * "error" and "fatal" levels default to a 100% keep rate, but can be
2091
+ * overridden by setting `perLevel` rates or via `shouldEmit`.
2092
+ */
2093
+ interface WideEventSamplingConfig {
2094
+ /**
2095
+ * The sampling strategy.
2096
+ *
2097
+ * - `"default"` — a single `rate` applies to all non-error/fatal levels.
2098
+ * - `"per_level"` — per-level rates from the `perLevel` map; levels not in
2099
+ * the map use `rate` as a fallback.
2100
+ *
2101
+ * @default "default"
2102
+ */
2103
+ strategy?: WideEventSamplingStrategy;
2104
+ /**
2105
+ * A rate between 0 and 1 that determines the fraction of events to keep.
2106
+ *
2107
+ * - `1` (or `true`) — keep 100% (sampling disabled)
2108
+ * - `0.1` — ~10% of events kept
2109
+ * - `0` (or `false`) — keep 0% (all dropped for sample-able levels)
2110
+ *
2111
+ * With `"default"` strategy this rate applies to all non-error/fatal levels.
2112
+ * With `"per_level"` strategy this field is **ignored** — unmapped levels
2113
+ * default to a 100% keep rate.
2114
+ *
2115
+ * @default 1
2116
+ */
2117
+ rate?: boolean | number;
2118
+ /**
2119
+ * Per-level sampling rates when strategy is `"per_level"`.
2120
+ * Keys are log level strings (e.g. `"trace"`, `"info"`, `"warn"`).
2121
+ * Levels not listed use `rate` as a fallback.
2122
+ *
2123
+ * **Important:** "error" and "fatal" default to a 100% keep rate, but can be
2124
+ * explicitly overridden by setting their rate in `perLevel` or using a
2125
+ * `shouldEmit` callback.
2126
+ *
2127
+ * The map is snapshotted at construction time; mutating it afterward has
2128
+ * no effect.
2129
+ *
2130
+ * @example
2131
+ * ```ts
2132
+ * {
2133
+ * strategy: "per_level",
2134
+ * perLevel: {
2135
+ * trace: 0.1,
2136
+ * debug: 0.3,
2137
+ * info: 0.5,
2138
+ * },
2139
+ * }
2140
+ * // warn, error, fatal are all 100%
2141
+ * ```
2142
+ */
2143
+ perLevel?: Partial<Record<LogLevelType, boolean | number>>;
2144
+ /**
2145
+ * A custom sampling callback that receives the wide event data and log
2146
+ * level, allowing you to make an informed keep/drop decision.
2147
+ *
2148
+ * When provided, this callback is invoked **in addition to** the built-in
2149
+ * rate-based sampling. An event is only kept when **both** the built-in
2150
+ * check passes (if `rate`/`perLevel` are configured) **and** the callback
2151
+ * returns `true`. If only `shouldEmit` is set (no `rate`), the callback
2152
+ * acts as the sole gate.
2153
+ *
2154
+ * **Note:** "error" and "fatal" default to a 100% keep rate, but can be
2155
+ * overridden by returning `false` from this callback.
2156
+ *
2157
+ * @example
2158
+ * ```ts
2159
+ * {
2160
+ * shouldEmit: ({ wideData, level }) => {
2161
+ * // Only emit wide events that have a userId
2162
+ * return !!wideData.userId;
2163
+ * },
2164
+ * }
2165
+ * ```
2166
+ */
2167
+ shouldEmit?: (params: WideEventSamplingParams) => boolean;
2168
+ /**
2169
+ * Override the default log level when no explicit `level` is passed to
2170
+ * `emitWideEvent()`. When set, the resolved level uses this value instead
2171
+ * of `"info"`. This **does** affect sampling decisions — with `per_level`
2172
+ * strategy, the level from `emitLevel` determines which rate bucket applies.
2173
+ *
2174
+ * @default undefined (falls back to `"info"`)
2175
+ */
2176
+ emitLevel?: LogLevelType;
2177
+ }
2063
2178
  /**
2064
2179
  * Configuration options for creating a wide event mixin.
2065
2180
  */
@@ -2101,6 +2216,22 @@ interface WideEventMixinOptions {
2101
2216
  * @default false
2102
2217
  */
2103
2218
  errorsAsArray?: boolean;
2219
+ /**
2220
+ * Optional: Sampling configuration for wide events.
2221
+ * When provided, the mixin will randomly decide whether to emit or skip wide
2222
+ * events based on the configured rate(s).
2223
+ *
2224
+ * "error" and "fatal" default to a 100% keep rate, but can be overridden
2225
+ * via `perLevel` rates or the `shouldEmit` callback.
2226
+ *
2227
+ * @example
2228
+ * // Keep ~10% of wide events (excluding errors/fatals)
2229
+ * { sampling: { strategy: "default", rate: 0.1 } }
2230
+ *
2231
+ * // Per-level: keep all trace/debug, but sample info at 5%
2232
+ * { sampling: { strategy: "per_level", perLevel: { info: 0.05 } } }
2233
+ */
2234
+ sampling?: WideEventSamplingConfig;
2104
2235
  }
2105
2236
  /**
2106
2237
  * Configuration for emitting a wide event.
@@ -2250,7 +2381,6 @@ declare module "@loglayer/shared" {
2250
2381
  * wide event data across async boundaries. For Node.js, use `new AsyncLocalStorage()`
2251
2382
  * from `async_hooks`. For browser environments, provide your own compatible implementation.
2252
2383
  * @param options.includeContext - Whether to include withContext() data in emitted wide events (default: true)
2253
-
2254
2384
  *
2255
2385
  * @returns A LogLayer mixin registration object
2256
2386
  *
@@ -2283,4 +2413,4 @@ declare module "@loglayer/shared" {
2283
2413
  */
2284
2414
  declare function createWideEventMixin(options: WideEventMixinOptions): LogLayerMixinRegistration;
2285
2415
  //#endregion
2286
- export { type EmitWideEventConfig, type IWideEventMixin, type WideEventMixinOptions, createWideEventMixin };
2416
+ export { type EmitWideEventConfig, type IWideEventMixin, type WideEventMixinOptions, type WideEventSamplingConfig, type WideEventSamplingParams, type WideEventSamplingStrategy, createWideEventMixin };
package/dist/index.d.mts CHANGED
@@ -2060,6 +2060,121 @@ declare class LogBuilder implements ILogBuilder<LogBuilder, boolean> {
2060
2060
  */
2061
2061
  //#endregion
2062
2062
  //#region src/types.d.ts
2063
+ /**
2064
+ * Parameters passed to a custom `shouldEmit` sampling callback.
2065
+ * Provides the accumulated wide event data and the log level so the
2066
+ * callback can make an informed keep/drop decision.
2067
+ */
2068
+ interface WideEventSamplingParams {
2069
+ /**
2070
+ * The accumulated wide event data (wide events + optional context).
2071
+ * Contains the merged data that would be emitted if kept.
2072
+ */
2073
+ wideData: Record<string, any>;
2074
+ /**
2075
+ * The log level that would be used for the emission.
2076
+ */
2077
+ level: LogLevelType;
2078
+ }
2079
+ /**
2080
+ * Sampling strategy for wide events.
2081
+ *
2082
+ * - `"default"` — a single `rate` applies to all non-error/fatal levels.
2083
+ * - `"per_level"` — per-level rates keyed by LogLevelType; levels not in the
2084
+ * map use `rate` as a fallback.
2085
+ */
2086
+ type WideEventSamplingStrategy = "default" | "per_level";
2087
+ /**
2088
+ * Configuration for sampling wide event emissions.
2089
+ *
2090
+ * "error" and "fatal" levels default to a 100% keep rate, but can be
2091
+ * overridden by setting `perLevel` rates or via `shouldEmit`.
2092
+ */
2093
+ interface WideEventSamplingConfig {
2094
+ /**
2095
+ * The sampling strategy.
2096
+ *
2097
+ * - `"default"` — a single `rate` applies to all non-error/fatal levels.
2098
+ * - `"per_level"` — per-level rates from the `perLevel` map; levels not in
2099
+ * the map use `rate` as a fallback.
2100
+ *
2101
+ * @default "default"
2102
+ */
2103
+ strategy?: WideEventSamplingStrategy;
2104
+ /**
2105
+ * A rate between 0 and 1 that determines the fraction of events to keep.
2106
+ *
2107
+ * - `1` (or `true`) — keep 100% (sampling disabled)
2108
+ * - `0.1` — ~10% of events kept
2109
+ * - `0` (or `false`) — keep 0% (all dropped for sample-able levels)
2110
+ *
2111
+ * With `"default"` strategy this rate applies to all non-error/fatal levels.
2112
+ * With `"per_level"` strategy this field is **ignored** — unmapped levels
2113
+ * default to a 100% keep rate.
2114
+ *
2115
+ * @default 1
2116
+ */
2117
+ rate?: boolean | number;
2118
+ /**
2119
+ * Per-level sampling rates when strategy is `"per_level"`.
2120
+ * Keys are log level strings (e.g. `"trace"`, `"info"`, `"warn"`).
2121
+ * Levels not listed use `rate` as a fallback.
2122
+ *
2123
+ * **Important:** "error" and "fatal" default to a 100% keep rate, but can be
2124
+ * explicitly overridden by setting their rate in `perLevel` or using a
2125
+ * `shouldEmit` callback.
2126
+ *
2127
+ * The map is snapshotted at construction time; mutating it afterward has
2128
+ * no effect.
2129
+ *
2130
+ * @example
2131
+ * ```ts
2132
+ * {
2133
+ * strategy: "per_level",
2134
+ * perLevel: {
2135
+ * trace: 0.1,
2136
+ * debug: 0.3,
2137
+ * info: 0.5,
2138
+ * },
2139
+ * }
2140
+ * // warn, error, fatal are all 100%
2141
+ * ```
2142
+ */
2143
+ perLevel?: Partial<Record<LogLevelType, boolean | number>>;
2144
+ /**
2145
+ * A custom sampling callback that receives the wide event data and log
2146
+ * level, allowing you to make an informed keep/drop decision.
2147
+ *
2148
+ * When provided, this callback is invoked **in addition to** the built-in
2149
+ * rate-based sampling. An event is only kept when **both** the built-in
2150
+ * check passes (if `rate`/`perLevel` are configured) **and** the callback
2151
+ * returns `true`. If only `shouldEmit` is set (no `rate`), the callback
2152
+ * acts as the sole gate.
2153
+ *
2154
+ * **Note:** "error" and "fatal" default to a 100% keep rate, but can be
2155
+ * overridden by returning `false` from this callback.
2156
+ *
2157
+ * @example
2158
+ * ```ts
2159
+ * {
2160
+ * shouldEmit: ({ wideData, level }) => {
2161
+ * // Only emit wide events that have a userId
2162
+ * return !!wideData.userId;
2163
+ * },
2164
+ * }
2165
+ * ```
2166
+ */
2167
+ shouldEmit?: (params: WideEventSamplingParams) => boolean;
2168
+ /**
2169
+ * Override the default log level when no explicit `level` is passed to
2170
+ * `emitWideEvent()`. When set, the resolved level uses this value instead
2171
+ * of `"info"`. This **does** affect sampling decisions — with `per_level`
2172
+ * strategy, the level from `emitLevel` determines which rate bucket applies.
2173
+ *
2174
+ * @default undefined (falls back to `"info"`)
2175
+ */
2176
+ emitLevel?: LogLevelType;
2177
+ }
2063
2178
  /**
2064
2179
  * Configuration options for creating a wide event mixin.
2065
2180
  */
@@ -2101,6 +2216,22 @@ interface WideEventMixinOptions {
2101
2216
  * @default false
2102
2217
  */
2103
2218
  errorsAsArray?: boolean;
2219
+ /**
2220
+ * Optional: Sampling configuration for wide events.
2221
+ * When provided, the mixin will randomly decide whether to emit or skip wide
2222
+ * events based on the configured rate(s).
2223
+ *
2224
+ * "error" and "fatal" default to a 100% keep rate, but can be overridden
2225
+ * via `perLevel` rates or the `shouldEmit` callback.
2226
+ *
2227
+ * @example
2228
+ * // Keep ~10% of wide events (excluding errors/fatals)
2229
+ * { sampling: { strategy: "default", rate: 0.1 } }
2230
+ *
2231
+ * // Per-level: keep all trace/debug, but sample info at 5%
2232
+ * { sampling: { strategy: "per_level", perLevel: { info: 0.05 } } }
2233
+ */
2234
+ sampling?: WideEventSamplingConfig;
2104
2235
  }
2105
2236
  /**
2106
2237
  * Configuration for emitting a wide event.
@@ -2250,7 +2381,6 @@ declare module "@loglayer/shared" {
2250
2381
  * wide event data across async boundaries. For Node.js, use `new AsyncLocalStorage()`
2251
2382
  * from `async_hooks`. For browser environments, provide your own compatible implementation.
2252
2383
  * @param options.includeContext - Whether to include withContext() data in emitted wide events (default: true)
2253
-
2254
2384
  *
2255
2385
  * @returns A LogLayer mixin registration object
2256
2386
  *
@@ -2283,4 +2413,4 @@ declare module "@loglayer/shared" {
2283
2413
  */
2284
2414
  declare function createWideEventMixin(options: WideEventMixinOptions): LogLayerMixinRegistration;
2285
2415
  //#endregion
2286
- export { type EmitWideEventConfig, type IWideEventMixin, type WideEventMixinOptions, createWideEventMixin };
2416
+ export { type EmitWideEventConfig, type IWideEventMixin, type WideEventMixinOptions, type WideEventSamplingConfig, type WideEventSamplingParams, type WideEventSamplingStrategy, createWideEventMixin };
package/dist/index.mjs CHANGED
@@ -36,6 +36,45 @@ let LogLayerMixinAugmentType = /* @__PURE__ */ function(LogLayerMixinAugmentType
36
36
  //#endregion
37
37
  //#region src/mixin.ts
38
38
  /**
39
+ * Log levels that default to rate=1 (error/fatal) — can be overridden via `perLevel` or callback.
40
+ */
41
+ const EXEMPT_LEVELS = new Set(["error", "fatal"]);
42
+ /**
43
+ * Normalize a boolean or numeric rate to a number in [0, 1].
44
+ * `true` becomes 1, `false` becomes 0, numbers are clamped to [0, 1].
45
+ * `NaN`, `Infinity`, and `-Infinity` are treated as 0 (drop all).
46
+ */
47
+ function toRate(value) {
48
+ if (value === void 0) return 1;
49
+ if (typeof value === "boolean") return value ? 1 : 0;
50
+ if (typeof value !== "number" || !Number.isFinite(value)) return 0;
51
+ return Math.max(0, Math.min(1, value));
52
+ }
53
+ /**
54
+ * Run rate-based sampling (default or per_level strategy).
55
+ * Returns true if the rate check passes, false if dropped.
56
+ * Returns true for error/fatal by default, unless their rate is explicitly set in `perLevel`.
57
+ */
58
+ function runRateSampling(level, strategy, rate, perLevel) {
59
+ if (EXEMPT_LEVELS.has(level) && perLevel?.[level] === void 0) return true;
60
+ if (strategy === "per_level" && perLevel) {
61
+ const perRate = toRate(perLevel[level]);
62
+ if (perLevel[level] === void 0) {
63
+ const r = toRate(rate);
64
+ if (r === 1) return true;
65
+ if (r === 0) return false;
66
+ return Math.random() < r;
67
+ }
68
+ if (perRate === 1) return true;
69
+ if (perRate === 0) return false;
70
+ return Math.random() < perRate;
71
+ }
72
+ const r = toRate(rate);
73
+ if (r === 1) return true;
74
+ if (r === 0) return false;
75
+ return Math.random() < r;
76
+ }
77
+ /**
39
78
  * Creates a LogLayer mixin that adds wide event logging functionality.
40
79
  *
41
80
  * Wide events are comprehensive, self-contained log entries that capture an entire
@@ -47,7 +86,6 @@ let LogLayerMixinAugmentType = /* @__PURE__ */ function(LogLayerMixinAugmentType
47
86
  * wide event data across async boundaries. For Node.js, use `new AsyncLocalStorage()`
48
87
  * from `async_hooks`. For browser environments, provide your own compatible implementation.
49
88
  * @param options.includeContext - Whether to include withContext() data in emitted wide events (default: true)
50
-
51
89
  *
52
90
  * @returns A LogLayer mixin registration object
53
91
  *
@@ -84,6 +122,14 @@ function createWideEventMixin(options) {
84
122
  const wideEventField = options.wideEventField;
85
123
  const errorsAsArray = options.errorsAsArray ?? false;
86
124
  const errorField = options.errorField ?? (errorsAsArray ? "errors" : "error");
125
+ const snapshotPerLevel = options.sampling?.perLevel ? { ...options.sampling.perLevel } : void 0;
126
+ const samplingConfig = options.sampling ? {
127
+ strategy: options.sampling.strategy ?? "default",
128
+ rate: options.sampling.rate,
129
+ perLevel: snapshotPerLevel,
130
+ emitLevel: options.sampling.emitLevel,
131
+ shouldEmit: options.sampling.shouldEmit
132
+ } : void 0;
87
133
  function defaultErrorSerializer(err) {
88
134
  if (err instanceof Error) return {
89
135
  name: err.name,
@@ -180,11 +226,20 @@ function createWideEventMixin(options) {
180
226
  * Implementation for emitWideEvent
181
227
  */
182
228
  function emitWideEventImpl(config, self) {
229
+ const defaultLevel = samplingConfig?.emitLevel ?? "info";
230
+ const level = config.level ?? defaultLevel;
231
+ if (samplingConfig && !samplingConfig.shouldEmit && !runRateSampling(level, samplingConfig.strategy, samplingConfig.rate, samplingConfig.perLevel)) return;
183
232
  const store = asyncContext.getStore();
184
233
  const wideEventData = {};
185
234
  if (includeContext && store?._llContext) Object.assign(wideEventData, store._llContext);
186
235
  if (store?._llWideEvents) Object.assign(wideEventData, store._llWideEvents);
187
- const level = config.level ?? "info";
236
+ if (samplingConfig?.shouldEmit) try {
237
+ const callbackOk = samplingConfig.shouldEmit({
238
+ wideData: wideEventData,
239
+ level
240
+ });
241
+ if (!runRateSampling(level, samplingConfig.strategy, samplingConfig.rate, samplingConfig.perLevel) || !callbackOk) return;
242
+ } catch {}
188
243
  const metadataToEmit = wideEventField ? { [wideEventField]: wideEventData } : wideEventData;
189
244
  self.withMetadata(metadataToEmit)[level](config.message);
190
245
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@loglayer/mixin-wide-events",
3
3
  "description": "Adds wide event logging functionality to LogLayer for comprehensive, self-contained log entries.",
4
- "version": "1.0.1",
4
+ "version": "1.1.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.mjs",
@@ -37,8 +37,8 @@
37
37
  "tsdown": "0.22.0",
38
38
  "typescript": "6.0.3",
39
39
  "vitest": "4.1.7",
40
- "@loglayer/shared": "4.2.0",
41
40
  "@internal/tsconfig": "2.1.0",
41
+ "@loglayer/shared": "4.2.0",
42
42
  "loglayer": "9.2.0"
43
43
  },
44
44
  "peerDependencies": {},