@xylabs/telemetry 5.0.83 → 5.0.84

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
@@ -46,20 +46,28 @@ Base functionality used throughout XY Labs TypeScript/JavaScript libraries
46
46
  function cloneContextWithoutSpan(activeCtx, configKeys?): Context;
47
47
  ```
48
48
 
49
+ Creates a new OpenTelemetry context that preserves baggage and custom keys but has no active span.
50
+
49
51
  ## Parameters
50
52
 
51
53
  ### activeCtx
52
54
 
53
55
  `Context`
54
56
 
57
+ The context to clone from.
58
+
55
59
  ### configKeys?
56
60
 
57
61
  `symbol`[] = `[]`
58
62
 
63
+ Additional context keys to copy.
64
+
59
65
  ## Returns
60
66
 
61
67
  `Context`
62
68
 
69
+ A new context with baggage but no parent span.
70
+
63
71
  ### <a id="span"></a>span
64
72
 
65
73
  [**@xylabs/telemetry**](#../README)
@@ -73,6 +81,8 @@ function span<T>(
73
81
  tracer?): T;
74
82
  ```
75
83
 
84
+ Executes a synchronous function within an OpenTelemetry span, recording status and exceptions.
85
+
76
86
  ## Type Parameters
77
87
 
78
88
  ### T
