@loglayer/mixin-wide-events 1.0.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.
- package/README.md +9 -0
- package/dist/index.cjs +213 -0
- package/dist/index.d.cts +2260 -0
- package/dist/index.d.mts +2260 -0
- package/dist/index.mjs +211 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @loglayer/mixin-wide-events
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@loglayer/mixin-wide-events)
|
|
4
|
+
[](https://www.npmjs.com/package/@loglayer/mixin-wide-events)
|
|
5
|
+
[](http://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
Adds wide event logging functionality to LogLayer for comprehensive, self-contained log entries.
|
|
8
|
+
|
|
9
|
+
[Documentation](https://loglayer.dev/mixins/wide-events) | [API Reference](https://loglayer.dev/mixins/wide-events)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
//#region ../../core/plugin/dist/index.js
|
|
4
|
+
/**
|
|
5
|
+
* List of plugin callbacks that can be called by the plugin manager.
|
|
6
|
+
*
|
|
7
|
+
* @see {@link https://loglayer.dev/plugins/creating-plugins.html#transformloglevel | transformLogLevel Docs}
|
|
8
|
+
* @see {@link https://loglayer.dev/plugins/creating-plugins.html#onbeforedataout | onBeforeDataOut Docs}
|
|
9
|
+
* @see {@link https://loglayer.dev/plugins/creating-plugins.html#shouldsendtologger | shouldSendToLogger Docs}
|
|
10
|
+
* @see {@link https://loglayer.dev/plugins/creating-plugins.html#onmetadatacalled | onMetadataCalled Docs}
|
|
11
|
+
* @see {@link https://loglayer.dev/plugins/creating-plugins.html#onbeforemessageout | onBeforeMessageOut Docs}
|
|
12
|
+
* @see {@link https://loglayer.dev/plugins/creating-plugins.html#oncontextcalled | onContextCalled Docs}
|
|
13
|
+
*/
|
|
14
|
+
let PluginCallbackType = /* @__PURE__ */ function(PluginCallbackType) {
|
|
15
|
+
PluginCallbackType["transformLogLevel"] = "transformLogLevel";
|
|
16
|
+
PluginCallbackType["onBeforeDataOut"] = "onBeforeDataOut";
|
|
17
|
+
PluginCallbackType["shouldSendToLogger"] = "shouldSendToLogger";
|
|
18
|
+
PluginCallbackType["onMetadataCalled"] = "onMetadataCalled";
|
|
19
|
+
PluginCallbackType["onBeforeMessageOut"] = "onBeforeMessageOut";
|
|
20
|
+
PluginCallbackType["onContextCalled"] = "onContextCalled";
|
|
21
|
+
return PluginCallbackType;
|
|
22
|
+
}({});
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region ../../core/loglayer/dist/index.js
|
|
26
|
+
const CALLBACK_LIST = [
|
|
27
|
+
PluginCallbackType.onBeforeDataOut,
|
|
28
|
+
PluginCallbackType.onMetadataCalled,
|
|
29
|
+
PluginCallbackType.onBeforeMessageOut,
|
|
30
|
+
PluginCallbackType.transformLogLevel,
|
|
31
|
+
PluginCallbackType.shouldSendToLogger,
|
|
32
|
+
PluginCallbackType.onContextCalled
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* The class that the mixin extends
|
|
36
|
+
*/
|
|
37
|
+
let LogLayerMixinAugmentType = /* @__PURE__ */ function(LogLayerMixinAugmentType) {
|
|
38
|
+
/**
|
|
39
|
+
* Mixin extends the LogBuilder prototype
|
|
40
|
+
*/
|
|
41
|
+
LogLayerMixinAugmentType["LogBuilder"] = "LogBuilder";
|
|
42
|
+
/**
|
|
43
|
+
* Mixin extends the LogLayer prototype
|
|
44
|
+
*/
|
|
45
|
+
LogLayerMixinAugmentType["LogLayer"] = "LogLayer";
|
|
46
|
+
return LogLayerMixinAugmentType;
|
|
47
|
+
}({});
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/mixin.ts
|
|
51
|
+
/**
|
|
52
|
+
* Creates a LogLayer mixin that adds wide event logging functionality.
|
|
53
|
+
*
|
|
54
|
+
* Wide events are comprehensive, self-contained log entries that capture an entire
|
|
55
|
+
* operation's context and data in a single emission. This pattern helps with
|
|
56
|
+
* observability by ensuring all relevant data is available in one log entry.
|
|
57
|
+
*
|
|
58
|
+
* @param options - Configuration options
|
|
59
|
+
* @param options.asyncContext - An async context implementation for propagating
|
|
60
|
+
* wide event data across async boundaries. For Node.js, use `new AsyncLocalStorage()`
|
|
61
|
+
* from `async_hooks`. For browser environments, provide your own compatible implementation.
|
|
62
|
+
* @param options.includeContext - Whether to include withContext() data in emitted wide events (default: true)
|
|
63
|
+
|
|
64
|
+
*
|
|
65
|
+
* @returns A LogLayer mixin registration object
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* import { AsyncLocalStorage } from "async_hooks";
|
|
70
|
+
* import { LogLayer, StructuredTransport } from "loglayer";
|
|
71
|
+
* import { createWideEventMixin } from "@loglayer/mixin-wide-events";
|
|
72
|
+
*
|
|
73
|
+
* const wideEventMixin = createWideEventMixin({
|
|
74
|
+
* asyncContext: new AsyncLocalStorage(),
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* const log = new LogLayer({
|
|
78
|
+
* transport: new StructuredTransport({ logger: console }),
|
|
79
|
+
* mixins: [wideEventMixin],
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* // Create a child logger for the request
|
|
83
|
+
* const logger = log.child().withContext({ requestId: "123" });
|
|
84
|
+
*
|
|
85
|
+
* // Accumulate data throughout the request
|
|
86
|
+
* logger.withWideEvents({ userId: "456" });
|
|
87
|
+
* await doSomething();
|
|
88
|
+
* logger.withWideEvents({ orderId: "789" });
|
|
89
|
+
*
|
|
90
|
+
* // Emit the wide event
|
|
91
|
+
* logger.emitWideEvent({ message: "Request completed" });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
function createWideEventMixin(options) {
|
|
95
|
+
const asyncContext = options.asyncContext;
|
|
96
|
+
const includeContext = options.includeContext ?? true;
|
|
97
|
+
const wideEventField = options.wideEventField;
|
|
98
|
+
/**
|
|
99
|
+
* Context tracker plugin - stores context in async storage
|
|
100
|
+
* for inclusion in wide events (only if includeContext is true)
|
|
101
|
+
*/
|
|
102
|
+
const contextTrackerPlugin = {
|
|
103
|
+
id: `@loglayer/wide-events-context-tracker-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
104
|
+
onBeforeDataOut: (params) => {
|
|
105
|
+
if (!includeContext) return params;
|
|
106
|
+
const store = asyncContext.getStore();
|
|
107
|
+
if (store && params.context && Object.keys(params.context).length > 0) {
|
|
108
|
+
if (!store._llContext) store._llContext = {};
|
|
109
|
+
Object.assign(store._llContext, params.context);
|
|
110
|
+
}
|
|
111
|
+
return params;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Deep merge utility - merges source into target recursively for nested objects.
|
|
116
|
+
* Filters out dangerous keys to prevent prototype pollution attacks.
|
|
117
|
+
* Uses WeakRef to detect circular references.
|
|
118
|
+
*/
|
|
119
|
+
function deepMerge(target, source, visited = /* @__PURE__ */ new WeakSet()) {
|
|
120
|
+
const result = { ...target };
|
|
121
|
+
for (const key of Object.keys(source)) {
|
|
122
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
123
|
+
const sourceValue = source[key];
|
|
124
|
+
const targetValue = result[key];
|
|
125
|
+
if (sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue !== null && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
126
|
+
if (visited.has(sourceValue)) continue;
|
|
127
|
+
visited.add(sourceValue);
|
|
128
|
+
result[key] = deepMerge(targetValue, sourceValue, visited);
|
|
129
|
+
} else result[key] = sourceValue;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Implementation for withWideEvents
|
|
135
|
+
*/
|
|
136
|
+
function withWideEventsImpl(data, self) {
|
|
137
|
+
const store = asyncContext.getStore();
|
|
138
|
+
if (store) {
|
|
139
|
+
if (!store._llWideEvents) store._llWideEvents = {};
|
|
140
|
+
store._llWideEvents = deepMerge(store._llWideEvents, data);
|
|
141
|
+
}
|
|
142
|
+
return self;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Implementation for getWideEvents
|
|
146
|
+
*/
|
|
147
|
+
function getWideEventsImpl(key, _self) {
|
|
148
|
+
const data = asyncContext.getStore()?._llWideEvents;
|
|
149
|
+
if (!data) return key ? void 0 : {};
|
|
150
|
+
if (key !== void 0) return data[key];
|
|
151
|
+
return { ...data };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Implementation for clearWideEvents
|
|
155
|
+
*/
|
|
156
|
+
function clearWideEventsImpl(key, self) {
|
|
157
|
+
const store = asyncContext.getStore();
|
|
158
|
+
if (store?._llWideEvents) if (key !== void 0) delete store._llWideEvents[key];
|
|
159
|
+
else store._llWideEvents = {};
|
|
160
|
+
return self;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Implementation for emitWideEvent
|
|
164
|
+
*/
|
|
165
|
+
function emitWideEventImpl(config, self) {
|
|
166
|
+
const store = asyncContext.getStore();
|
|
167
|
+
const wideEventData = {};
|
|
168
|
+
if (includeContext && store?._llContext) Object.assign(wideEventData, store._llContext);
|
|
169
|
+
if (store?._llWideEvents) Object.assign(wideEventData, store._llWideEvents);
|
|
170
|
+
if (config.metadata) Object.assign(wideEventData, config.metadata);
|
|
171
|
+
const level = config.level ?? "info";
|
|
172
|
+
const metadataToEmit = wideEventField ? { [wideEventField]: wideEventData } : wideEventData;
|
|
173
|
+
self.withMetadata(metadataToEmit)[level](config.message);
|
|
174
|
+
return self;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
mixinsToAdd: [{
|
|
178
|
+
augmentationType: LogLayerMixinAugmentType.LogLayer,
|
|
179
|
+
augment: (prototype) => {
|
|
180
|
+
prototype.withWideEvents = function(data) {
|
|
181
|
+
return withWideEventsImpl(data, this);
|
|
182
|
+
};
|
|
183
|
+
prototype.getWideEvents = function(key) {
|
|
184
|
+
return getWideEventsImpl(key, this);
|
|
185
|
+
};
|
|
186
|
+
prototype.clearWideEvents = function(key) {
|
|
187
|
+
return clearWideEventsImpl(key, this);
|
|
188
|
+
};
|
|
189
|
+
prototype.emitWideEvent = function(config) {
|
|
190
|
+
return emitWideEventImpl(config, this);
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
augmentMock: (prototype) => {
|
|
194
|
+
prototype.withWideEvents = function(data) {
|
|
195
|
+
return withWideEventsImpl(data, this);
|
|
196
|
+
};
|
|
197
|
+
prototype.getWideEvents = function(key) {
|
|
198
|
+
return getWideEventsImpl(key, this);
|
|
199
|
+
};
|
|
200
|
+
prototype.clearWideEvents = function(key) {
|
|
201
|
+
return clearWideEventsImpl(key, this);
|
|
202
|
+
};
|
|
203
|
+
prototype.emitWideEvent = function(config) {
|
|
204
|
+
return emitWideEventImpl(config, this);
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}],
|
|
208
|
+
pluginsToAdd: [contextTrackerPlugin]
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
//#endregion
|
|
213
|
+
exports.createWideEventMixin = createWideEventMixin;
|