@onebun/core 0.2.15 → 0.2.17
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/package.json +6 -5
- package/src/application/application.ts +35 -3
- package/src/module/controller.ts +11 -0
- package/src/module/module.ts +38 -2
- package/src/module/service.ts +18 -1
- package/src/types.ts +41 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onebun/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"description": "Core package for OneBun framework - decorators, DI, modules, controllers",
|
|
5
5
|
"license": "LGPL-3.0",
|
|
6
6
|
"author": "RemRyahirev",
|
|
@@ -43,13 +43,14 @@
|
|
|
43
43
|
"test": "bun test"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"effect": "^3.13.10",
|
|
47
|
-
"arktype": "^2.0.0",
|
|
48
|
-
"@onebun/logger": "^0.2.1",
|
|
49
46
|
"@onebun/envs": "^0.2.2",
|
|
47
|
+
"@onebun/logger": "^0.2.2",
|
|
50
48
|
"@onebun/metrics": "^0.2.2",
|
|
51
49
|
"@onebun/requests": "^0.2.1",
|
|
52
|
-
"@onebun/trace": "^0.2.
|
|
50
|
+
"@onebun/trace": "^0.2.3",
|
|
51
|
+
"@opentelemetry/api": "^1.9.1",
|
|
52
|
+
"arktype": "^2.0.0",
|
|
53
|
+
"effect": "^3.13.10"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"bun-types": "^1.3.8",
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
LoggerService,
|
|
21
21
|
makeLogger,
|
|
22
22
|
makeLoggerFromOptions,
|
|
23
|
+
shutdownLogger,
|
|
23
24
|
type SyncLogger,
|
|
24
25
|
} from '@onebun/logger';
|
|
25
26
|
import {
|
|
@@ -295,9 +296,26 @@ export class OneBunApplication<QA extends import('../queue/types').QueueAdapterC
|
|
|
295
296
|
|
|
296
297
|
// Use provided logger layer, or create from options, or use default
|
|
297
298
|
// Priority: loggerLayer > loggerOptions > env variables > NODE_ENV defaults
|
|
299
|
+
// Auto-populate OTLP resource attributes from tracing config if available
|
|
300
|
+
const loggerOptions = this.options.loggerOptions
|
|
301
|
+
? {
|
|
302
|
+
...this.options.loggerOptions,
|
|
303
|
+
otlpResourceAttributes: this.options.loggerOptions.otlpResourceAttributes ?? (
|
|
304
|
+
this.options.loggerOptions.otlpEndpoint && this.options.tracing
|
|
305
|
+
? {
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
307
|
+
'service.name': this.options.tracing.serviceName ?? 'onebun-service',
|
|
308
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
309
|
+
'service.version': this.options.tracing.serviceVersion ?? '1.0.0',
|
|
310
|
+
}
|
|
311
|
+
: undefined
|
|
312
|
+
),
|
|
313
|
+
}
|
|
314
|
+
: undefined;
|
|
315
|
+
|
|
298
316
|
this.loggerLayer = this.options.loggerLayer
|
|
299
|
-
?? (
|
|
300
|
-
? makeLoggerFromOptions(
|
|
317
|
+
?? (loggerOptions
|
|
318
|
+
? makeLoggerFromOptions(loggerOptions)
|
|
301
319
|
: makeLogger());
|
|
302
320
|
|
|
303
321
|
// Initialize logger with application class name as context
|
|
@@ -503,7 +521,12 @@ export class OneBunApplication<QA extends import('../queue/types').QueueAdapterC
|
|
|
503
521
|
// Create the root module AFTER config is initialized and QueueService proxy is registered,
|
|
504
522
|
// so services can safely use this.config.get() in their constructors
|
|
505
523
|
// and inject QueueService in any module depth.
|
|
506
|
-
this.rootModule = OneBunModule.create(
|
|
524
|
+
this.rootModule = OneBunModule.create(
|
|
525
|
+
this.moduleClass, this.loggerLayer, this.config,
|
|
526
|
+
this.options.tracing?.traceAll
|
|
527
|
+
? { traceAll: true, traceFilter: this.options.tracing.traceFilter }
|
|
528
|
+
: undefined,
|
|
529
|
+
);
|
|
507
530
|
|
|
508
531
|
// Register test provider overrides (must happen before setup() so controllers receive mocks)
|
|
509
532
|
if (this.options._testProviders) {
|
|
@@ -1744,6 +1767,12 @@ export class OneBunApplication<QA extends import('../queue/types').QueueAdapterC
|
|
|
1744
1767
|
this.logger.debug('HTTP server stopped');
|
|
1745
1768
|
}
|
|
1746
1769
|
|
|
1770
|
+
// Shutdown trace service — flush pending spans before module destroy
|
|
1771
|
+
if (this.traceService?.shutdown) {
|
|
1772
|
+
this.logger.debug('Shutting down trace service');
|
|
1773
|
+
await this.traceService.shutdown();
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1747
1776
|
// Call onModuleDestroy lifecycle hook
|
|
1748
1777
|
if (this.rootModule?.callOnModuleDestroy) {
|
|
1749
1778
|
this.logger.debug('Calling onModuleDestroy hooks');
|
|
@@ -1763,6 +1792,9 @@ export class OneBunApplication<QA extends import('../queue/types').QueueAdapterC
|
|
|
1763
1792
|
}
|
|
1764
1793
|
|
|
1765
1794
|
this.logger.info('OneBun application stopped');
|
|
1795
|
+
|
|
1796
|
+
// Shutdown logger transport LAST — flush OTLP log batches after final log message
|
|
1797
|
+
await shutdownLogger();
|
|
1766
1798
|
}
|
|
1767
1799
|
|
|
1768
1800
|
/**
|
package/src/module/controller.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { trace } from '@opentelemetry/api';
|
|
2
|
+
|
|
1
3
|
import type { IConfig, OneBunAppConfig } from './config.interface';
|
|
2
4
|
import type {
|
|
3
5
|
OneBunRequest,
|
|
4
6
|
SseEvent,
|
|
5
7
|
SseOptions,
|
|
6
8
|
} from '../types';
|
|
9
|
+
import type { Span } from '@opentelemetry/api';
|
|
7
10
|
import type { Context } from 'effect';
|
|
8
11
|
|
|
9
12
|
import type { SyncLogger } from '@onebun/logger';
|
|
@@ -134,6 +137,14 @@ export class Controller {
|
|
|
134
137
|
this.logger.debug(`Controller ${className} initialized`);
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Get the currently active OpenTelemetry span.
|
|
142
|
+
* Returns undefined when no span is active.
|
|
143
|
+
*/
|
|
144
|
+
protected get span(): Span | undefined {
|
|
145
|
+
return trace.getActiveSpan();
|
|
146
|
+
}
|
|
147
|
+
|
|
137
148
|
/**
|
|
138
149
|
* Get a service instance by tag
|
|
139
150
|
* @param tag - The service tag
|
package/src/module/module.ts
CHANGED
|
@@ -14,6 +14,11 @@ import {
|
|
|
14
14
|
makeLogger,
|
|
15
15
|
type SyncLogger,
|
|
16
16
|
} from '@onebun/logger';
|
|
17
|
+
import {
|
|
18
|
+
applyAutoTrace,
|
|
19
|
+
shouldAutoTrace,
|
|
20
|
+
type TraceFilterOptions,
|
|
21
|
+
} from '@onebun/trace';
|
|
17
22
|
|
|
18
23
|
import {
|
|
19
24
|
autoDetectDependencies,
|
|
@@ -48,6 +53,7 @@ import {
|
|
|
48
53
|
getServiceTag,
|
|
49
54
|
} from './service';
|
|
50
55
|
|
|
56
|
+
|
|
51
57
|
/**
|
|
52
58
|
* Global services registry
|
|
53
59
|
* Stores services from modules marked with @Global() decorator
|
|
@@ -127,11 +133,17 @@ export class OneBunModule implements ModuleInstance {
|
|
|
127
133
|
*/
|
|
128
134
|
private resolvedAncestorMiddleware: Function[] = [];
|
|
129
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Tracing options for auto-trace (traceAll + filters)
|
|
138
|
+
*/
|
|
139
|
+
private readonly tracingOptions?: { traceAll?: boolean; traceFilter?: TraceFilterOptions };
|
|
140
|
+
|
|
130
141
|
constructor(
|
|
131
142
|
private moduleClass: Function,
|
|
132
143
|
private loggerLayer?: Layer.Layer<never, never, unknown>,
|
|
133
144
|
config?: IConfig<OneBunAppConfig>,
|
|
134
145
|
ancestorMiddleware?: Function[],
|
|
146
|
+
tracingOptions?: { traceAll?: boolean; traceFilter?: TraceFilterOptions },
|
|
135
147
|
) {
|
|
136
148
|
// Initialize logger with module class name as context
|
|
137
149
|
const effectLogger = Effect.runSync(
|
|
@@ -144,6 +156,7 @@ export class OneBunModule implements ModuleInstance {
|
|
|
144
156
|
) as Logger;
|
|
145
157
|
this.logger = createSyncLogger(effectLogger);
|
|
146
158
|
this.config = config ?? new NotInitializedConfig();
|
|
159
|
+
this.tracingOptions = tracingOptions;
|
|
147
160
|
this.ancestorMiddlewareClasses = ancestorMiddleware ?? [];
|
|
148
161
|
|
|
149
162
|
// Read module-level middleware from OnModuleConfigure interface
|
|
@@ -230,7 +243,10 @@ export class OneBunModule implements ModuleInstance {
|
|
|
230
243
|
|
|
231
244
|
// Pass the logger layer, config, and accumulated middleware class refs to child modules
|
|
232
245
|
const accumulatedMiddleware = [...this.ancestorMiddlewareClasses, ...this.ownMiddlewareClasses];
|
|
233
|
-
const childModule = new OneBunModule(
|
|
246
|
+
const childModule = new OneBunModule(
|
|
247
|
+
importModule, this.loggerLayer, this.config,
|
|
248
|
+
accumulatedMiddleware, this.tracingOptions,
|
|
249
|
+
);
|
|
234
250
|
this.childModules.push(childModule);
|
|
235
251
|
|
|
236
252
|
// Merge layers
|
|
@@ -426,6 +442,14 @@ export class OneBunModule implements ModuleInstance {
|
|
|
426
442
|
});
|
|
427
443
|
}
|
|
428
444
|
|
|
445
|
+
// Apply auto-tracing if enabled
|
|
446
|
+
if (
|
|
447
|
+
this.tracingOptions &&
|
|
448
|
+
shouldAutoTrace(provider, provider.name, !!this.tracingOptions.traceAll, this.tracingOptions.traceFilter)
|
|
449
|
+
) {
|
|
450
|
+
applyAutoTrace(serviceInstance, provider.name, this.tracingOptions.traceFilter);
|
|
451
|
+
}
|
|
452
|
+
|
|
429
453
|
this.serviceInstances.set(serviceMetadata.tag, serviceInstance);
|
|
430
454
|
createdServices.add(provider.name);
|
|
431
455
|
this.logger.debug(
|
|
@@ -633,6 +657,17 @@ export class OneBunModule implements ModuleInstance {
|
|
|
633
657
|
controller.initializeController(this.logger, this.config);
|
|
634
658
|
}
|
|
635
659
|
|
|
660
|
+
// Apply auto-tracing if enabled
|
|
661
|
+
if (
|
|
662
|
+
this.tracingOptions &&
|
|
663
|
+
shouldAutoTrace(
|
|
664
|
+
controllerClass, controllerClass.name,
|
|
665
|
+
!!this.tracingOptions.traceAll, this.tracingOptions.traceFilter,
|
|
666
|
+
)
|
|
667
|
+
) {
|
|
668
|
+
applyAutoTrace(controller, controllerClass.name, this.tracingOptions.traceFilter);
|
|
669
|
+
}
|
|
670
|
+
|
|
636
671
|
this.controllerInstances.set(controllerClass, controller);
|
|
637
672
|
|
|
638
673
|
// Inject all services into controller (for legacy compatibility)
|
|
@@ -1145,9 +1180,10 @@ export class OneBunModule implements ModuleInstance {
|
|
|
1145
1180
|
moduleClass: Function,
|
|
1146
1181
|
loggerLayer?: Layer.Layer<never, never, unknown>,
|
|
1147
1182
|
config?: IConfig<OneBunAppConfig>,
|
|
1183
|
+
tracingOptions?: { traceAll?: boolean; traceFilter?: TraceFilterOptions },
|
|
1148
1184
|
): ModuleInstance {
|
|
1149
1185
|
// Using console.log here because we don't have access to the logger instance yet
|
|
1150
1186
|
// The instance will create its own logger in the constructor
|
|
1151
|
-
return new OneBunModule(moduleClass, loggerLayer, config);
|
|
1187
|
+
return new OneBunModule(moduleClass, loggerLayer, config, undefined, tracingOptions);
|
|
1152
1188
|
}
|
|
1153
1189
|
}
|
package/src/module/service.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { trace } from '@opentelemetry/api';
|
|
1
2
|
import {
|
|
2
3
|
Context,
|
|
3
4
|
Effect,
|
|
@@ -5,6 +6,7 @@ import {
|
|
|
5
6
|
} from 'effect';
|
|
6
7
|
|
|
7
8
|
import type { IConfig, OneBunAppConfig } from './config.interface';
|
|
9
|
+
import type { Span } from '@opentelemetry/api';
|
|
8
10
|
|
|
9
11
|
import type { SyncLogger } from '@onebun/logger';
|
|
10
12
|
|
|
@@ -22,7 +24,7 @@ const META_SERVICES = new Map<
|
|
|
22
24
|
* Services extending BaseService will have logger and config available
|
|
23
25
|
* immediately after super() in the constructor (via ambient init context),
|
|
24
26
|
* as well as through the initializeService fallback method.
|
|
25
|
-
*
|
|
27
|
+
*
|
|
26
28
|
* @param tag - Optional Effect Context tag for the service
|
|
27
29
|
*/
|
|
28
30
|
export function Service<T>(tag?: Context.Tag<T, T>) {
|
|
@@ -170,6 +172,21 @@ export class BaseService {
|
|
|
170
172
|
return this._initialized;
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Get the currently active OpenTelemetry span.
|
|
177
|
+
* Returns undefined when no span is active (e.g. outside of @Traced context).
|
|
178
|
+
*
|
|
179
|
+
* The returned Span has a fully synchronous API:
|
|
180
|
+
* - `span.setAttribute(key, value)`
|
|
181
|
+
* - `span.setAttributes({ key: value })`
|
|
182
|
+
* - `span.addEvent(name, attributes?)`
|
|
183
|
+
* - `span.recordException(error)`
|
|
184
|
+
* - `span.setStatus({ code, message })`
|
|
185
|
+
*/
|
|
186
|
+
protected get span(): Span | undefined {
|
|
187
|
+
return trace.getActiveSpan();
|
|
188
|
+
}
|
|
189
|
+
|
|
173
190
|
/**
|
|
174
191
|
* Run an effect with error handling
|
|
175
192
|
* @param effect - The effect to run
|
package/src/types.ts
CHANGED
|
@@ -385,6 +385,47 @@ export interface ApplicationOptions<QA extends QueueAdapterConstructor<any> = Qu
|
|
|
385
385
|
*/
|
|
386
386
|
traceDatabaseQueries?: boolean;
|
|
387
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Auto-trace all async methods on services and controllers.
|
|
390
|
+
* When enabled, all async methods are wrapped in spans without
|
|
391
|
+
* requiring @Traced() on each method.
|
|
392
|
+
*
|
|
393
|
+
* Priority: method-level decorators > class-level > this setting.
|
|
394
|
+
* Use @NoTrace() to opt out, @TraceAll() on a class to opt in
|
|
395
|
+
* when traceAll is false.
|
|
396
|
+
*
|
|
397
|
+
* @defaultValue false
|
|
398
|
+
*/
|
|
399
|
+
traceAll?: boolean;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Filter options for traceAll. Only effective when traceAll is true.
|
|
403
|
+
*/
|
|
404
|
+
traceFilter?: {
|
|
405
|
+
/**
|
|
406
|
+
* Only trace async methods. Sync methods are skipped.
|
|
407
|
+
* @defaultValue true
|
|
408
|
+
*/
|
|
409
|
+
asyncOnly?: boolean;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Additional method names to exclude from auto-tracing
|
|
413
|
+
* (on top of built-in exclusions like lifecycle hooks and base class methods).
|
|
414
|
+
*/
|
|
415
|
+
excludeMethods?: string[];
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Class name glob patterns to include (e.g. ['*Service', '*Repository']).
|
|
419
|
+
* When set, only matching classes are auto-traced.
|
|
420
|
+
*/
|
|
421
|
+
includeClasses?: string[];
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Class name glob patterns to exclude (e.g. ['HealthController']).
|
|
425
|
+
*/
|
|
426
|
+
excludeClasses?: string[];
|
|
427
|
+
};
|
|
428
|
+
|
|
388
429
|
/**
|
|
389
430
|
* Custom attributes to add to all spans
|
|
390
431
|
*/
|