@@ -85,18 +95,26 @@ function span<T>(
85
95
 
86
96
  `string`
87
97
 
98
+ The span name.
99
+
88
100
  ### fn
89
101
 
90
102
  () => `T`
91
103
 
104
+ The function to execute.
105
+
92
106
  ### tracer?
93
107
 
94
108
  `Tracer`
95
109
 
110
+ Optional tracer to use.
111
+
96
112
  ## Returns
97
113
 
98
114
  `T`
99
115
 
116
+ The return value of `fn`.
117
+
100
118
  ### <a id="spanAsync"></a>spanAsync
101
119
 
102
120
  [**@xylabs/telemetry**](#../README)
@@ -107,9 +125,11 @@ function span<T>(
107
125
  function spanAsync<T>(
108
126
  name,
109
127
  fn,
110
- __namedParameters?): Promise<T>;
128
+ config?): Promise<T>;
111
129
  ```
112
130
 
131
+ Executes an async function within an OpenTelemetry span, with optional time budget monitoring.
132
+
113
133
  ## Type Parameters
114
134
 
115
135
  ### T
@@ -122,18 +142,26 @@ __namedParameters?): Promise<T>;
122
142
 
123
143
  `string`
124
144
 
145
+ The span name.
146
+
125
147
  ### fn
126
148
 
127
149
  () => `Promise`\<`T`\>
128
150
 
129
- ### \_\_namedParameters?
151
+ The async function to execute.
152
+
153
+ ### config?
130
154
 
131
155
  [`SpanConfig`](#../interfaces/SpanConfig) = `{}`
132
156
 
157
+ Optional span configuration (tracer, logger, time budget).
158
+
133
159
  ## Returns
134
160
 
135
161
  `Promise`\<`T`\>
136
162
 
163
+ The resolved value of `fn`.
164
+
137
165
  ### <a id="spanRoot"></a>spanRoot
138
166
 
139
167
  [**@xylabs/telemetry**](#../README)
@@ -147,6 +175,8 @@ function spanRoot<T>(
147
175
  tracer?): T;
148
176
  ```
149
177
 
178
+ Executes a synchronous function within a new root span that has no parent, even if a span is already active.
179
+
150
180
  ## Type Parameters
151
181
 
152
182
  ### T
@@ -159,18 +189,26 @@ function spanRoot<T>(
159
189
 
160
190
  `string`
161
191
 
192
+ The span name.
193
+
162
194
  ### fn
163
195
 
164
196
  () => `T`
165
197
 
198
+ The function to execute.
199
+
166
200
  ### tracer?
167
201
 
168
202
  `Tracer`
169
203
 
204
+ Optional tracer to use.
205
+
170
206
  ## Returns
171
207
 
172
208
  `T`
173
209
 
210
+ The return value of `fn`.
211
+
174
212
  ### <a id="spanRootAsync"></a>spanRootAsync
175
213
 
176
214
  [**@xylabs/telemetry**](#../README)
@@ -181,9 +219,11 @@ function spanRoot<T>(
181
219
  function spanRootAsync<T>(
182
220
  name,
183
221
  fn,
184
- __namedParameters?): Promise<T>;
222
+ config?): Promise<T>;
185
223
  ```
186
224
 
225
+ Executes an async function within a new root span (no parent), with optional time budget monitoring.
226
+
187
227
  ## Type Parameters
188
228
 
189
229
  ### T
@@ -196,18 +236,26 @@ __namedParameters?): Promise<T>;
196
236
 
197
237
  `string`
198
238
 
239
+ The span name.
240
+
199
241
  ### fn
200
242
 
201
243
  () => `Promise`\<`T`\>
202
244
 
203
- ### \_\_namedParameters?
245
+ The async function to execute.
246
+
247
+ ### config?
204
248
 
205
249
  [`SpanConfig`](#../interfaces/SpanConfig) = `{}`
206
250
 
251
+ Optional span configuration (tracer, logger, time budget).
252
+
207
253
  ## Returns
208
254
 
209
255
  `Promise`\<`T`\>
210
256
 
257
+ The resolved value of `fn`.
258
+
211
259
  ### <a id="timeBudget"></a>timeBudget
212
260
 
213
261
  [**@xylabs/telemetry**](#../README)
@@ -223,6 +271,8 @@ function timeBudget<TResult>(
223
271
  status?): Promise<TResult>;
224
272
  ```
225
273
 
274
+ Executes an async function and logs a warning if it exceeds the given time budget.
275
+
226
276
  ## Type Parameters
227
277
 
228
278
  ### TResult
@@ -235,26 +285,38 @@ status?): Promise<TResult>;
235
285
 
236
286
  `string`
237
287
 
288
+ A label for the function, used in warning messages.
289
+
238
290
  ### logger
239
291
 
292
+ The logger to use for budget-exceeded warnings.
293
+
240
294
  `Logger` | `undefined`
241
295
 
242
296
  ### func
243
297
 
244
298
  () => `Promise`\<`TResult`\>
245
299
 
300
+ The async function to execute.
301
+
246
302
  ### budget
247
303
 
248
304
  `number`
249
305
 
306
+ The time budget in milliseconds.
307
+
250
308
  ### status?
251
309
 
252
310
  `boolean` = `false`
253
311
 
312
+ If true, logs periodic warnings while the function is still running.
313
+
254
314
  ## Returns
255
315
 
256
316
  `Promise`\<`TResult`\>
257
317
 
318
+ The result of the executed function.
319
+
258
320
  ### interfaces
259
321
 
260
322
  ### <a id="SpanConfig"></a>SpanConfig
@@ -263,6 +325,8 @@ status?): Promise<TResult>;
263
325
 
264
326
  ***
265
327
 
328
+ Configuration options for span creation and execution.
329
+
266
330
  ## Properties
267
331
 
268
332
  ### logger?
@@ -271,6 +335,8 @@ status?): Promise<TResult>;
271
335
  optional logger: Logger | null;
272
336
  ```
273
337
 
338
+ Optional logger for time budget warnings. Falls back to console if not provided.
339
+
274
340
  ***
275
341
 
276
342
  ### timeBudgetLimit?
@@ -279,6 +345,8 @@ optional logger: Logger | null;
279
345
  optional timeBudgetLimit: number;
280
346
  ```
281
347
 
348
+ Maximum allowed execution time in milliseconds before logging a warning.
349
+
282
350
  ***
283
351
 
284
352
  ### tracer?
@@ -287,6 +355,8 @@ optional timeBudgetLimit: number;
287
355
  optional tracer: Tracer;
288
356
  ```
289
357
 
358
+ OpenTelemetry tracer to use. Defaults to a tracer named after the span.
359
+
290
360
 
291
361
  Part of [sdk-js](https://www.npmjs.com/package/@xyo-network/sdk-js)
292
362
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/span.ts","../../src/timeBudget.ts"],"sourcesContent":["import type {\n Context,\n Tracer,\n} from '@opentelemetry/api'\nimport {\n context, propagation, ROOT_CONTEXT, SpanStatusCode, trace as TRACE_API,\n} from '@opentelemetry/api'\nimport type { Logger } from '@xylabs/logger'\nimport { isDefined } from '@xylabs/typeof'\n\nimport { timeBudget } from './timeBudget.ts'\n\nexport interface SpanConfig {\n logger?: Logger | null\n timeBudgetLimit?: number\n tracer?: Tracer\n}\n\nexport function cloneContextWithoutSpan(activeCtx: Context, configKeys: symbol[] = []): Context {\n // Start from root to ensure no span is propagated\n let newCtx = ROOT_CONTEXT\n\n // Copy baggage\n const baggage = propagation.getBaggage(activeCtx)\n if (baggage) {\n newCtx = propagation.setBaggage(newCtx, baggage)\n }\n\n // Copy custom config keys\n for (const key of configKeys) {\n const value = activeCtx.getValue(key)\n if (value !== undefined) {\n newCtx = newCtx.setValue(key, value)\n }\n }\n\n return newCtx\n}\n\nexport function span<T>(name: string, fn: () => T, tracer?: Tracer): T {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const span = activeTracer.startSpan(name)\n return context.with(TRACE_API.setSpan(context.active(), span), () => {\n try {\n const result = fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\nexport function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n // Get current active context for configuration\n const activeContext = context.active()\n\n // Create a new context with no active span\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = activeTracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return context.with(TRACE_API.setSpan(noSpanContext, span), () => {\n try {\n const result = fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\nexport async function spanAsync<T>(\n name: string,\n fn: () => Promise<T>,\n {\n timeBudgetLimit, logger, tracer,\n }: SpanConfig = {},\n): Promise<T> {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n const funcToRun = isDefined(timeBudgetLimit) ? () => timeBudget(name, logger ?? console, fn, timeBudgetLimit) : fn\n if (isDefined(activeTracer)) {\n const span = activeTracer.startSpan(name)\n return await context.with(TRACE_API.setSpan(context.active(), span), async () => {\n try {\n const result = await funcToRun()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return await funcToRun()\n }\n}\n\nexport async function spanRootAsync<T>(\n name: string,\n fn: () => Promise<T>,\n {\n timeBudgetLimit, logger, tracer,\n }: SpanConfig = {},\n): Promise<T> {\n const funcToRun = isDefined(timeBudgetLimit) ? () => timeBudget(name, logger ?? console, fn, timeBudgetLimit) : fn\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const activeContext = context.active()\n\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = activeTracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return await context.with(TRACE_API.setSpan(noSpanContext, span), async () => {\n try {\n const result = await funcToRun()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return await funcToRun()\n }\n}\n","import type { Logger } from '@xylabs/logger'\n\nexport async function timeBudget<TResult>(\n name: string,\n logger: Logger | undefined,\n func: () => Promise<TResult>,\n budget: number,\n status = false,\n): Promise<TResult> {\n const start = Date.now()\n const timer = status\n ? setInterval(() => {\n const duration = Date.now() - start\n if ((budget > 0) && (duration > budget)) {\n logger?.warn(`Function [${name}] execution is exceeding budget: ${duration}ms > ${budget}ms`)\n }\n }, Math.max(100, budget))\n : undefined\n\n const result = await func()\n const duration = Date.now() - start\n\n if (!timer && (budget > 0) && (duration > budget)) {\n logger?.warn(`Function [${name}] execution exceeded budget: ${duration}ms > ${budget}ms`)\n }\n if (timer) {\n clearInterval(timer)\n }\n return result\n}\n"],"mappings":"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","names":["duration","span"]}
1
+ {"version":3,"sources":["../../src/span.ts","../../src/timeBudget.ts"],"sourcesContent":["import type {\n Context,\n Tracer,\n} from '@opentelemetry/api'\nimport {\n context, propagation, ROOT_CONTEXT, SpanStatusCode, trace as TRACE_API,\n} from '@opentelemetry/api'\nimport type { Logger } from '@xylabs/logger'\nimport { isDefined } from '@xylabs/typeof'\n\nimport { timeBudget } from './timeBudget.ts'\n\n/** Configuration options for span creation and execution. */\nexport interface SpanConfig {\n /** Optional logger for time budget warnings. Falls back to console if not provided. */\n logger?: Logger | null\n /** Maximum allowed execution time in milliseconds before logging a warning. */\n timeBudgetLimit?: number\n /** OpenTelemetry tracer to use. Defaults to a tracer named after the span. */\n tracer?: Tracer\n}\n\n/**\n * Creates a new OpenTelemetry context that preserves baggage and custom keys but has no active span.\n * @param activeCtx - The context to clone from.\n * @param configKeys - Additional context keys to copy.\n * @returns A new context with baggage but no parent span.\n */\nexport function cloneContextWithoutSpan(activeCtx: Context, configKeys: symbol[] = []): Context {\n // Start from root to ensure no span is propagated\n let newCtx = ROOT_CONTEXT\n\n // Copy baggage\n const baggage = propagation.getBaggage(activeCtx)\n if (baggage) {\n newCtx = propagation.setBaggage(newCtx, baggage)\n }\n\n // Copy custom config keys\n for (const key of configKeys) {\n const value = activeCtx.getValue(key)\n if (value !== undefined) {\n newCtx = newCtx.setValue(key, value)\n }\n }\n\n return newCtx\n}\n\n/**\n * Executes a synchronous function within an OpenTelemetry span, recording status and exceptions.\n * @param name - The span name.\n * @param fn - The function to execute.\n * @param tracer - Optional tracer to use.\n * @returns The return value of `fn`.\n */\nexport function span<T>(name: string, fn: () => T, tracer?: Tracer): T {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const span = activeTracer.startSpan(name)\n return context.with(TRACE_API.setSpan(context.active(), span), () => {\n try {\n const result = fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\n/**\n * Executes a synchronous function within a new root span that has no parent, even if a span is already active.\n * @param name - The span name.\n * @param fn - The function to execute.\n * @param tracer - Optional tracer to use.\n * @returns The return value of `fn`.\n */\nexport function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n // Get current active context for configuration\n const activeContext = context.active()\n\n // Create a new context with no active span\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = activeTracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return context.with(TRACE_API.setSpan(noSpanContext, span), () => {\n try {\n const result = fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\n/**\n * Executes an async function within an OpenTelemetry span, with optional time budget monitoring.\n * @param name - The span name.\n * @param fn - The async function to execute.\n * @param config - Optional span configuration (tracer, logger, time budget).\n * @returns The resolved value of `fn`.\n */\nexport async function spanAsync<T>(\n name: string,\n fn: () => Promise<T>,\n {\n timeBudgetLimit, logger, tracer,\n }: SpanConfig = {},\n): Promise<T> {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n const funcToRun = isDefined(timeBudgetLimit) ? () => timeBudget(name, logger ?? console, fn, timeBudgetLimit) : fn\n if (isDefined(activeTracer)) {\n const span = activeTracer.startSpan(name)\n return await context.with(TRACE_API.setSpan(context.active(), span), async () => {\n try {\n const result = await funcToRun()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return await funcToRun()\n }\n}\n\n/**\n * Executes an async function within a new root span (no parent), with optional time budget monitoring.\n * @param name - The span name.\n * @param fn - The async function to execute.\n * @param config - Optional span configuration (tracer, logger, time budget).\n * @returns The resolved value of `fn`.\n */\nexport async function spanRootAsync<T>(\n name: string,\n fn: () => Promise<T>,\n {\n timeBudgetLimit, logger, tracer,\n }: SpanConfig = {},\n): Promise<T> {\n const funcToRun = isDefined(timeBudgetLimit) ? () => timeBudget(name, logger ?? console, fn, timeBudgetLimit) : fn\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const activeContext = context.active()\n\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = activeTracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return await context.with(TRACE_API.setSpan(noSpanContext, span), async () => {\n try {\n const result = await funcToRun()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return await funcToRun()\n }\n}\n","import type { Logger } from '@xylabs/logger'\n\n/**\n * Executes an async function and logs a warning if it exceeds the given time budget.\n * @param name - A label for the function, used in warning messages.\n * @param logger - The logger to use for budget-exceeded warnings.\n * @param func - The async function to execute.\n * @param budget - The time budget in milliseconds.\n * @param status - If true, logs periodic warnings while the function is still running.\n * @returns The result of the executed function.\n */\nexport async function timeBudget<TResult>(\n name: string,\n logger: Logger | undefined,\n func: () => Promise<TResult>,\n budget: number,\n status = false,\n): Promise<TResult> {\n const start = Date.now()\n const timer = status\n ? setInterval(() => {\n const duration = Date.now() - start\n if ((budget > 0) && (duration > budget)) {\n logger?.warn(`Function [${name}] execution is exceeding budget: ${duration}ms > ${budget}ms`)\n }\n }, Math.max(100, budget))\n : undefined\n\n const result = await func()\n const duration = Date.now() - start\n\n if (!timer && (budget > 0) && (duration > budget)) {\n logger?.warn(`Function [${name}] execution exceeded budget: ${duration}ms > ${budget}ms`)\n }\n if (timer) {\n clearInterval(timer)\n }\n return result\n}\n"],"mappings":"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","names":["duration","span"]}
@@ -1,13 +1,51 @@
1
1
  import type { Context, Tracer } from '@opentelemetry/api';
2
2
  import type { Logger } from '@xylabs/logger';
3
+ /** Configuration options for span creation and execution. */
3
4
  export interface SpanConfig {
5
+ /** Optional logger for time budget warnings. Falls back to console if not provided. */
4
6
  logger?: Logger | null;
7
+ /** Maximum allowed execution time in milliseconds before logging a warning. */
5
8
  timeBudgetLimit?: number;
9
+ /** OpenTelemetry tracer to use. Defaults to a tracer named after the span. */
6
10
  tracer?: Tracer;
7
11
  }
12
+ /**
13
+ * Creates a new OpenTelemetry context that preserves baggage and custom keys but has no active span.
14
+ * @param activeCtx - The context to clone from.
15
+ * @param configKeys - Additional context keys to copy.
16
+ * @returns A new context with baggage but no parent span.
17
+ */
8
18
  export declare function cloneContextWithoutSpan(activeCtx: Context, configKeys?: symbol[]): Context;
19
+ /**
20
+ * Executes a synchronous function within an OpenTelemetry span, recording status and exceptions.
21
+ * @param name - The span name.
22
+ * @param fn - The function to execute.
23
+ * @param tracer - Optional tracer to use.
24
+ * @returns The return value of `fn`.
25
+ */
9
26
  export declare function span<T>(name: string, fn: () => T, tracer?: Tracer): T;
27
+ /**
28
+ * Executes a synchronous function within a new root span that has no parent, even if a span is already active.
29
+ * @param name - The span name.
30
+ * @param fn - The function to execute.
31
+ * @param tracer - Optional tracer to use.
32
+ * @returns The return value of `fn`.
33
+ */
10
34
  export declare function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T;
35
+ /**
36
+ * Executes an async function within an OpenTelemetry span, with optional time budget monitoring.
37
+ * @param name - The span name.
38
+ * @param fn - The async function to execute.
39
+ * @param config - Optional span configuration (tracer, logger, time budget).
40
+ * @returns The resolved value of `fn`.
41
+ */
11
42
  export declare function spanAsync<T>(name: string, fn: () => Promise<T>, { timeBudgetLimit, logger, tracer, }?: SpanConfig): Promise<T>;
43
+ /**
44
+ * Executes an async function within a new root span (no parent), with optional time budget monitoring.
45
+ * @param name - The span name.
46
+ * @param fn - The async function to execute.
47
+ * @param config - Optional span configuration (tracer, logger, time budget).
48
+ * @returns The resolved value of `fn`.
49
+ */
12
50
  export declare function spanRootAsync<T>(name: string, fn: () => Promise<T>, { timeBudgetLimit, logger, tracer, }?: SpanConfig): Promise<T>;
13
51
  //# sourceMappingURL=span.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"span.d.ts","sourceRoot":"","sources":["../../src/span.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACP,MAAM,oBAAoB,CAAA;AAI3B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAK5C,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAmB9F;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAqBrE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CA8BzE;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,EACE,eAAe,EAAE,MAAM,EAAE,MAAM,GAChC,GAAE,UAAe,GACjB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,EACE,eAAe,EAAE,MAAM,EAAE,MAAM,GAChC,GAAE,UAAe,GACjB,OAAO,CAAC,CAAC,CAAC,CA6BZ"}
1
+ {"version":3,"file":"span.d.ts","sourceRoot":"","sources":["../../src/span.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACP,MAAM,oBAAoB,CAAA;AAI3B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAK5C,6DAA6D;AAC7D,MAAM,WAAW,UAAU;IACzB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAmB9F;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAqBrE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CA8BzE;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,EACE,eAAe,EAAE,MAAM,EAAE,MAAM,GAChC,GAAE,UAAe,GACjB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,EACE,eAAe,EAAE,MAAM,EAAE,MAAM,GAChC,GAAE,UAAe,GACjB,OAAO,CAAC,CAAC,CAAC,CA6BZ"}
@@ -1,3 +1,12 @@
1
1
  import type { Logger } from '@xylabs/logger';
2
+ /**
3
+ * Executes an async function and logs a warning if it exceeds the given time budget.
4
+ * @param name - A label for the function, used in warning messages.
5
+ * @param logger - The logger to use for budget-exceeded warnings.
6
+ * @param func - The async function to execute.
7
+ * @param budget - The time budget in milliseconds.
8
+ * @param status - If true, logs periodic warnings while the function is still running.
9
+ * @returns The result of the executed function.
10
+ */
2
11
  export declare function timeBudget<TResult>(name: string, logger: Logger | undefined, func: () => Promise<TResult>, budget: number, status?: boolean): Promise<TResult>;
3
12
  //# sourceMappingURL=timeBudget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timeBudget.d.ts","sourceRoot":"","sources":["../../src/timeBudget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAE5C,wBAAsB,UAAU,CAAC,OAAO,EACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC5B,MAAM,EAAE,MAAM,EACd,MAAM,UAAQ,GACb,OAAO,CAAC,OAAO,CAAC,CAqBlB"}
1
+ {"version":3,"file":"timeBudget.d.ts","sourceRoot":"","sources":["../../src/timeBudget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAE5C;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,OAAO,EACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC5B,MAAM,EAAE,MAAM,EACd,MAAM,UAAQ,GACb,OAAO,CAAC,OAAO,CAAC,CAqBlB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/telemetry",
3
- "version": "5.0.83",
3
+ "version": "5.0.84",
4
4
  "description": "Base functionality used throughout XY Labs TypeScript/JavaScript libraries",
5
5
  "keywords": [
6
6
  "hex",
@@ -43,12 +43,12 @@
43
43
  ],
44
44
  "dependencies": {
45
45
  "@opentelemetry/api": "^1.9.0",
46
- "@xylabs/logger": "~5.0.83",
47
- "@xylabs/typeof": "~5.0.83"
46
+ "@xylabs/logger": "~5.0.84",
47
+ "@xylabs/typeof": "~5.0.84"
48
48
  },
49
49
  "devDependencies": {
50
- "@xylabs/ts-scripts-yarn3": "~7.4.11",
51
- "@xylabs/tsconfig": "~7.4.11",
50
+ "@xylabs/ts-scripts-yarn3": "~7.4.13",
51
+ "@xylabs/tsconfig": "~7.4.13",
52
52
  "typescript": "~5.9.3",
53
53
  "vitest": "~4.0.18"
54
54
  },