@gobing-ai/ts-infra 0.3.5 → 0.3.7
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 +95 -60
- package/dist/application/index.d.ts +16 -18
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +59 -96
- package/dist/application/plugins/builtins.d.ts +64 -0
- package/dist/application/plugins/builtins.d.ts.map +1 -0
- package/dist/application/plugins/builtins.js +146 -0
- package/dist/application/plugins/host.d.ts +61 -0
- package/dist/application/plugins/host.d.ts.map +1 -0
- package/dist/application/plugins/host.js +131 -0
- package/dist/application/plugins/index.d.ts +3 -0
- package/dist/application/plugins/index.d.ts.map +1 -0
- package/dist/application/plugins/index.js +2 -0
- package/dist/application/plugins/types.d.ts +69 -0
- package/dist/application/plugins/types.d.ts.map +1 -0
- package/dist/application/plugins/types.js +10 -0
- package/dist/application/types.d.ts +7 -0
- package/dist/application/types.d.ts.map +1 -1
- package/dist/application-node.d.ts.map +1 -1
- package/dist/application-node.js +40 -57
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/scheduler/cloudflare.d.ts.map +1 -1
- package/dist/scheduler/cloudflare.js +9 -2
- package/dist/scheduler/factory.d.ts +4 -8
- package/dist/scheduler/factory.d.ts.map +1 -1
- package/dist/scheduler/factory.js +12 -22
- package/dist/scheduler/index.d.ts +1 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/scheduler/wrap-handler.d.ts +8 -4
- package/dist/scheduler/wrap-handler.d.ts.map +1 -1
- package/dist/scheduler/wrap-handler.js +8 -4
- package/dist/telemetry/index.d.ts +1 -2
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +1 -2
- package/dist/telemetry/metrics.d.ts +9 -1
- package/dist/telemetry/metrics.d.ts.map +1 -1
- package/dist/telemetry/metrics.js +22 -1
- package/dist/telemetry/sdk.d.ts +33 -1
- package/dist/telemetry/sdk.d.ts.map +1 -1
- package/dist/telemetry/sdk.js +14 -1
- package/package.json +5 -5
- package/src/application/index.ts +72 -102
- package/src/application/plugins/builtins.ts +178 -0
- package/src/application/plugins/host.ts +143 -0
- package/src/application/plugins/index.ts +3 -0
- package/src/application/plugins/types.ts +86 -0
- package/src/application/types.ts +7 -0
- package/src/application-node.ts +43 -61
- package/src/index.ts +0 -2
- package/src/scheduler/cloudflare.ts +16 -5
- package/src/scheduler/factory.ts +15 -26
- package/src/scheduler/index.ts +1 -1
- package/src/scheduler/wrap-handler.ts +8 -4
- package/src/telemetry/index.ts +9 -2
- package/src/telemetry/metrics.ts +22 -1
- package/src/telemetry/sdk.ts +51 -2
- package/dist/telemetry/config.d.ts +0 -41
- package/dist/telemetry/config.d.ts.map +0 -1
- package/dist/telemetry/config.js +0 -21
- package/src/telemetry/config.ts +0 -59
package/src/application/types.ts
CHANGED
|
@@ -13,6 +13,8 @@ import type { BusLifecycleEvents, EventMap } from '../event-bus/types';
|
|
|
13
13
|
import type { InfraEvents } from '../events';
|
|
14
14
|
import type { Logger, LogLevel } from '../logger';
|
|
15
15
|
import type { SchedulerAdapter } from '../scheduler/types';
|
|
16
|
+
import type { PluginHost } from './plugins/host';
|
|
17
|
+
import type { Plugin } from './plugins/types';
|
|
16
18
|
|
|
17
19
|
// ── Feature flag option groups ────────────────────────────────────────────
|
|
18
20
|
|
|
@@ -93,6 +95,8 @@ export interface ApplicationServices<TEvents extends EventMap = InfraEvents> {
|
|
|
93
95
|
lifecycleBus?: EventBus<BusLifecycleEvents>;
|
|
94
96
|
db?: DbAdapterLike;
|
|
95
97
|
scheduler?: SchedulerAdapter;
|
|
98
|
+
/** Pre-built plugin host (when injecting instead of constructing). */
|
|
99
|
+
pluginHost?: PluginHost;
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
/**
|
|
@@ -130,6 +134,7 @@ export interface ApplicationRuntime<TAppConfig = unknown, TEvents extends EventM
|
|
|
130
134
|
readonly db?: DbAdapterLike;
|
|
131
135
|
/** Scheduler adapter (when enabled). */
|
|
132
136
|
readonly scheduler?: SchedulerAdapter;
|
|
137
|
+
readonly pluginHost: PluginHost;
|
|
133
138
|
/** Graceful shutdown. Idempotent — safe to call multiple times. */
|
|
134
139
|
stop(reason?: ApplicationStopReason): Promise<void>;
|
|
135
140
|
}
|
|
@@ -151,6 +156,8 @@ export interface ApplicationBootstrapOptions<TAppConfig = unknown, TEvents exten
|
|
|
151
156
|
readonly appConfig?: TAppConfig;
|
|
152
157
|
/** Pre-built services to inject instead of creating defaults. */
|
|
153
158
|
readonly services?: Partial<ApplicationServices<TEvents>>;
|
|
159
|
+
/** Plugins to register and lifecycle-manage via PluginHost. */
|
|
160
|
+
readonly plugins?: Plugin[];
|
|
154
161
|
/** User callback: application logic. Called after all services are ready. */
|
|
155
162
|
readonly start: (app: ApplicationRuntime<TAppConfig, TEvents>) => Promise<void> | void;
|
|
156
163
|
/** User callback: cleanup before services shut down. */
|
package/src/application-node.ts
CHANGED
|
@@ -22,6 +22,8 @@ import { createDbAdapter, type DbAdapter } from '@gobing-ai/ts-db';
|
|
|
22
22
|
import { interpolateTree, parseYamlObject } from '@gobing-ai/ts-runtime';
|
|
23
23
|
|
|
24
24
|
import { runApplication } from './application/index';
|
|
25
|
+
import { dbPlugin } from './application/plugins/builtins';
|
|
26
|
+
import type { Plugin } from './application/plugins/types';
|
|
25
27
|
import type {
|
|
26
28
|
ApplicationBootstrapOptions,
|
|
27
29
|
ApplicationConfigLoader,
|
|
@@ -213,8 +215,6 @@ export interface NodeApplicationOptions<TAppConfig = unknown, TEvents extends Ev
|
|
|
213
215
|
export async function runNodeApplication<TAppConfig = unknown, TEvents extends EventMap = InfraEvents>(
|
|
214
216
|
options: NodeApplicationOptions<TAppConfig, TEvents>,
|
|
215
217
|
): Promise<ApplicationRuntime<TAppConfig, TEvents>> {
|
|
216
|
-
let nodeTelemetryInitialized = false;
|
|
217
|
-
|
|
218
218
|
// ── Load config ─────────────────────────────────────────────────────
|
|
219
219
|
let loadedAppConfig: TAppConfig | undefined;
|
|
220
220
|
let yamlBootstrap: Record<string, unknown> = {};
|
|
@@ -231,44 +231,54 @@ export async function runNodeApplication<TAppConfig = unknown, TEvents extends E
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
// ── Resolve bootstrap config from YAML + inline options ────────────
|
|
234
|
-
// YAML loads as Record<string, unknown>; bridge into typed options.
|
|
235
|
-
// Inline options (options.config) take precedence over YAML sections.
|
|
236
234
|
const yamlLog = yamlBootstrap.logging as Partial<LoggingOptions> | undefined;
|
|
237
235
|
const yamlTel = yamlBootstrap.telemetry as Partial<TelemetryOptions> | undefined;
|
|
238
236
|
const yamlSched = yamlBootstrap.scheduler as Partial<SchedulerOptions> | undefined;
|
|
239
237
|
const databaseOpts = (yamlBootstrap.database ?? {}) as Record<string, unknown>;
|
|
240
238
|
|
|
241
|
-
const loggingOpts: Partial<LoggingOptions> = {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
};
|
|
245
|
-
const telemetryOpts: Partial<TelemetryOptions> = {
|
|
246
|
-
...yamlTel,
|
|
247
|
-
...options.config?.telemetry,
|
|
248
|
-
};
|
|
249
|
-
const schedulerOpts: Partial<SchedulerOptions> = {
|
|
250
|
-
...yamlSched,
|
|
251
|
-
...options.config?.scheduler,
|
|
252
|
-
};
|
|
239
|
+
const loggingOpts: Partial<LoggingOptions> = { ...yamlLog, ...options.config?.logging };
|
|
240
|
+
const telemetryOpts: Partial<TelemetryOptions> = { ...yamlTel, ...options.config?.telemetry };
|
|
241
|
+
const schedulerOpts: Partial<SchedulerOptions> = { ...yamlSched, ...options.config?.scheduler };
|
|
253
242
|
|
|
254
|
-
// File sink from logging.filePath
|
|
255
243
|
const logFilePath = (yamlBootstrap.logging as Record<string, unknown> | undefined)?.filePath as string | undefined;
|
|
256
244
|
const loggingConfig: Partial<LoggingOptions> =
|
|
257
245
|
typeof logFilePath === 'string' ? { ...loggingOpts, fileSink: createFileSink(logFilePath) } : loggingOpts;
|
|
258
246
|
|
|
259
|
-
// ──
|
|
247
|
+
// ── Scheduler adapter ───────────────────────────────────────────────
|
|
248
|
+
const schedulerConfig: SchedulerOptions = {};
|
|
249
|
+
const rawSched = { ...schedulerOpts } as Record<string, unknown>;
|
|
250
|
+
if (rawSched.enabled === true) {
|
|
251
|
+
schedulerConfig.enabled = true;
|
|
252
|
+
schedulerConfig.autoStart = schedulerOpts.autoStart;
|
|
253
|
+
schedulerConfig.adapter = new NodeSchedulerAdapter();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ── Node-owned plugins ──────────────────────────────────────────────
|
|
257
|
+
const plugins: Plugin[] = [];
|
|
258
|
+
let dbAdapter: DbAdapterLike | undefined = options.services?.db;
|
|
260
259
|
const rawTel = { ...telemetryOpts } as Record<string, unknown>;
|
|
260
|
+
|
|
261
|
+
// Node OTel telemetry as a failFast plugin
|
|
261
262
|
if (rawTel.enabled !== false && rawTel.endpoint) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
263
|
+
plugins.push({
|
|
264
|
+
name: 'builtin:node-telemetry',
|
|
265
|
+
version: '0.0.0',
|
|
266
|
+
failFast: true,
|
|
267
|
+
onLoad: async () => {},
|
|
268
|
+
onStart: async () => {
|
|
269
|
+
initNodeTelemetry({
|
|
270
|
+
serviceName: (rawTel.serviceName as string | undefined) ?? 'ts-libs',
|
|
271
|
+
endpoint: rawTel.endpoint as string,
|
|
272
|
+
headers: rawTel.headers as Record<string, string> | undefined,
|
|
273
|
+
});
|
|
274
|
+
},
|
|
275
|
+
onStop: async () => {
|
|
276
|
+
await shutdownNodeTelemetry();
|
|
277
|
+
},
|
|
266
278
|
});
|
|
267
|
-
nodeTelemetryInitialized = true;
|
|
268
279
|
}
|
|
269
280
|
|
|
270
|
-
//
|
|
271
|
-
let dbAdapter: DbAdapterLike | undefined = options.services?.db;
|
|
281
|
+
// DB adapter (owned — registered as a plugin with fail-soft close)
|
|
272
282
|
if (!dbAdapter && databaseOpts.enabled === true) {
|
|
273
283
|
const driver = databaseOpts.driver as string | undefined;
|
|
274
284
|
if (driver === 'bun-sqlite') {
|
|
@@ -277,6 +287,7 @@ export async function runNodeApplication<TAppConfig = unknown, TEvents extends E
|
|
|
277
287
|
url: databaseOpts.url as string | undefined,
|
|
278
288
|
});
|
|
279
289
|
dbAdapter = adapter as DbAdapter;
|
|
290
|
+
plugins.push(dbPlugin(dbAdapter));
|
|
280
291
|
} else {
|
|
281
292
|
throw new ConfigValidationError(
|
|
282
293
|
`database.enabled is true but driver ${driver ? `"${driver}"` : 'is missing'} is not supported ` +
|
|
@@ -285,45 +296,16 @@ export async function runNodeApplication<TAppConfig = unknown, TEvents extends E
|
|
|
285
296
|
}
|
|
286
297
|
}
|
|
287
298
|
|
|
288
|
-
// ── Scheduler adapter ───────────────────────────────────────────────
|
|
289
|
-
const schedulerConfig: SchedulerOptions = {};
|
|
290
|
-
const rawSched = { ...schedulerOpts } as Record<string, unknown>;
|
|
291
|
-
if (rawSched.enabled === true) {
|
|
292
|
-
schedulerConfig.enabled = true;
|
|
293
|
-
schedulerConfig.autoStart = schedulerOpts.autoStart;
|
|
294
|
-
// Use Node scheduler adapter by default in this subpath
|
|
295
|
-
schedulerConfig.adapter = new NodeSchedulerAdapter();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
299
|
// ── Delegate to portable runApplication ─────────────────────────────
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
scheduler: schedulerConfig,
|
|
305
|
-
},
|
|
300
|
+
// Node-specific cleanup is handled by plugins in the service ring —
|
|
301
|
+
// node-telemetry onStop, owned-db onStop. No manual try/catch or stop
|
|
302
|
+
// override needed.
|
|
303
|
+
return await runApplication<TAppConfig, TEvents>({
|
|
304
|
+
config: { ...options.config, logging: loggingConfig, telemetry: telemetryOpts, scheduler: schedulerConfig },
|
|
306
305
|
appConfig: loadedAppConfig,
|
|
307
|
-
services: {
|
|
308
|
-
...options.services,
|
|
309
|
-
...(dbAdapter ? { db: dbAdapter } : {}),
|
|
310
|
-
},
|
|
306
|
+
services: { ...options.services, ...(dbAdapter ? { db: dbAdapter } : {}) },
|
|
311
307
|
start: options.start,
|
|
312
308
|
stop: options.stop,
|
|
309
|
+
plugins: plugins.length ? plugins : undefined,
|
|
313
310
|
});
|
|
314
|
-
|
|
315
|
-
// ── Compose a handle with Node-specific cleanup on stop ─────────────
|
|
316
|
-
const originalStop = app.stop.bind(app);
|
|
317
|
-
return {
|
|
318
|
-
...app,
|
|
319
|
-
stop: async (reason?: ApplicationStopReason) => {
|
|
320
|
-
await originalStop(reason);
|
|
321
|
-
|
|
322
|
-
// Node-specific cleanup (after portable shutdown):
|
|
323
|
-
// 5. Shut down Node telemetry exporter
|
|
324
|
-
if (nodeTelemetryInitialized) {
|
|
325
|
-
await shutdownNodeTelemetry();
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
};
|
|
329
311
|
}
|
package/src/index.ts
CHANGED
|
@@ -52,7 +52,6 @@ export {
|
|
|
52
52
|
ActionRegistry,
|
|
53
53
|
type CreateDefaultRegistryOptions,
|
|
54
54
|
createDefaultRegistry,
|
|
55
|
-
getSchedulerAdapter,
|
|
56
55
|
HealthPingAction,
|
|
57
56
|
type HealthPingWriter,
|
|
58
57
|
initScheduler,
|
|
@@ -63,7 +62,6 @@ export {
|
|
|
63
62
|
type ScheduledAction,
|
|
64
63
|
type SchedulerAction,
|
|
65
64
|
type SchedulerAdapter,
|
|
66
|
-
setSchedulerAdapter,
|
|
67
65
|
toScheduledAction,
|
|
68
66
|
wrapScheduledHandler,
|
|
69
67
|
} from './scheduler/index';
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
* Cloudflare Workers scheduler adapter using Cron Triggers.
|
|
3
3
|
* Uses minimal local type declarations — no @cloudflare/workers-types dependency.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getSchedulerJobDuration,
|
|
7
|
+
getSchedulerJobExecutedTotal,
|
|
8
|
+
getSchedulerJobFailedTotal,
|
|
9
|
+
} from '../telemetry/metrics';
|
|
6
10
|
import type { ScheduledAction, SchedulerAdapter } from './types';
|
|
7
11
|
|
|
8
12
|
interface CfScheduledEvent {
|
|
@@ -46,12 +50,19 @@ export class CloudflareSchedulerAdapter implements SchedulerAdapter {
|
|
|
46
50
|
handleScheduledEvent(event: CfScheduledEvent, ctx: CfEventContext): void {
|
|
47
51
|
const action = this.entries.get(event.cron);
|
|
48
52
|
if (action) {
|
|
53
|
+
const startMs = performance.now();
|
|
49
54
|
getSchedulerJobExecutedTotal().add(1, { cron: event.cron });
|
|
50
55
|
ctx.waitUntil(
|
|
51
|
-
action()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
action()
|
|
57
|
+
.catch((error: unknown) => {
|
|
58
|
+
getSchedulerJobFailedTotal().add(1, { cron: event.cron });
|
|
59
|
+
throw error;
|
|
60
|
+
})
|
|
61
|
+
.finally(() => {
|
|
62
|
+
// Duration parity with NodeSchedulerAdapter — record the job
|
|
63
|
+
// duration metric keyed by cron for both runtimes.
|
|
64
|
+
getSchedulerJobDuration().record(performance.now() - startMs, { cron: event.cron });
|
|
65
|
+
}),
|
|
55
66
|
);
|
|
56
67
|
}
|
|
57
68
|
}
|
package/src/scheduler/factory.ts
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Scheduler factory —
|
|
2
|
+
* Scheduler factory — initializes an adapter and registers cron entries.
|
|
3
|
+
*
|
|
4
|
+
* The adapter is passed in explicitly (dependency injection); there is no
|
|
5
|
+
* process-global adapter state. Callers that don't supply one get a
|
|
6
|
+
* {@link NoopSchedulerAdapter}.
|
|
3
7
|
*/
|
|
4
8
|
import { NoopSchedulerAdapter } from './noop';
|
|
5
9
|
import type { ScheduledAction, SchedulerAdapter } from './types';
|
|
6
10
|
|
|
7
|
-
let runtimeAdapter: SchedulerAdapter | undefined;
|
|
8
|
-
|
|
9
|
-
/** Set the runtime scheduler adapter. Call before {@link initScheduler}. */
|
|
10
|
-
export function setSchedulerAdapter(adapter: SchedulerAdapter): void {
|
|
11
|
-
runtimeAdapter = adapter;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** Reset the scheduler adapter singleton. For testing. */
|
|
15
|
-
export function resetSchedulerAdapter(): void {
|
|
16
|
-
runtimeAdapter = undefined;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Get the currently configured scheduler adapter, or `undefined` if not set. */
|
|
20
|
-
export function getSchedulerAdapter(): SchedulerAdapter | undefined {
|
|
21
|
-
return runtimeAdapter;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
11
|
/**
|
|
25
12
|
* Initialize the scheduler adapter and register cron entries.
|
|
26
13
|
*
|
|
@@ -28,19 +15,21 @@ export function getSchedulerAdapter(): SchedulerAdapter | undefined {
|
|
|
28
15
|
* running, newly registered entries will NOT be started until the next
|
|
29
16
|
* `start()` call.
|
|
30
17
|
*
|
|
31
|
-
*
|
|
18
|
+
* @param adapter - Adapter to use. Defaults to a {@link NoopSchedulerAdapter}.
|
|
19
|
+
* @param cronEntries - `[cron, action]` pairs to register on the adapter.
|
|
20
|
+
* @returns The configured adapter.
|
|
32
21
|
*/
|
|
33
|
-
export function initScheduler(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
export function initScheduler(
|
|
23
|
+
adapter?: SchedulerAdapter,
|
|
24
|
+
cronEntries?: Array<[string, ScheduledAction]>,
|
|
25
|
+
): SchedulerAdapter {
|
|
26
|
+
const resolved = adapter ?? new NoopSchedulerAdapter();
|
|
38
27
|
|
|
39
28
|
if (cronEntries) {
|
|
40
29
|
for (const [cron, action] of cronEntries) {
|
|
41
|
-
|
|
30
|
+
resolved.register(cron, action);
|
|
42
31
|
}
|
|
43
32
|
}
|
|
44
33
|
|
|
45
|
-
return
|
|
34
|
+
return resolved;
|
|
46
35
|
}
|
package/src/scheduler/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export {
|
|
|
10
10
|
type SchedulerAction,
|
|
11
11
|
toScheduledAction,
|
|
12
12
|
} from './action';
|
|
13
|
-
export {
|
|
13
|
+
export { initScheduler } from './factory';
|
|
14
14
|
export { NoopSchedulerAdapter } from './noop';
|
|
15
15
|
export type { ScheduledAction, SchedulerAdapter } from './types';
|
|
16
16
|
export { wrapScheduledHandler } from './wrap-handler';
|
|
@@ -7,10 +7,14 @@ import type { ScheduledAction } from './types';
|
|
|
7
7
|
* Wrap a scheduled action with OTel tracing, duration measurement, and
|
|
8
8
|
* `scheduler.job.executed` event emission.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* Observability is split by design across two axes, not duplicated:
|
|
11
|
+
* - The adapters (`NodeSchedulerAdapter`, `CloudflareSchedulerAdapter`) record
|
|
12
|
+
* executed/failed/duration **metrics keyed by `cron`** for aggregate dashboards.
|
|
13
|
+
* - This opt-in wrapper adds a named **tracing span + lifecycle event keyed by
|
|
14
|
+
* the human `name`**, for per-job diagnosis. Its timer measures the inner action
|
|
15
|
+
* scope; the adapter's measures the full tick — nested, not double-counted.
|
|
16
|
+
*
|
|
17
|
+
* Wrap an action before registering it when you want the named span/event.
|
|
14
18
|
*
|
|
15
19
|
* @param name - Job name, surfaced as `scheduler.job_name` on the span/event.
|
|
16
20
|
* @param action - The action to wrap (new no-arg `ScheduledAction` signature).
|
package/src/telemetry/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { getTelemetryConfig, type TelemetryConfig, type TelemetryConfigPartial } from './config';
|
|
2
1
|
export { extractSqlOperation, sanitizeSql } from './db-sanitize';
|
|
3
2
|
export {
|
|
4
3
|
type Counter,
|
|
@@ -18,6 +17,14 @@ export {
|
|
|
18
17
|
initMetrics,
|
|
19
18
|
shutdownMetrics,
|
|
20
19
|
} from './metrics';
|
|
21
|
-
export {
|
|
20
|
+
export {
|
|
21
|
+
getTelemetryConfig,
|
|
22
|
+
getTracer,
|
|
23
|
+
initTelemetry,
|
|
24
|
+
isTelemetryEnabled,
|
|
25
|
+
shutdownTelemetry,
|
|
26
|
+
type TelemetryConfig,
|
|
27
|
+
type TelemetryConfigPartial,
|
|
28
|
+
} from './sdk';
|
|
22
29
|
export type { Span, SpanOptions, Tracer } from './tracing';
|
|
23
30
|
export { addSpanAttributes, addSpanEvent, getActiveSpan, traceAsync, traceSync, withSpan } from './tracing';
|
package/src/telemetry/metrics.ts
CHANGED
|
@@ -109,9 +109,30 @@ export function getSchedulerJobFailedTotal(): Counter {
|
|
|
109
109
|
|
|
110
110
|
// ── Lifecycle ───────────────────────────────────────────────────────
|
|
111
111
|
|
|
112
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* Pre-warm every instrument against the currently-registered meter and mark the
|
|
114
|
+
* subsystem initialized. Idempotent.
|
|
115
|
+
*
|
|
116
|
+
* Instruments are otherwise created lazily on first getter call (so metrics keep
|
|
117
|
+
* working even if this is never called — see the module contract). Calling this
|
|
118
|
+
* during bootstrap eagerly materializes them, so `isMetricsInitialized()` reflects
|
|
119
|
+
* real wiring rather than being a flag that gates nothing.
|
|
120
|
+
*/
|
|
113
121
|
export function initMetrics(): void {
|
|
114
122
|
if (metricsInitialized) return;
|
|
123
|
+
// Eagerly materialize all instruments against the live meter.
|
|
124
|
+
getHttpClientRequestTotal();
|
|
125
|
+
getHttpClientRequestDuration();
|
|
126
|
+
getHttpClientRequestErrors();
|
|
127
|
+
getEventbusEmitsTotal();
|
|
128
|
+
getEventbusErrorsTotal();
|
|
129
|
+
getQueueJobEnqueuedTotal();
|
|
130
|
+
getQueueJobCompletedTotal();
|
|
131
|
+
getQueueJobFailedTotal();
|
|
132
|
+
getQueueJobProcessingDuration();
|
|
133
|
+
getSchedulerJobExecutedTotal();
|
|
134
|
+
getSchedulerJobDuration();
|
|
135
|
+
getSchedulerJobFailedTotal();
|
|
115
136
|
metricsInitialized = true;
|
|
116
137
|
}
|
|
117
138
|
|
package/src/telemetry/sdk.ts
CHANGED
|
@@ -8,8 +8,57 @@
|
|
|
8
8
|
* keeps the main barrel free of any SDK runtime dependency.
|
|
9
9
|
*/
|
|
10
10
|
import { type Tracer, trace } from '@opentelemetry/api';
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
// ── Configuration ───────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Full telemetry configuration: master enable switch, service name,
|
|
16
|
+
* environment, and debug-level DB statement capture.
|
|
17
|
+
*/
|
|
18
|
+
export interface TelemetryConfig {
|
|
19
|
+
/** Master switch — when false, all tracing degrades to no-ops. */
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
/** Logical service name emitted on every span. */
|
|
22
|
+
serviceName: string;
|
|
23
|
+
/** Deployment environment (development, staging, production). */
|
|
24
|
+
environment: string;
|
|
25
|
+
/**
|
|
26
|
+
* Debug-only DB statement capture.
|
|
27
|
+
*
|
|
28
|
+
* When true, DB spans may include sanitized SQL text in a `db.statement`
|
|
29
|
+
* attribute. SQL text is redacted — parameter values, literals, and
|
|
30
|
+
* identifiers are stripped before capture.
|
|
31
|
+
*
|
|
32
|
+
* Default: `false`. Controlled by `OTEL_DB_STATEMENT_DEBUG` env var.
|
|
33
|
+
*/
|
|
34
|
+
dbStatementDebug: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Partial telemetry config from the centralized config system. */
|
|
38
|
+
export interface TelemetryConfigPartial {
|
|
39
|
+
enabled?: boolean | undefined;
|
|
40
|
+
serviceName?: string | undefined;
|
|
41
|
+
environment?: string | undefined;
|
|
42
|
+
dbStatementDebug?: boolean | undefined;
|
|
43
|
+
/** Deployment environment fallback (from app.env). */
|
|
44
|
+
appEnv?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const CONFIG_DEFAULTS = {
|
|
48
|
+
enabled: true as const,
|
|
49
|
+
serviceName: 'ts-libs' as const,
|
|
50
|
+
environment: 'development' as const,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Resolve the full telemetry config by merging a partial override with defaults. */
|
|
54
|
+
export function getTelemetryConfig(configPartial: TelemetryConfigPartial = {}): TelemetryConfig {
|
|
55
|
+
return {
|
|
56
|
+
enabled: configPartial.enabled ?? CONFIG_DEFAULTS.enabled,
|
|
57
|
+
serviceName: configPartial.serviceName ?? CONFIG_DEFAULTS.serviceName,
|
|
58
|
+
environment: configPartial.environment ?? configPartial.appEnv ?? CONFIG_DEFAULTS.environment,
|
|
59
|
+
dbStatementDebug: configPartial.dbStatementDebug ?? false,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
13
62
|
|
|
14
63
|
const TRACER_NAME = '@gobing-ai/ts-infra';
|
|
15
64
|
const TRACER_VERSION = '0.1.0';
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telemetry configuration interface.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Full telemetry configuration: master enable switch, service name,
|
|
6
|
-
* environment, and debug-level DB statement capture.
|
|
7
|
-
*/
|
|
8
|
-
export interface TelemetryConfig {
|
|
9
|
-
/** Master switch — when false, all tracing degrades to no-ops. */
|
|
10
|
-
enabled: boolean;
|
|
11
|
-
/** Logical service name emitted on every span. */
|
|
12
|
-
serviceName: string;
|
|
13
|
-
/** Deployment environment (development, staging, production). */
|
|
14
|
-
environment: string;
|
|
15
|
-
/**
|
|
16
|
-
* Debug-only DB statement capture.
|
|
17
|
-
*
|
|
18
|
-
* When true, DB spans may include sanitized SQL text in a `db.statement`
|
|
19
|
-
* attribute. SQL text is redacted — parameter values, literals, and
|
|
20
|
-
* identifiers are stripped before capture.
|
|
21
|
-
*
|
|
22
|
-
* Default: `false`. Controlled by `OTEL_DB_STATEMENT_DEBUG` env var.
|
|
23
|
-
*/
|
|
24
|
-
dbStatementDebug: boolean;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Partial telemetry config from the centralized config system.
|
|
28
|
-
*/
|
|
29
|
-
export interface TelemetryConfigPartial {
|
|
30
|
-
enabled?: boolean | undefined;
|
|
31
|
-
serviceName?: string | undefined;
|
|
32
|
-
environment?: string | undefined;
|
|
33
|
-
dbStatementDebug?: boolean | undefined;
|
|
34
|
-
/** Deployment environment fallback (from app.env). */
|
|
35
|
-
appEnv?: string | undefined;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Resolve the full telemetry config by merging a partial override with defaults.
|
|
39
|
-
*/
|
|
40
|
-
export declare function getTelemetryConfig(configPartial?: TelemetryConfigPartial): TelemetryConfig;
|
|
41
|
-
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/telemetry/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC5B,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAQD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,GAAE,sBAA2B,GAAG,eAAe,CAU9F"}
|
package/dist/telemetry/config.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telemetry configuration interface.
|
|
3
|
-
*/
|
|
4
|
-
const DEFAULTS = {
|
|
5
|
-
enabled: true,
|
|
6
|
-
serviceName: 'ts-libs',
|
|
7
|
-
environment: 'development',
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Resolve the full telemetry config by merging a partial override with defaults.
|
|
11
|
-
*/
|
|
12
|
-
export function getTelemetryConfig(configPartial = {}) {
|
|
13
|
-
const enabled = configPartial.enabled ?? DEFAULTS.enabled;
|
|
14
|
-
const serviceName = configPartial.serviceName ?? DEFAULTS.serviceName;
|
|
15
|
-
return {
|
|
16
|
-
enabled,
|
|
17
|
-
serviceName,
|
|
18
|
-
environment: configPartial.environment ?? configPartial.appEnv ?? DEFAULTS.environment,
|
|
19
|
-
dbStatementDebug: configPartial.dbStatementDebug ?? false,
|
|
20
|
-
};
|
|
21
|
-
}
|
package/src/telemetry/config.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telemetry configuration interface.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Full telemetry configuration: master enable switch, service name,
|
|
7
|
-
* environment, and debug-level DB statement capture.
|
|
8
|
-
*/
|
|
9
|
-
export interface TelemetryConfig {
|
|
10
|
-
/** Master switch — when false, all tracing degrades to no-ops. */
|
|
11
|
-
enabled: boolean;
|
|
12
|
-
/** Logical service name emitted on every span. */
|
|
13
|
-
serviceName: string;
|
|
14
|
-
/** Deployment environment (development, staging, production). */
|
|
15
|
-
environment: string;
|
|
16
|
-
/**
|
|
17
|
-
* Debug-only DB statement capture.
|
|
18
|
-
*
|
|
19
|
-
* When true, DB spans may include sanitized SQL text in a `db.statement`
|
|
20
|
-
* attribute. SQL text is redacted — parameter values, literals, and
|
|
21
|
-
* identifiers are stripped before capture.
|
|
22
|
-
*
|
|
23
|
-
* Default: `false`. Controlled by `OTEL_DB_STATEMENT_DEBUG` env var.
|
|
24
|
-
*/
|
|
25
|
-
dbStatementDebug: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Partial telemetry config from the centralized config system.
|
|
30
|
-
*/
|
|
31
|
-
export interface TelemetryConfigPartial {
|
|
32
|
-
enabled?: boolean | undefined;
|
|
33
|
-
serviceName?: string | undefined;
|
|
34
|
-
environment?: string | undefined;
|
|
35
|
-
dbStatementDebug?: boolean | undefined;
|
|
36
|
-
/** Deployment environment fallback (from app.env). */
|
|
37
|
-
appEnv?: string | undefined;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const DEFAULTS = {
|
|
41
|
-
enabled: true as const,
|
|
42
|
-
serviceName: 'ts-libs' as const,
|
|
43
|
-
environment: 'development' as const,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Resolve the full telemetry config by merging a partial override with defaults.
|
|
48
|
-
*/
|
|
49
|
-
export function getTelemetryConfig(configPartial: TelemetryConfigPartial = {}): TelemetryConfig {
|
|
50
|
-
const enabled = configPartial.enabled ?? DEFAULTS.enabled;
|
|
51
|
-
const serviceName = configPartial.serviceName ?? DEFAULTS.serviceName;
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
enabled,
|
|
55
|
-
serviceName,
|
|
56
|
-
environment: configPartial.environment ?? configPartial.appEnv ?? DEFAULTS.environment,
|
|
57
|
-
dbStatementDebug: configPartial.dbStatementDebug ?? false,
|
|
58
|
-
};
|
|
59
|
-
}
|