@twin.org/tracing-facades 0.9.3-next.4 → 0.9.3-next.6
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/dist/es/tracingFacade.js
CHANGED
|
@@ -59,12 +59,22 @@ export class TracingFacade {
|
|
|
59
59
|
*/
|
|
60
60
|
static _ASYNC_FUNCTION_TAG = "[object AsyncFunction]";
|
|
61
61
|
/**
|
|
62
|
-
* The component recording the spans
|
|
62
|
+
* The type of the component recording the spans.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
_tracingComponentType;
|
|
66
|
+
/**
|
|
67
|
+
* The component recording the spans, resolved on first use.
|
|
63
68
|
* @internal
|
|
64
69
|
*/
|
|
65
70
|
_tracingComponent;
|
|
66
71
|
/**
|
|
67
|
-
* The component for logging a tracing failure.
|
|
72
|
+
* The type of the component for logging a tracing failure.
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
_loggingComponentType;
|
|
76
|
+
/**
|
|
77
|
+
* The component for logging a tracing failure, resolved on first use.
|
|
68
78
|
* @internal
|
|
69
79
|
*/
|
|
70
80
|
_loggingComponent;
|
|
@@ -108,8 +118,8 @@ export class TracingFacade {
|
|
|
108
118
|
* @param options The options for the facade.
|
|
109
119
|
*/
|
|
110
120
|
constructor(options) {
|
|
111
|
-
this.
|
|
112
|
-
this.
|
|
121
|
+
this._tracingComponentType = options?.tracingComponentType;
|
|
122
|
+
this._loggingComponentType = options?.loggingComponentType;
|
|
113
123
|
this._excludeParams = (options?.config?.excludeParams ?? TracingFacade.DEFAULT_EXCLUDE_PARAMS).map(pattern => pattern.split("."));
|
|
114
124
|
this._excludeMethods = (options?.config?.excludeMethods ?? TracingFacade.DEFAULT_EXCLUDE_METHODS).map(pattern => pattern.split("."));
|
|
115
125
|
this._includeObjects = (options?.config?.includeObjects ?? []).map(pattern => {
|
|
@@ -137,16 +147,23 @@ export class TracingFacade {
|
|
|
137
147
|
/**
|
|
138
148
|
* Wrap the target so its method calls are recorded as spans.
|
|
139
149
|
* @param target The component to wrap.
|
|
140
|
-
* @returns The wrapped component
|
|
150
|
+
* @returns The wrapped component.
|
|
141
151
|
*/
|
|
142
152
|
wrap(target) {
|
|
143
|
-
if (Is.empty(this._tracingComponent)) {
|
|
144
|
-
return target;
|
|
145
|
-
}
|
|
146
153
|
return new Proxy(target, {
|
|
147
154
|
get: (t, prop, receiver) => this.interceptGet(t, prop, receiver)
|
|
148
155
|
});
|
|
149
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the component recording the spans, resolving it from the factory on first use.
|
|
159
|
+
* @returns The component, or undefined when it does not resolve.
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
tracingComponent() {
|
|
163
|
+
this._tracingComponent ??= ComponentFactory.getIfExists(this._tracingComponentType);
|
|
164
|
+
this._loggingComponent ??= ComponentFactory.getIfExists(this._loggingComponentType);
|
|
165
|
+
return this._tracingComponent;
|
|
166
|
+
}
|
|
150
167
|
/**
|
|
151
168
|
* Intercept a property read, returning a replacement function for a method which should be
|
|
152
169
|
* traced, and the value itself for anything else.
|
|
@@ -189,19 +206,25 @@ export class TracingFacade {
|
|
|
189
206
|
}
|
|
190
207
|
let wrapper = wrappers.get(method);
|
|
191
208
|
if (Is.undefined(wrapper)) {
|
|
192
|
-
wrapper = async (...args) =>
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
195
|
-
|
|
196
|
-
if (!Is.undefined(recorded)) {
|
|
197
|
-
span.attributes = {
|
|
198
|
-
...span.attributes,
|
|
199
|
-
[TracingFacadeAttributes.Result]: recorded
|
|
200
|
-
};
|
|
201
|
-
}
|
|
209
|
+
wrapper = async (...args) => {
|
|
210
|
+
const tracingComponent = this.tracingComponent();
|
|
211
|
+
if (Is.empty(tracingComponent)) {
|
|
212
|
+
return method.apply(target, args);
|
|
202
213
|
}
|
|
203
|
-
return
|
|
204
|
-
|
|
214
|
+
return TracingHelper.withSpan(tracingComponent, Is.stringValue(className) ? `method:${className}.${name}` : `method:${name}`, { attributes: this.callAttributes(className, name, method, args) }, async (span) => {
|
|
215
|
+
const resolved = await method.apply(target, args);
|
|
216
|
+
if (!Is.empty(span)) {
|
|
217
|
+
const recorded = this.attributeValue([className, name, TracingFacade.RESULT_NAME], resolved);
|
|
218
|
+
if (!Is.undefined(recorded)) {
|
|
219
|
+
span.attributes = {
|
|
220
|
+
...span.attributes,
|
|
221
|
+
[TracingFacadeAttributes.Result]: recorded
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return resolved;
|
|
226
|
+
}, this._loggingComponent);
|
|
227
|
+
};
|
|
205
228
|
wrappers.set(method, wrapper);
|
|
206
229
|
}
|
|
207
230
|
return wrapper;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracingFacade.js","sourceRoot":"","sources":["../../src/tracingFacade.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ComponentFactory, Is, type IComponent, type IFacade } from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { TracingHelper, type ITracingComponent } from \"@twin.org/tracing-models\";\nimport type { ITracingFacadeConstructorOptions } from \"./models/ITracingFacadeConstructorOptions.js\";\nimport { TracingFacadeAttributes } from \"./models/tracingFacadeAttributes.js\";\n\n/**\n * Facade which records a span for each external call to an async method on the component it wraps,\n * so a component can be traced without being modified.\n *\n * Only methods declared async are traced. A span cannot be opened synchronously, so wrapping a\n * synchronous method would make it return a promise and break the contract of the wrapped\n * component.\n */\nexport class TracingFacade implements IFacade, IComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TracingFacade>();\n\n\t/**\n\t * The methods that are excluded from tracing by default.\n\t */\n\tpublic static readonly DEFAULT_EXCLUDE_METHODS: string[] = [\n\t\t\"start\",\n\t\t\"stop\",\n\t\t\"bootstrap\",\n\t\t\"teardown\"\n\t];\n\n\t/**\n\t * The parameters that are excluded from recording by default.\n\t */\n\tpublic static readonly DEFAULT_EXCLUDE_PARAMS: string[] = [\n\t\t\"password\",\n\t\t\"token\",\n\t\t\"apiKey\",\n\t\t\"mnemonic\"\n\t];\n\n\t/**\n\t * The default maximum length of a recorded string.\n\t */\n\tpublic static readonly DEFAULT_MAX_STRING_LENGTH: number = 256;\n\n\t/**\n\t * The default maximum number of entries recorded for an array.\n\t */\n\tpublic static readonly DEFAULT_MAX_ARRAY_LENGTH: number = 10;\n\n\t/**\n\t * The name a returned value is matched under, so it can be excluded or have a property\n\t * selected with the same patterns as a parameter.\n\t */\n\tpublic static readonly RESULT_NAME: string = \"resolved\";\n\n\t/**\n\t * A camel case parameter name, used to check the names read from the source are trustworthy.\n\t * @internal\n\t */\n\tprivate static readonly _IDENTIFIER: RegExp = /^[a-z][A-Za-z0-9]*$/;\n\n\t/**\n\t * The result of Object.prototype.toString for a method declared async. Used in preference to\n\t * the constructor name, which throws for a function with no prototype.\n\t * @internal\n\t */\n\tprivate static readonly _ASYNC_FUNCTION_TAG: string = \"[object AsyncFunction]\";\n\n\t/**\n\t * The component recording the spans, when absent every call passes straight through.\n\t * @internal\n\t */\n\tprivate readonly _tracingComponent?: ITracingComponent;\n\n\t/**\n\t * The component for logging a tracing failure.\n\t * @internal\n\t */\n\tprivate readonly _loggingComponent?: ILoggingComponent;\n\n\t/**\n\t * Patterns for parameters whose values are never recorded.\n\t * @internal\n\t */\n\tprivate readonly _excludeParams: string[][];\n\n\t/**\n\t * Patterns for methods which are not intercepted.\n\t * @internal\n\t */\n\tprivate readonly _excludeMethods: string[][];\n\n\t/**\n\t * Patterns for parameters to record even when the value is not primitive.\n\t * @internal\n\t */\n\tprivate readonly _includeObjects: { path: string[]; root: string[]; last: string }[];\n\n\t/**\n\t * The maximum length of a recorded string.\n\t * @internal\n\t */\n\tprivate readonly _maxStringLength: number;\n\n\t/**\n\t * The maximum number of entries recorded for an array.\n\t * @internal\n\t */\n\tprivate readonly _maxArrayLength: number;\n\n\t/**\n\t * The wrapper for each method, held against the target as well as the method.\n\t * @internal\n\t */\n\tprivate readonly _wrappers: WeakMap<\n\t\tobject,\n\t\tWeakMap<object, (...args: unknown[]) => Promise<unknown>>\n\t>;\n\n\t/**\n\t * The parameter names of each method, parsed once on first use.\n\t * @internal\n\t */\n\tprivate readonly _paramNames: WeakMap<object, string[]>;\n\n\t/**\n\t * Create a new instance of TracingFacade.\n\t * @param options The options for the facade.\n\t */\n\tconstructor(options?: ITracingFacadeConstructorOptions) {\n\t\tthis._tracingComponent = ComponentFactory.getIfExists(options?.tracingComponentType);\n\t\tthis._loggingComponent = ComponentFactory.getIfExists(options?.loggingComponentType);\n\t\tthis._excludeParams = (\n\t\t\toptions?.config?.excludeParams ?? TracingFacade.DEFAULT_EXCLUDE_PARAMS\n\t\t).map(pattern => pattern.split(\".\"));\n\t\tthis._excludeMethods = (\n\t\t\toptions?.config?.excludeMethods ?? TracingFacade.DEFAULT_EXCLUDE_METHODS\n\t\t).map(pattern => pattern.split(\".\"));\n\t\tthis._includeObjects = (options?.config?.includeObjects ?? []).map(pattern => {\n\t\t\tconst segments = pattern.split(\".\");\n\n\t\t\treturn {\n\t\t\t\tpath: segments,\n\t\t\t\troot: segments.slice(0, -1),\n\t\t\t\tlast: segments[segments.length - 1]\n\t\t\t};\n\t\t});\n\t\tthis._maxStringLength =\n\t\t\toptions?.config?.maxStringLength ?? TracingFacade.DEFAULT_MAX_STRING_LENGTH;\n\t\tthis._maxArrayLength =\n\t\t\toptions?.config?.maxArrayLength ?? TracingFacade.DEFAULT_MAX_ARRAY_LENGTH;\n\t\tthis._wrappers = new WeakMap();\n\t\tthis._paramNames = new WeakMap();\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TracingFacade.CLASS_NAME;\n\t}\n\n\t/**\n\t * Wrap the target so its method calls are recorded as spans.\n\t * @param target The component to wrap.\n\t * @returns The wrapped component, or the target itself when there is no tracing component.\n\t */\n\tpublic wrap<T>(target: T): T {\n\t\tif (Is.empty(this._tracingComponent)) {\n\t\t\treturn target;\n\t\t}\n\n\t\treturn new Proxy(target as { [key: string]: unknown }, {\n\t\t\tget: (t, prop, receiver): unknown => this.interceptGet(t, prop, receiver)\n\t\t}) as T;\n\t}\n\n\t/**\n\t * Intercept a property read, returning a replacement function for a method which should be\n\t * traced, and the value itself for anything else.\n\t * @param target The component being wrapped.\n\t * @param prop The property being read.\n\t * @param receiver The proxy the read was made through.\n\t * @returns The value for the property.\n\t * @internal\n\t */\n\tprivate interceptGet(\n\t\ttarget: { [key: string]: unknown },\n\t\tprop: string | symbol,\n\t\treceiver: unknown\n\t): unknown {\n\t\tconst value = Reflect.get(target, prop, receiver);\n\n\t\tif (!Is.function(value) || !Is.string(prop)) {\n\t\t\treturn value;\n\t\t}\n\n\t\t// Wrapping a synchronous method would make it return a promise. The declaration is tested\n\t\t// rather than the return value, which would open the span too late to nest inner calls.\n\t\tif (Object.prototype.toString.call(value) !== TracingFacade._ASYNC_FUNCTION_TAG) {\n\t\t\treturn value;\n\t\t}\n\n\t\tconst className = this.targetClassName(target);\n\n\t\tif (this.matchesAny(this._excludeMethods, [className, prop])) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn this.tracedMethod(target, className, prop, value);\n\t}\n\n\t/**\n\t * Get the wrapper for a method, building it on first use.\n\t * @param target The component being wrapped.\n\t * @param className The name of the component class.\n\t * @param name The name of the method.\n\t * @param method The method to wrap.\n\t * @returns The wrapper, which is the same function for every read of that method.\n\t * @internal\n\t */\n\tprivate tracedMethod(\n\t\ttarget: { [key: string]: unknown },\n\t\tclassName: string,\n\t\tname: string,\n\t\tmethod: (...args: unknown[]) => unknown\n\t): (...args: unknown[]) => Promise<unknown> {\n\t\tlet wrappers = this._wrappers.get(target);\n\n\t\tif (Is.undefined(wrappers)) {\n\t\t\twrappers = new WeakMap();\n\t\t\tthis._wrappers.set(target, wrappers);\n\t\t}\n\n\t\tlet wrapper = wrappers.get(method);\n\n\t\tif (Is.undefined(wrapper)) {\n\t\t\twrapper = async (...args: unknown[]): Promise<unknown> =>\n\t\t\t\tTracingHelper.withSpan(\n\t\t\t\t\tthis._tracingComponent,\n\t\t\t\t\tIs.stringValue(className) ? `method:${className}.${name}` : `method:${name}`,\n\t\t\t\t\t{ attributes: this.callAttributes(className, name, method, args) },\n\t\t\t\t\tasync span => {\n\t\t\t\t\t\tconst resolved = await method.apply(target, args);\n\n\t\t\t\t\t\tif (!Is.empty(span)) {\n\t\t\t\t\t\t\tconst recorded = this.attributeValue(\n\t\t\t\t\t\t\t\t[className, name, TracingFacade.RESULT_NAME],\n\t\t\t\t\t\t\t\tresolved\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (!Is.undefined(recorded)) {\n\t\t\t\t\t\t\t\tspan.attributes = {\n\t\t\t\t\t\t\t\t\t...span.attributes,\n\t\t\t\t\t\t\t\t\t[TracingFacadeAttributes.Result]: recorded\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn resolved;\n\t\t\t\t\t},\n\t\t\t\t\tthis._loggingComponent\n\t\t\t\t);\n\n\t\t\twrappers.set(method, wrapper);\n\t\t}\n\n\t\treturn wrapper;\n\t}\n\n\t/**\n\t * Build the attributes describing a call.\n\t * @param className The name of the component class.\n\t * @param name The name of the method.\n\t * @param method The method being called.\n\t * @param args The arguments the method was called with.\n\t * @returns The attributes.\n\t * @internal\n\t */\n\tprivate callAttributes(\n\t\tclassName: string,\n\t\tname: string,\n\t\tmethod: (...args: unknown[]) => unknown,\n\t\targs: unknown[]\n\t): { [key: string]: unknown } {\n\t\tconst attributes: { [key: string]: unknown } = {\n\t\t\t[TracingFacadeAttributes.Method]: Is.stringValue(className) ? `${className}.${name}` : name\n\t\t};\n\n\t\tconst paramNames = this.paramNames(method);\n\n\t\tfor (let i = 0; i < args.length; i++) {\n\t\t\tconst paramName = paramNames[i];\n\n\t\t\tif (Is.stringValue(paramName)) {\n\t\t\t\tconst recorded = this.attributeValue([className, name, paramName], args[i]);\n\n\t\t\t\tif (!Is.undefined(recorded)) {\n\t\t\t\t\tattributes[`${TracingFacadeAttributes.ParamPrefix}${paramName}`] = recorded;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn attributes;\n\t}\n\n\t/**\n\t * Decide what is recorded for a value, applying the exclusions, the object selection and the\n\t * length limits.\n\t * @param path The class, method and parameter name the value belongs to.\n\t * @param value The value to record.\n\t * @returns The value to record, or undefined when nothing is recorded.\n\t * @internal\n\t */\n\tprivate attributeValue(path: string[], value: unknown): unknown {\n\t\tif (this.matchesAny(this._excludeParams, path)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst primitive = this.primitiveValue(value);\n\n\t\tif (!Is.undefined(primitive)) {\n\t\t\treturn primitive;\n\t\t}\n\n\t\tconst included = this.included(path);\n\n\t\tif (!included.record) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (Is.arrayValue(included.properties)) {\n\t\t\tif (!Is.object<{ [key: string]: unknown }>(value)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst selected: { [key: string]: unknown } = {};\n\t\t\tfor (const property of included.properties) {\n\t\t\t\tselected[property] = value[property];\n\t\t\t}\n\n\t\t\treturn selected;\n\t\t}\n\n\t\treturn Is.array(value) ? value.slice(0, this._maxArrayLength) : value;\n\t}\n\n\t/**\n\t * Convert a value which can be recorded as a span attribute directly.\n\t * @param value The value to convert.\n\t * @returns The value to record, or undefined when it is not a primitive.\n\t * @internal\n\t */\n\tprivate primitiveValue(value: unknown): unknown {\n\t\tif (Is.string(value)) {\n\t\t\treturn value.length > this._maxStringLength ? value.slice(0, this._maxStringLength) : value;\n\t\t}\n\n\t\t// A bigint cannot be serialised by JSON.stringify, so it is converted here.\n\t\tif (Is.bigint(value)) {\n\t\t\treturn String(value);\n\t\t}\n\n\t\tif (Is.number(value) || Is.boolean(value) || Is.null(value)) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Decide whether a non primitive value is recorded, and which of its properties are.\n\t * @param path The class, method and parameter name the value belongs to.\n\t * @returns Whether to record the value, and the properties to record when the patterns select\n\t * them rather than the whole value.\n\t * @internal\n\t */\n\tprivate included(path: string[]): { record: boolean; properties?: string[] } {\n\t\tconst properties: string[] = [];\n\n\t\tfor (const pattern of this._includeObjects) {\n\t\t\t// The parameter itself is named, so the whole value is recorded.\n\t\t\tif (this.matches(pattern.path, path)) {\n\t\t\t\treturn { record: true };\n\t\t\t}\n\n\t\t\tif (pattern.root.length > 0 && this.matches(pattern.root, path)) {\n\t\t\t\tproperties.push(pattern.last);\n\t\t\t}\n\t\t}\n\n\t\treturn properties.length > 0 ? { record: true, properties } : { record: false };\n\t}\n\n\t/**\n\t * Does any of the patterns match the path.\n\t * @param patterns The patterns to test.\n\t * @param path The path to test them against.\n\t * @returns True when one of the patterns matches.\n\t * @internal\n\t */\n\tprivate matchesAny(patterns: string[][], path: string[]): boolean {\n\t\treturn patterns.some(pattern => this.matches(pattern, path));\n\t}\n\n\t/**\n\t * Does a dot separated pattern match a path. The pattern is matched from the right, so a\n\t * pattern shorter than the path leaves the leading segments unconstrained, and a `*` matches\n\t * any single segment.\n\t * @param segments The segments of the pattern to test.\n\t * @param path The path to test it against.\n\t * @returns True when the pattern matches.\n\t * @internal\n\t */\n\tprivate matches(segments: string[], path: string[]): boolean {\n\t\tif (segments.length > path.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst offset = path.length - segments.length;\n\n\t\treturn segments.every((segment, index) => segment === \"*\" || segment === path[offset + index]);\n\t}\n\n\t/**\n\t * Get the name of the class of the component being wrapped, which every IComponent\n\t * implementation provides.\n\t * @param target The component to get the name of.\n\t * @returns The class name, or an empty string when the component does not provide one.\n\t * @internal\n\t */\n\tprivate targetClassName(target: { [key: string]: unknown }): string {\n\t\tconst method = target.className;\n\n\t\tif (Is.function(method)) {\n\t\t\tconst name = method.call(target);\n\n\t\t\tif (Is.stringValue(name)) {\n\t\t\t\treturn name;\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * Get the parameter names of a method, read from its source and held for reuse. An empty list\n\t * is returned when the names cannot be read reliably, so no parameter values are recorded\n\t * rather than being recorded against a name which may be wrong.\n\t * @param method The method to read the parameter names of.\n\t * @returns The parameter names in order, or an empty list when they cannot be trusted.\n\t * @internal\n\t */\n\tprivate paramNames(method: (...args: unknown[]) => unknown): string[] {\n\t\tlet names = this._paramNames.get(method);\n\n\t\tif (Is.undefined(names)) {\n\t\t\tconst source = method.toString();\n\t\t\tconst open = source.indexOf(\"(\");\n\t\t\tconst close = source.indexOf(\")\", open);\n\n\t\t\tnames =\n\t\t\t\topen === -1 || close === -1\n\t\t\t\t\t? []\n\t\t\t\t\t: source\n\t\t\t\t\t\t\t.slice(open + 1, close)\n\t\t\t\t\t\t\t.split(\",\")\n\t\t\t\t\t\t\t.map(param => param.trim())\n\t\t\t\t\t\t\t.filter(param => param.length > 0);\n\n\t\t\t// Anything which is not a plain identifier means the whole list is suspect, so nothing is trusted.\n\t\t\tif (!names.every(name => TracingFacade._IDENTIFIER.test(name))) {\n\t\t\t\tnames = [];\n\t\t\t}\n\n\t\t\tthis._paramNames.set(method, names);\n\t\t}\n\n\t\treturn names;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tracingFacade.js","sourceRoot":"","sources":["../../src/tracingFacade.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAiC,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAE,aAAa,EAA0B,MAAM,0BAA0B,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE9E;;;;;;;GAOG;AACH,MAAM,OAAO,aAAa;IACzB;;OAEG;IACI,MAAM,CAAU,UAAU,mBAAmC;IAEpE;;OAEG;IACI,MAAM,CAAU,uBAAuB,GAAa;QAC1D,OAAO;QACP,MAAM;QACN,WAAW;QACX,UAAU;KACV,CAAC;IAEF;;OAEG;IACI,MAAM,CAAU,sBAAsB,GAAa;QACzD,UAAU;QACV,OAAO;QACP,QAAQ;QACR,UAAU;KACV,CAAC;IAEF;;OAEG;IACI,MAAM,CAAU,yBAAyB,GAAW,GAAG,CAAC;IAE/D;;OAEG;IACI,MAAM,CAAU,wBAAwB,GAAW,EAAE,CAAC;IAE7D;;;OAGG;IACI,MAAM,CAAU,WAAW,GAAW,UAAU,CAAC;IAExD;;;OAGG;IACK,MAAM,CAAU,WAAW,GAAW,qBAAqB,CAAC;IAEpE;;;;OAIG;IACK,MAAM,CAAU,mBAAmB,GAAW,wBAAwB,CAAC;IAE/E;;;OAGG;IACc,qBAAqB,CAAU;IAEhD;;;OAGG;IACK,iBAAiB,CAAqB;IAE9C;;;OAGG;IACc,qBAAqB,CAAU;IAEhD;;;OAGG;IACK,iBAAiB,CAAqB;IAE9C;;;OAGG;IACc,cAAc,CAAa;IAE5C;;;OAGG;IACc,eAAe,CAAa;IAE7C;;;OAGG;IACc,eAAe,CAAqD;IAErF;;;OAGG;IACc,gBAAgB,CAAS;IAE1C;;;OAGG;IACc,eAAe,CAAS;IAEzC;;;OAGG;IACc,SAAS,CAGxB;IAEF;;;OAGG;IACc,WAAW,CAA4B;IAExD;;;OAGG;IACH,YAAY,OAA0C;QACrD,IAAI,CAAC,qBAAqB,GAAG,OAAO,EAAE,oBAAoB,CAAC;QAC3D,IAAI,CAAC,qBAAqB,GAAG,OAAO,EAAE,oBAAoB,CAAC;QAC3D,IAAI,CAAC,cAAc,GAAG,CACrB,OAAO,EAAE,MAAM,EAAE,aAAa,IAAI,aAAa,CAAC,sBAAsB,CACtE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,eAAe,GAAG,CACtB,OAAO,EAAE,MAAM,EAAE,cAAc,IAAI,aAAa,CAAC,uBAAuB,CACxE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YAC5E,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAEpC,OAAO;gBACN,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC3B,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;aACnC,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB;YACpB,OAAO,EAAE,MAAM,EAAE,eAAe,IAAI,aAAa,CAAC,yBAAyB,CAAC;QAC7E,IAAI,CAAC,eAAe;YACnB,OAAO,EAAE,MAAM,EAAE,cAAc,IAAI,aAAa,CAAC,wBAAwB,CAAC;QAC3E,IAAI,CAAC,SAAS,GAAG,IAAI,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,OAAO,EAAE,CAAC;IAClC,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,OAAO,aAAa,CAAC,UAAU,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACI,IAAI,CAAI,MAAS;QACvB,OAAO,IAAI,KAAK,CAAC,MAAoC,EAAE;YACtD,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAW,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC;SACzE,CAAM,CAAC;IACT,CAAC;IAED;;;;OAIG;IACK,gBAAgB;QACvB,IAAI,CAAC,iBAAiB,KAAK,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACpF,IAAI,CAAC,iBAAiB,KAAK,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAEpF,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAC/B,CAAC;IAED;;;;;;;;OAQG;IACK,YAAY,CACnB,MAAkC,EAClC,IAAqB,EACrB,QAAiB;QAEjB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAElD,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,OAAO,KAAK,CAAC;QACd,CAAC;QAED,0FAA0F;QAC1F,wFAAwF;QACxF,IAAI,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,aAAa,CAAC,mBAAmB,EAAE,CAAC;YACjF,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAE/C,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YAC9D,OAAO,KAAK,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED;;;;;;;;OAQG;IACK,YAAY,CACnB,MAAkC,EAClC,SAAiB,EACjB,IAAY,EACZ,MAAuC;QAEvC,IAAI,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE1C,IAAI,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,QAAQ,GAAG,IAAI,OAAO,EAAE,CAAC;YACzB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEnC,IAAI,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,KAAK,EAAE,GAAG,IAAe,EAAoB,EAAE;gBACxD,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAEjD,IAAI,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;oBAChC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBACnC,CAAC;gBAED,OAAO,aAAa,CAAC,QAAQ,CAC5B,gBAAgB,EAChB,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,EAC5E,EAAE,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAClE,KAAK,EAAC,IAAI,EAAC,EAAE;oBACZ,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;oBAElD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CACnC,CAAC,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,EAC5C,QAAQ,CACR,CAAC;wBAEF,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC7B,IAAI,CAAC,UAAU,GAAG;gCACjB,GAAG,IAAI,CAAC,UAAU;gCAClB,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,QAAQ;6BAC1C,CAAC;wBACH,CAAC;oBACF,CAAC;oBAED,OAAO,QAAQ,CAAC;gBACjB,CAAC,EACD,IAAI,CAAC,iBAAiB,CACtB,CAAC;YACH,CAAC,CAAC;YAEF,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,OAAO,CAAC;IAChB,CAAC;IAED;;;;;;;;OAQG;IACK,cAAc,CACrB,SAAiB,EACjB,IAAY,EACZ,MAAuC,EACvC,IAAe;QAEf,MAAM,UAAU,GAA+B;YAC9C,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI;SAC3F,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAE3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAEhC,IAAI,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBAE5E,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC7B,UAAU,CAAC,GAAG,uBAAuB,CAAC,WAAW,GAAG,SAAS,EAAE,CAAC,GAAG,QAAQ,CAAC;gBAC7E,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,UAAU,CAAC;IACnB,CAAC;IAED;;;;;;;OAOG;IACK,cAAc,CAAC,IAAc,EAAE,KAAc;QACpD,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAE7C,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAErC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC;QAClB,CAAC;QAED,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,EAAE,CAAC,MAAM,CAA6B,KAAK,CAAC,EAAE,CAAC;gBACnD,OAAO,SAAS,CAAC;YAClB,CAAC;YAED,MAAM,QAAQ,GAA+B,EAAE,CAAC;YAChD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC5C,QAAQ,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;YACtC,CAAC;YAED,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,OAAO,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACK,cAAc,CAAC,KAAc;QACpC,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7F,CAAC;QAED,4EAA4E;QAC5E,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7D,OAAO,KAAK,CAAC;QACd,CAAC;QAED,OAAO,SAAS,CAAC;IAClB,CAAC;IAED;;;;;;OAMG;IACK,QAAQ,CAAC,IAAc;QAC9B,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC5C,iEAAiE;YACjE,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACtC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACzB,CAAC;YAED,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACjE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC;QAED,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACjF,CAAC;IAED;;;;;;OAMG;IACK,UAAU,CAAC,QAAoB,EAAE,IAAc;QACtD,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;;;;OAQG;IACK,OAAO,CAAC,QAAkB,EAAE,IAAc;QACjD,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAE7C,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;IAChG,CAAC;IAED;;;;;;OAMG;IACK,eAAe,CAAC,MAAkC;QACzD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;QAEhC,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAEjC,IAAI,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;QAED,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;;;;;OAOG;IACK,UAAU,CAAC,MAAuC;QACzD,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEzC,IAAI,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAExC,KAAK;gBACJ,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;oBAC1B,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,MAAM;yBACL,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC;yBACtB,KAAK,CAAC,GAAG,CAAC;yBACV,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;yBAC1B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAEvC,mGAAmG;YACnG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAChE,KAAK,GAAG,EAAE,CAAC;YACZ,CAAC;YAED,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;QAED,OAAO,KAAK,CAAC;IACd,CAAC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { ComponentFactory, Is, type IComponent, type IFacade } from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { TracingHelper, type ITracingComponent } from \"@twin.org/tracing-models\";\nimport type { ITracingFacadeConstructorOptions } from \"./models/ITracingFacadeConstructorOptions.js\";\nimport { TracingFacadeAttributes } from \"./models/tracingFacadeAttributes.js\";\n\n/**\n * Facade which records a span for each external call to an async method on the component it wraps,\n * so a component can be traced without being modified.\n *\n * Only methods declared async are traced. A span cannot be opened synchronously, so wrapping a\n * synchronous method would make it return a promise and break the contract of the wrapped\n * component.\n */\nexport class TracingFacade implements IFacade, IComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TracingFacade>();\n\n\t/**\n\t * The methods that are excluded from tracing by default.\n\t */\n\tpublic static readonly DEFAULT_EXCLUDE_METHODS: string[] = [\n\t\t\"start\",\n\t\t\"stop\",\n\t\t\"bootstrap\",\n\t\t\"teardown\"\n\t];\n\n\t/**\n\t * The parameters that are excluded from recording by default.\n\t */\n\tpublic static readonly DEFAULT_EXCLUDE_PARAMS: string[] = [\n\t\t\"password\",\n\t\t\"token\",\n\t\t\"apiKey\",\n\t\t\"mnemonic\"\n\t];\n\n\t/**\n\t * The default maximum length of a recorded string.\n\t */\n\tpublic static readonly DEFAULT_MAX_STRING_LENGTH: number = 256;\n\n\t/**\n\t * The default maximum number of entries recorded for an array.\n\t */\n\tpublic static readonly DEFAULT_MAX_ARRAY_LENGTH: number = 10;\n\n\t/**\n\t * The name a returned value is matched under, so it can be excluded or have a property\n\t * selected with the same patterns as a parameter.\n\t */\n\tpublic static readonly RESULT_NAME: string = \"resolved\";\n\n\t/**\n\t * A camel case parameter name, used to check the names read from the source are trustworthy.\n\t * @internal\n\t */\n\tprivate static readonly _IDENTIFIER: RegExp = /^[a-z][A-Za-z0-9]*$/;\n\n\t/**\n\t * The result of Object.prototype.toString for a method declared async. Used in preference to\n\t * the constructor name, which throws for a function with no prototype.\n\t * @internal\n\t */\n\tprivate static readonly _ASYNC_FUNCTION_TAG: string = \"[object AsyncFunction]\";\n\n\t/**\n\t * The type of the component recording the spans.\n\t * @internal\n\t */\n\tprivate readonly _tracingComponentType?: string;\n\n\t/**\n\t * The component recording the spans, resolved on first use.\n\t * @internal\n\t */\n\tprivate _tracingComponent?: ITracingComponent;\n\n\t/**\n\t * The type of the component for logging a tracing failure.\n\t * @internal\n\t */\n\tprivate readonly _loggingComponentType?: string;\n\n\t/**\n\t * The component for logging a tracing failure, resolved on first use.\n\t * @internal\n\t */\n\tprivate _loggingComponent?: ILoggingComponent;\n\n\t/**\n\t * Patterns for parameters whose values are never recorded.\n\t * @internal\n\t */\n\tprivate readonly _excludeParams: string[][];\n\n\t/**\n\t * Patterns for methods which are not intercepted.\n\t * @internal\n\t */\n\tprivate readonly _excludeMethods: string[][];\n\n\t/**\n\t * Patterns for parameters to record even when the value is not primitive.\n\t * @internal\n\t */\n\tprivate readonly _includeObjects: { path: string[]; root: string[]; last: string }[];\n\n\t/**\n\t * The maximum length of a recorded string.\n\t * @internal\n\t */\n\tprivate readonly _maxStringLength: number;\n\n\t/**\n\t * The maximum number of entries recorded for an array.\n\t * @internal\n\t */\n\tprivate readonly _maxArrayLength: number;\n\n\t/**\n\t * The wrapper for each method, held against the target as well as the method.\n\t * @internal\n\t */\n\tprivate readonly _wrappers: WeakMap<\n\t\tobject,\n\t\tWeakMap<object, (...args: unknown[]) => Promise<unknown>>\n\t>;\n\n\t/**\n\t * The parameter names of each method, parsed once on first use.\n\t * @internal\n\t */\n\tprivate readonly _paramNames: WeakMap<object, string[]>;\n\n\t/**\n\t * Create a new instance of TracingFacade.\n\t * @param options The options for the facade.\n\t */\n\tconstructor(options?: ITracingFacadeConstructorOptions) {\n\t\tthis._tracingComponentType = options?.tracingComponentType;\n\t\tthis._loggingComponentType = options?.loggingComponentType;\n\t\tthis._excludeParams = (\n\t\t\toptions?.config?.excludeParams ?? TracingFacade.DEFAULT_EXCLUDE_PARAMS\n\t\t).map(pattern => pattern.split(\".\"));\n\t\tthis._excludeMethods = (\n\t\t\toptions?.config?.excludeMethods ?? TracingFacade.DEFAULT_EXCLUDE_METHODS\n\t\t).map(pattern => pattern.split(\".\"));\n\t\tthis._includeObjects = (options?.config?.includeObjects ?? []).map(pattern => {\n\t\t\tconst segments = pattern.split(\".\");\n\n\t\t\treturn {\n\t\t\t\tpath: segments,\n\t\t\t\troot: segments.slice(0, -1),\n\t\t\t\tlast: segments[segments.length - 1]\n\t\t\t};\n\t\t});\n\t\tthis._maxStringLength =\n\t\t\toptions?.config?.maxStringLength ?? TracingFacade.DEFAULT_MAX_STRING_LENGTH;\n\t\tthis._maxArrayLength =\n\t\t\toptions?.config?.maxArrayLength ?? TracingFacade.DEFAULT_MAX_ARRAY_LENGTH;\n\t\tthis._wrappers = new WeakMap();\n\t\tthis._paramNames = new WeakMap();\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TracingFacade.CLASS_NAME;\n\t}\n\n\t/**\n\t * Wrap the target so its method calls are recorded as spans.\n\t * @param target The component to wrap.\n\t * @returns The wrapped component.\n\t */\n\tpublic wrap<T>(target: T): T {\n\t\treturn new Proxy(target as { [key: string]: unknown }, {\n\t\t\tget: (t, prop, receiver): unknown => this.interceptGet(t, prop, receiver)\n\t\t}) as T;\n\t}\n\n\t/**\n\t * Get the component recording the spans, resolving it from the factory on first use.\n\t * @returns The component, or undefined when it does not resolve.\n\t * @internal\n\t */\n\tprivate tracingComponent(): ITracingComponent | undefined {\n\t\tthis._tracingComponent ??= ComponentFactory.getIfExists(this._tracingComponentType);\n\t\tthis._loggingComponent ??= ComponentFactory.getIfExists(this._loggingComponentType);\n\n\t\treturn this._tracingComponent;\n\t}\n\n\t/**\n\t * Intercept a property read, returning a replacement function for a method which should be\n\t * traced, and the value itself for anything else.\n\t * @param target The component being wrapped.\n\t * @param prop The property being read.\n\t * @param receiver The proxy the read was made through.\n\t * @returns The value for the property.\n\t * @internal\n\t */\n\tprivate interceptGet(\n\t\ttarget: { [key: string]: unknown },\n\t\tprop: string | symbol,\n\t\treceiver: unknown\n\t): unknown {\n\t\tconst value = Reflect.get(target, prop, receiver);\n\n\t\tif (!Is.function(value) || !Is.string(prop)) {\n\t\t\treturn value;\n\t\t}\n\n\t\t// Wrapping a synchronous method would make it return a promise. The declaration is tested\n\t\t// rather than the return value, which would open the span too late to nest inner calls.\n\t\tif (Object.prototype.toString.call(value) !== TracingFacade._ASYNC_FUNCTION_TAG) {\n\t\t\treturn value;\n\t\t}\n\n\t\tconst className = this.targetClassName(target);\n\n\t\tif (this.matchesAny(this._excludeMethods, [className, prop])) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn this.tracedMethod(target, className, prop, value);\n\t}\n\n\t/**\n\t * Get the wrapper for a method, building it on first use.\n\t * @param target The component being wrapped.\n\t * @param className The name of the component class.\n\t * @param name The name of the method.\n\t * @param method The method to wrap.\n\t * @returns The wrapper, which is the same function for every read of that method.\n\t * @internal\n\t */\n\tprivate tracedMethod(\n\t\ttarget: { [key: string]: unknown },\n\t\tclassName: string,\n\t\tname: string,\n\t\tmethod: (...args: unknown[]) => unknown\n\t): (...args: unknown[]) => Promise<unknown> {\n\t\tlet wrappers = this._wrappers.get(target);\n\n\t\tif (Is.undefined(wrappers)) {\n\t\t\twrappers = new WeakMap();\n\t\t\tthis._wrappers.set(target, wrappers);\n\t\t}\n\n\t\tlet wrapper = wrappers.get(method);\n\n\t\tif (Is.undefined(wrapper)) {\n\t\t\twrapper = async (...args: unknown[]): Promise<unknown> => {\n\t\t\t\tconst tracingComponent = this.tracingComponent();\n\n\t\t\t\tif (Is.empty(tracingComponent)) {\n\t\t\t\t\treturn method.apply(target, args);\n\t\t\t\t}\n\n\t\t\t\treturn TracingHelper.withSpan(\n\t\t\t\t\ttracingComponent,\n\t\t\t\t\tIs.stringValue(className) ? `method:${className}.${name}` : `method:${name}`,\n\t\t\t\t\t{ attributes: this.callAttributes(className, name, method, args) },\n\t\t\t\t\tasync span => {\n\t\t\t\t\t\tconst resolved = await method.apply(target, args);\n\n\t\t\t\t\t\tif (!Is.empty(span)) {\n\t\t\t\t\t\t\tconst recorded = this.attributeValue(\n\t\t\t\t\t\t\t\t[className, name, TracingFacade.RESULT_NAME],\n\t\t\t\t\t\t\t\tresolved\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif (!Is.undefined(recorded)) {\n\t\t\t\t\t\t\t\tspan.attributes = {\n\t\t\t\t\t\t\t\t\t...span.attributes,\n\t\t\t\t\t\t\t\t\t[TracingFacadeAttributes.Result]: recorded\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn resolved;\n\t\t\t\t\t},\n\t\t\t\t\tthis._loggingComponent\n\t\t\t\t);\n\t\t\t};\n\n\t\t\twrappers.set(method, wrapper);\n\t\t}\n\n\t\treturn wrapper;\n\t}\n\n\t/**\n\t * Build the attributes describing a call.\n\t * @param className The name of the component class.\n\t * @param name The name of the method.\n\t * @param method The method being called.\n\t * @param args The arguments the method was called with.\n\t * @returns The attributes.\n\t * @internal\n\t */\n\tprivate callAttributes(\n\t\tclassName: string,\n\t\tname: string,\n\t\tmethod: (...args: unknown[]) => unknown,\n\t\targs: unknown[]\n\t): { [key: string]: unknown } {\n\t\tconst attributes: { [key: string]: unknown } = {\n\t\t\t[TracingFacadeAttributes.Method]: Is.stringValue(className) ? `${className}.${name}` : name\n\t\t};\n\n\t\tconst paramNames = this.paramNames(method);\n\n\t\tfor (let i = 0; i < args.length; i++) {\n\t\t\tconst paramName = paramNames[i];\n\n\t\t\tif (Is.stringValue(paramName)) {\n\t\t\t\tconst recorded = this.attributeValue([className, name, paramName], args[i]);\n\n\t\t\t\tif (!Is.undefined(recorded)) {\n\t\t\t\t\tattributes[`${TracingFacadeAttributes.ParamPrefix}${paramName}`] = recorded;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn attributes;\n\t}\n\n\t/**\n\t * Decide what is recorded for a value, applying the exclusions, the object selection and the\n\t * length limits.\n\t * @param path The class, method and parameter name the value belongs to.\n\t * @param value The value to record.\n\t * @returns The value to record, or undefined when nothing is recorded.\n\t * @internal\n\t */\n\tprivate attributeValue(path: string[], value: unknown): unknown {\n\t\tif (this.matchesAny(this._excludeParams, path)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst primitive = this.primitiveValue(value);\n\n\t\tif (!Is.undefined(primitive)) {\n\t\t\treturn primitive;\n\t\t}\n\n\t\tconst included = this.included(path);\n\n\t\tif (!included.record) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (Is.arrayValue(included.properties)) {\n\t\t\tif (!Is.object<{ [key: string]: unknown }>(value)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst selected: { [key: string]: unknown } = {};\n\t\t\tfor (const property of included.properties) {\n\t\t\t\tselected[property] = value[property];\n\t\t\t}\n\n\t\t\treturn selected;\n\t\t}\n\n\t\treturn Is.array(value) ? value.slice(0, this._maxArrayLength) : value;\n\t}\n\n\t/**\n\t * Convert a value which can be recorded as a span attribute directly.\n\t * @param value The value to convert.\n\t * @returns The value to record, or undefined when it is not a primitive.\n\t * @internal\n\t */\n\tprivate primitiveValue(value: unknown): unknown {\n\t\tif (Is.string(value)) {\n\t\t\treturn value.length > this._maxStringLength ? value.slice(0, this._maxStringLength) : value;\n\t\t}\n\n\t\t// A bigint cannot be serialised by JSON.stringify, so it is converted here.\n\t\tif (Is.bigint(value)) {\n\t\t\treturn String(value);\n\t\t}\n\n\t\tif (Is.number(value) || Is.boolean(value) || Is.null(value)) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Decide whether a non primitive value is recorded, and which of its properties are.\n\t * @param path The class, method and parameter name the value belongs to.\n\t * @returns Whether to record the value, and the properties to record when the patterns select\n\t * them rather than the whole value.\n\t * @internal\n\t */\n\tprivate included(path: string[]): { record: boolean; properties?: string[] } {\n\t\tconst properties: string[] = [];\n\n\t\tfor (const pattern of this._includeObjects) {\n\t\t\t// The parameter itself is named, so the whole value is recorded.\n\t\t\tif (this.matches(pattern.path, path)) {\n\t\t\t\treturn { record: true };\n\t\t\t}\n\n\t\t\tif (pattern.root.length > 0 && this.matches(pattern.root, path)) {\n\t\t\t\tproperties.push(pattern.last);\n\t\t\t}\n\t\t}\n\n\t\treturn properties.length > 0 ? { record: true, properties } : { record: false };\n\t}\n\n\t/**\n\t * Does any of the patterns match the path.\n\t * @param patterns The patterns to test.\n\t * @param path The path to test them against.\n\t * @returns True when one of the patterns matches.\n\t * @internal\n\t */\n\tprivate matchesAny(patterns: string[][], path: string[]): boolean {\n\t\treturn patterns.some(pattern => this.matches(pattern, path));\n\t}\n\n\t/**\n\t * Does a dot separated pattern match a path. The pattern is matched from the right, so a\n\t * pattern shorter than the path leaves the leading segments unconstrained, and a `*` matches\n\t * any single segment.\n\t * @param segments The segments of the pattern to test.\n\t * @param path The path to test it against.\n\t * @returns True when the pattern matches.\n\t * @internal\n\t */\n\tprivate matches(segments: string[], path: string[]): boolean {\n\t\tif (segments.length > path.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst offset = path.length - segments.length;\n\n\t\treturn segments.every((segment, index) => segment === \"*\" || segment === path[offset + index]);\n\t}\n\n\t/**\n\t * Get the name of the class of the component being wrapped, which every IComponent\n\t * implementation provides.\n\t * @param target The component to get the name of.\n\t * @returns The class name, or an empty string when the component does not provide one.\n\t * @internal\n\t */\n\tprivate targetClassName(target: { [key: string]: unknown }): string {\n\t\tconst method = target.className;\n\n\t\tif (Is.function(method)) {\n\t\t\tconst name = method.call(target);\n\n\t\t\tif (Is.stringValue(name)) {\n\t\t\t\treturn name;\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * Get the parameter names of a method, read from its source and held for reuse. An empty list\n\t * is returned when the names cannot be read reliably, so no parameter values are recorded\n\t * rather than being recorded against a name which may be wrong.\n\t * @param method The method to read the parameter names of.\n\t * @returns The parameter names in order, or an empty list when they cannot be trusted.\n\t * @internal\n\t */\n\tprivate paramNames(method: (...args: unknown[]) => unknown): string[] {\n\t\tlet names = this._paramNames.get(method);\n\n\t\tif (Is.undefined(names)) {\n\t\t\tconst source = method.toString();\n\t\t\tconst open = source.indexOf(\"(\");\n\t\t\tconst close = source.indexOf(\")\", open);\n\n\t\t\tnames =\n\t\t\t\topen === -1 || close === -1\n\t\t\t\t\t? []\n\t\t\t\t\t: source\n\t\t\t\t\t\t\t.slice(open + 1, close)\n\t\t\t\t\t\t\t.split(\",\")\n\t\t\t\t\t\t\t.map(param => param.trim())\n\t\t\t\t\t\t\t.filter(param => param.length > 0);\n\n\t\t\t// Anything which is not a plain identifier means the whole list is suspect, so nothing is trusted.\n\t\t\tif (!names.every(name => TracingFacade._IDENTIFIER.test(name))) {\n\t\t\t\tnames = [];\n\t\t\t}\n\n\t\t\tthis._paramNames.set(method, names);\n\t\t}\n\n\t\treturn names;\n\t}\n}\n"]}
|
|
@@ -47,7 +47,7 @@ export declare class TracingFacade implements IFacade, IComponent {
|
|
|
47
47
|
/**
|
|
48
48
|
* Wrap the target so its method calls are recorded as spans.
|
|
49
49
|
* @param target The component to wrap.
|
|
50
|
-
* @returns The wrapped component
|
|
50
|
+
* @returns The wrapped component.
|
|
51
51
|
*/
|
|
52
52
|
wrap<T>(target: T): T;
|
|
53
53
|
}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.3-next.6](https://github.com/iotaledger/twin-tracing/compare/tracing-facades-v0.9.3-next.5...tracing-facades-v0.9.3-next.6) (2026-09-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **tracing-facades:** Synchronize repo versions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/tracing-models bumped from 0.9.3-next.5 to 0.9.3-next.6
|
|
16
|
+
|
|
17
|
+
## [0.9.3-next.5](https://github.com/iotaledger/twin-tracing/compare/tracing-facades-v0.9.3-next.4...tracing-facades-v0.9.3-next.5) (2026-09-10)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* resolve facade components lazily ([#49](https://github.com/iotaledger/twin-tracing/issues/49)) ([c618911](https://github.com/iotaledger/twin-tracing/commit/c6189111740eeecac31cc907cf330a993b3914a7))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Dependencies
|
|
26
|
+
|
|
27
|
+
* The following workspace dependencies were updated
|
|
28
|
+
* dependencies
|
|
29
|
+
* @twin.org/tracing-models bumped from 0.9.3-next.4 to 0.9.3-next.5
|
|
30
|
+
|
|
3
31
|
## [0.9.3-next.4](https://github.com/iotaledger/twin-tracing/compare/tracing-facades-v0.9.3-next.3...tracing-facades-v0.9.3-next.4) (2026-09-08)
|
|
4
32
|
|
|
5
33
|
|
package/docs/examples.md
CHANGED
|
@@ -15,14 +15,24 @@ FacadeFactory.register(
|
|
|
15
15
|
() => new TracingFacade({ tracingComponentType: 'tracing', loggingComponentType: 'logging' })
|
|
16
16
|
);
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// The components the facade itself uses are excluded, since wrapping them would mean recording
|
|
19
|
+
// a span for every span, and logging a failure to log a failure.
|
|
20
|
+
ComponentFactory.useFacade('tracing', [
|
|
21
|
+
'tracing-service',
|
|
22
|
+
'tracing-rest-client',
|
|
23
|
+
'logging-service'
|
|
24
|
+
]);
|
|
19
25
|
```
|
|
20
26
|
|
|
21
|
-
Every component the factory produces from that point on records a span named
|
|
22
|
-
`method:<class>.<name>` for each method called on it.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
Every other component the factory produces from that point on records a span named
|
|
28
|
+
`method:<class>.<name>` for each method called on it.
|
|
29
|
+
|
|
30
|
+
The exclusions are not optional when the tracing or logging components are registered with the
|
|
31
|
+
factory being activated.
|
|
32
|
+
|
|
33
|
+
With no tracing component registered the calls pass straight through. A tracing connector which
|
|
34
|
+
fails does not interrupt the call it was recording, and the failure is reported to the logging
|
|
35
|
+
component when one is configured.
|
|
26
36
|
|
|
27
37
|
## What is recorded
|
|
28
38
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/tracing-facades",
|
|
3
|
-
"version": "0.9.3-next.
|
|
3
|
+
"version": "0.9.3-next.6",
|
|
4
4
|
"description": "Applies tracing to factory produced components using a facade, without modifying them.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@twin.org/core": "^0.9.3-next.3",
|
|
18
18
|
"@twin.org/logging-models": "next",
|
|
19
19
|
"@twin.org/nameof": "next",
|
|
20
|
-
"@twin.org/tracing-models": "0.9.3-next.
|
|
20
|
+
"@twin.org/tracing-models": "0.9.3-next.6"
|
|
21
21
|
},
|
|
22
22
|
"main": "./dist/es/index.js",
|
|
23
23
|
"types": "./dist/types/index.d.ts",
|