@webtypen/webframez-core 0.3.14 → 0.3.15

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.
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ConsoleApplication = void 0;
13
+ /// <reference types="node" />
13
14
  const Config_1 = require("./Config");
14
15
  const ConsoleOutputHelper_1 = require("./Commands/ConsoleOutputHelper");
15
16
  const QueueWorkerCommand_1 = require("./Commands/QueueWorkerCommand");
@@ -22,6 +23,7 @@ const QueueStopCommand_1 = require("./Commands/QueueStopCommand");
22
23
  const QueueLogCommand_1 = require("./Commands/QueueLogCommand");
23
24
  const QueueWorkerAutorestartCommand_1 = require("./Commands/QueueWorkerAutorestartCommand");
24
25
  const info_1 = require("./info");
26
+ const SigNozTelemetry_1 = require("./Telemetry/SigNozTelemetry");
25
27
  class ConsoleApplication {
26
28
  constructor() {
27
29
  this.systemCommands = [
@@ -43,6 +45,9 @@ class ConsoleApplication {
43
45
  Config_1.Config.register(key, options.config[key]);
44
46
  }
45
47
  }
48
+ if (options && options.signoz) {
49
+ void SigNozTelemetry_1.SigNozTelemetry.init(options.signoz);
50
+ }
46
51
  if (options && options.datatables) {
47
52
  DatatableRegistry_1.DatatableRegistry.registerMany(options.datatables);
48
53
  }
@@ -0,0 +1,33 @@
1
+ export interface SigNozOptions {
2
+ enabled?: boolean;
3
+ serviceName?: string;
4
+ endpoint?: string;
5
+ apiKey?: string;
6
+ headers?: Record<string, string>;
7
+ environment?: string;
8
+ resourceAttributes?: Record<string, unknown>;
9
+ samplingRatio?: number;
10
+ instrumentations?: any[];
11
+ autoInstrumentations?: boolean;
12
+ autoInstrumentationConfig?: Record<string, unknown>;
13
+ logInitialization?: boolean;
14
+ }
15
+ export declare class SigNozTelemetry {
16
+ private static sdk;
17
+ private static initPromise;
18
+ private static shutdownRegistered;
19
+ private static readonly missingDependencies;
20
+ private static readonly shutdownListener;
21
+ static init(options?: SigNozOptions): Promise<void>;
22
+ private static initialize;
23
+ static shutdown(): Promise<void>;
24
+ private static safeImport;
25
+ private static ensureEndpoint;
26
+ private static warnMissingDependency;
27
+ private static registerShutdownHooks;
28
+ private static getProcess;
29
+ private static getEnv;
30
+ private static getConsole;
31
+ private static logInfo;
32
+ private static logWarn;
33
+ }
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.SigNozTelemetry = void 0;
36
+ const Config_1 = require("../Config");
37
+ class SigNozTelemetry {
38
+ static init(options) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ if (!options || options.enabled === false) {
41
+ return;
42
+ }
43
+ if (this.sdk) {
44
+ return;
45
+ }
46
+ if (this.initPromise) {
47
+ yield this.initPromise;
48
+ return;
49
+ }
50
+ const initialization = (() => __awaiter(this, void 0, void 0, function* () {
51
+ try {
52
+ yield this.initialize(options);
53
+ }
54
+ catch (error) {
55
+ this.logWarn("[SigNoz] Initialization failed:", error);
56
+ }
57
+ }))();
58
+ this.initPromise = initialization;
59
+ try {
60
+ yield initialization;
61
+ }
62
+ finally {
63
+ this.initPromise = null;
64
+ }
65
+ });
66
+ }
67
+ static initialize(options) {
68
+ return __awaiter(this, void 0, void 0, function* () {
69
+ const sdkModule = yield this.safeImport("@opentelemetry/sdk-node");
70
+ const traceExporterModule = yield this.safeImport("@opentelemetry/exporter-trace-otlp-http");
71
+ const resourcesModule = yield this.safeImport("@opentelemetry/resources");
72
+ const semanticModule = yield this.safeImport("@opentelemetry/semantic-conventions");
73
+ if (!(sdkModule === null || sdkModule === void 0 ? void 0 : sdkModule.NodeSDK) || !(traceExporterModule === null || traceExporterModule === void 0 ? void 0 : traceExporterModule.OTLPTraceExporter) || !(resourcesModule === null || resourcesModule === void 0 ? void 0 : resourcesModule.Resource) || !(semanticModule === null || semanticModule === void 0 ? void 0 : semanticModule.SemanticResourceAttributes)) {
74
+ throw new Error("OpenTelemetry packages are missing. Install '@opentelemetry/sdk-node', '@opentelemetry/exporter-trace-otlp-http', '@opentelemetry/resources' and '@opentelemetry/semantic-conventions'.");
75
+ }
76
+ const serviceName = options.serviceName ||
77
+ Config_1.Config.get("application.serviceName") ||
78
+ Config_1.Config.get("application.name") ||
79
+ this.getEnv("SIGNOZ_SERVICE_NAME") ||
80
+ this.getEnv("OTEL_SERVICE_NAME") ||
81
+ "webframez-service";
82
+ const environment = options.environment ||
83
+ Config_1.Config.get("application.environment") ||
84
+ this.getEnv("SIGNOZ_ENVIRONMENT") ||
85
+ this.getEnv("NODE_ENV") ||
86
+ "development";
87
+ const traceEndpoint = this.ensureEndpoint(options.endpoint ||
88
+ this.getEnv("SIGNOZ_ENDPOINT") ||
89
+ this.getEnv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") ||
90
+ this.getEnv("OTEL_EXPORTER_OTLP_ENDPOINT"), "http://localhost:4318", "/v1/traces");
91
+ const headers = Object.assign({}, (options.headers || {}));
92
+ const apiKey = options.apiKey || this.getEnv("SIGNOZ_API_KEY");
93
+ if (apiKey && !headers["signoz-access-token"]) {
94
+ headers["signoz-access-token"] = apiKey;
95
+ }
96
+ const { NodeSDK } = sdkModule;
97
+ const { OTLPTraceExporter } = traceExporterModule;
98
+ const { Resource } = resourcesModule;
99
+ const { SemanticResourceAttributes } = semanticModule;
100
+ const resourceAttributes = {
101
+ [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
102
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: environment,
103
+ };
104
+ if (options.resourceAttributes) {
105
+ Object.assign(resourceAttributes, options.resourceAttributes);
106
+ }
107
+ const resource = new Resource(resourceAttributes);
108
+ let instrumentations = options.instrumentations ? [...options.instrumentations] : [];
109
+ if (instrumentations.length === 0 && options.autoInstrumentations !== false) {
110
+ const autoModule = yield this.safeImport("@opentelemetry/auto-instrumentations-node");
111
+ if (autoModule === null || autoModule === void 0 ? void 0 : autoModule.getNodeAutoInstrumentations) {
112
+ instrumentations = [autoModule.getNodeAutoInstrumentations(options.autoInstrumentationConfig || {})];
113
+ }
114
+ else {
115
+ this.warnMissingDependency("@opentelemetry/auto-instrumentations-node");
116
+ }
117
+ }
118
+ let traceSampler;
119
+ if (typeof options.samplingRatio === "number") {
120
+ const samplerModule = yield this.safeImport("@opentelemetry/sdk-trace-base");
121
+ if ((samplerModule === null || samplerModule === void 0 ? void 0 : samplerModule.ParentBasedSampler) && (samplerModule === null || samplerModule === void 0 ? void 0 : samplerModule.TraceIdRatioBasedSampler)) {
122
+ const ratio = Math.min(Math.max(options.samplingRatio, 0), 1);
123
+ traceSampler = new samplerModule.ParentBasedSampler({
124
+ root: new samplerModule.TraceIdRatioBasedSampler(ratio),
125
+ });
126
+ }
127
+ else {
128
+ this.warnMissingDependency("@opentelemetry/sdk-trace-base");
129
+ }
130
+ }
131
+ const traceExporter = new OTLPTraceExporter({
132
+ url: traceEndpoint,
133
+ headers,
134
+ });
135
+ const sdkOptions = {
136
+ resource,
137
+ traceExporter,
138
+ };
139
+ if (instrumentations && instrumentations.length > 0) {
140
+ sdkOptions.instrumentations = instrumentations;
141
+ }
142
+ if (traceSampler) {
143
+ sdkOptions.traceSampler = traceSampler;
144
+ }
145
+ this.sdk = new NodeSDK(sdkOptions);
146
+ yield this.sdk.start();
147
+ if (options.logInitialization !== false) {
148
+ this.logInfo(`[SigNoz] Telemetry enabled (service="${serviceName}", endpoint="${traceEndpoint}")`);
149
+ }
150
+ this.registerShutdownHooks();
151
+ });
152
+ }
153
+ static shutdown() {
154
+ return __awaiter(this, void 0, void 0, function* () {
155
+ if (!this.sdk) {
156
+ return;
157
+ }
158
+ const sdkToShutdown = this.sdk;
159
+ this.sdk = null;
160
+ try {
161
+ yield sdkToShutdown.shutdown();
162
+ }
163
+ catch (error) {
164
+ this.logWarn("[SigNoz] Shutdown failed:", error);
165
+ }
166
+ });
167
+ }
168
+ static safeImport(moduleName) {
169
+ return __awaiter(this, void 0, void 0, function* () {
170
+ var _a;
171
+ try {
172
+ const module = yield (_a = moduleName, Promise.resolve().then(() => __importStar(require(_a))));
173
+ return module;
174
+ }
175
+ catch (error) {
176
+ if (error && (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_MODULE_NOT_FOUND")) {
177
+ return null;
178
+ }
179
+ throw error;
180
+ }
181
+ });
182
+ }
183
+ static ensureEndpoint(value, fallbackHost, defaultPath) {
184
+ const base = value && value.trim() !== "" ? value.trim() : fallbackHost;
185
+ if (base.includes("/v1/") || base.endsWith(defaultPath)) {
186
+ return base;
187
+ }
188
+ return `${base.replace(/\/$/, "")}${defaultPath}`;
189
+ }
190
+ static warnMissingDependency(name) {
191
+ if (this.missingDependencies.has(name)) {
192
+ return;
193
+ }
194
+ this.missingDependencies.add(name);
195
+ this.logWarn(`[SigNoz] Optional package "${name}" not found. Install it to enable the related feature.`);
196
+ }
197
+ static registerShutdownHooks() {
198
+ if (this.shutdownRegistered) {
199
+ return;
200
+ }
201
+ const nodeProcess = this.getProcess();
202
+ if (!nodeProcess) {
203
+ return;
204
+ }
205
+ nodeProcess.once("beforeExit", this.shutdownListener);
206
+ nodeProcess.once("exit", this.shutdownListener);
207
+ this.shutdownRegistered = true;
208
+ }
209
+ static getProcess() {
210
+ if (typeof globalThis === "undefined") {
211
+ return undefined;
212
+ }
213
+ const candidate = globalThis.process;
214
+ if (candidate && typeof candidate.once === "function") {
215
+ return candidate;
216
+ }
217
+ return undefined;
218
+ }
219
+ static getEnv(key) {
220
+ const nodeProcess = this.getProcess();
221
+ if (!nodeProcess || !nodeProcess.env) {
222
+ return undefined;
223
+ }
224
+ const value = nodeProcess.env[key];
225
+ return typeof value === "string" ? value : undefined;
226
+ }
227
+ static getConsole() {
228
+ if (typeof globalThis === "undefined") {
229
+ return undefined;
230
+ }
231
+ return globalThis.console;
232
+ }
233
+ static logInfo(...args) {
234
+ const target = this.getConsole();
235
+ if (target && typeof target.info === "function") {
236
+ target.info(...args);
237
+ }
238
+ }
239
+ static logWarn(...args) {
240
+ const target = this.getConsole();
241
+ if (target && typeof target.warn === "function") {
242
+ target.warn(...args);
243
+ }
244
+ }
245
+ }
246
+ exports.SigNozTelemetry = SigNozTelemetry;
247
+ SigNozTelemetry.sdk = null;
248
+ SigNozTelemetry.initPromise = null;
249
+ SigNozTelemetry.shutdownRegistered = false;
250
+ SigNozTelemetry.missingDependencies = new Set();
251
+ SigNozTelemetry.shutdownListener = () => {
252
+ void SigNozTelemetry.shutdown();
253
+ };
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WebApplication = void 0;
7
+ /// <reference types="node" />
7
8
  const http_1 = __importDefault(require("http"));
8
9
  const Config_1 = require("./Config");
9
10
  const Router_1 = require("./Router/Router");
10
11
  const QueueJobsRegisty_1 = require("./Queue/QueueJobsRegisty");
11
12
  const DatatableRegistry_1 = require("./Datatable/DatatableRegistry");
12
13
  const ModulesLoader_1 = require("./Modules/ModulesLoader");
14
+ const SigNozTelemetry_1 = require("./Telemetry/SigNozTelemetry");
13
15
  class WebApplication {
14
16
  constructor() {
15
17
  this.modulesLoader = null;
@@ -23,6 +25,9 @@ class WebApplication {
23
25
  Config_1.Config.register(key, options.config[key]);
24
26
  }
25
27
  }
28
+ if (options && options.signoz) {
29
+ void SigNozTelemetry_1.SigNozTelemetry.init(options.signoz);
30
+ }
26
31
  this.modulesLoader = new ModulesLoader_1.ModulesLoader();
27
32
  this.modulesLoader.load(options && options.modules ? options.modules : []);
28
33
  if (options && options.kernel) {
@@ -46,10 +51,16 @@ class WebApplication {
46
51
  this.server = http_1.default.createServer((req, res) => {
47
52
  Router_1.Router.handleRequest(req, res);
48
53
  });
54
+ this.server.on("close", () => {
55
+ void SigNozTelemetry_1.SigNozTelemetry.shutdown();
56
+ });
49
57
  this.server.listen(port, () => {
50
- console.log("Server started and listening on port " +
51
- port +
52
- (options && options.basename ? " (Basename: " + options && options.basename + ")" : ""));
58
+ const runtimeConsole = typeof globalThis !== "undefined" ? globalThis.console : undefined;
59
+ if (runtimeConsole && typeof runtimeConsole.log === "function") {
60
+ runtimeConsole.log("Server started and listening on port " +
61
+ port +
62
+ (options && options.basename ? " (Basename: " + options && options.basename + ")" : ""));
63
+ }
53
64
  if (options && options.onBoot) {
54
65
  options.onBoot(port);
55
66
  }
package/dist/index.d.ts CHANGED
@@ -31,4 +31,5 @@ export * from "./Queue/QueueJob";
31
31
  export * from "./Queue/QueueJobsRegisty";
32
32
  export * from "./Commands/ConsoleOutputHelper";
33
33
  export * from "./Modules/ModuleProvider";
34
+ export * from "./Telemetry/SigNozTelemetry";
34
35
  export * from "./info";
package/dist/index.js CHANGED
@@ -47,4 +47,5 @@ __exportStar(require("./Queue/QueueJob"), exports);
47
47
  __exportStar(require("./Queue/QueueJobsRegisty"), exports);
48
48
  __exportStar(require("./Commands/ConsoleOutputHelper"), exports);
49
49
  __exportStar(require("./Modules/ModuleProvider"), exports);
50
+ __exportStar(require("./Telemetry/SigNozTelemetry"), exports);
50
51
  __exportStar(require("./info"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webtypen/webframez-core",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "description": "The core package of the typescript based webframez (web-framework) by webtypen.de",
5
5
  "homepage": "https://webtypen.de/",
6
6
  "license": "MIT",
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { Config } from "./Config";
2
3
  import { ConsoleOutputHelper } from "./Commands/ConsoleOutputHelper";
3
4
  import { QueueWorkerCommand } from "./Commands/QueueWorkerCommand";
@@ -10,6 +11,7 @@ import { QueueStopCommand } from "./Commands/QueueStopCommand";
10
11
  import { QueueLogCommand } from "./Commands/QueueLogCommand";
11
12
  import { QueueWorkerAutorestartCommand } from "./Commands/QueueWorkerAutorestartCommand";
12
13
  import { WebframezInfo } from "./info";
14
+ import { SigNozTelemetry } from "./Telemetry/SigNozTelemetry";
13
15
 
14
16
  export class ConsoleApplication {
15
17
  systemCommands: any = [
@@ -32,6 +34,10 @@ export class ConsoleApplication {
32
34
  }
33
35
  }
34
36
 
37
+ if (options && options.signoz) {
38
+ void SigNozTelemetry.init(options.signoz);
39
+ }
40
+
35
41
  if (options && options.datatables) {
36
42
  DatatableRegistry.registerMany(options.datatables);
37
43
  }
@@ -0,0 +1,260 @@
1
+ import { Config } from "../Config";
2
+
3
+ export interface SigNozOptions {
4
+ enabled?: boolean;
5
+ serviceName?: string;
6
+ endpoint?: string;
7
+ apiKey?: string;
8
+ headers?: Record<string, string>;
9
+ environment?: string;
10
+ resourceAttributes?: Record<string, unknown>;
11
+ samplingRatio?: number;
12
+ instrumentations?: any[];
13
+ autoInstrumentations?: boolean;
14
+ autoInstrumentationConfig?: Record<string, unknown>;
15
+ logInitialization?: boolean;
16
+ }
17
+
18
+ export class SigNozTelemetry {
19
+ private static sdk: any = null;
20
+ private static initPromise: Promise<void> | null = null;
21
+ private static shutdownRegistered = false;
22
+ private static readonly missingDependencies = new Set<string>();
23
+ private static readonly shutdownListener = () => {
24
+ void SigNozTelemetry.shutdown();
25
+ };
26
+
27
+ static async init(options?: SigNozOptions): Promise<void> {
28
+ if (!options || options.enabled === false) {
29
+ return;
30
+ }
31
+ if (this.sdk) {
32
+ return;
33
+ }
34
+ if (this.initPromise) {
35
+ await this.initPromise;
36
+ return;
37
+ }
38
+
39
+ const initialization = (async () => {
40
+ try {
41
+ await this.initialize(options);
42
+ } catch (error) {
43
+ this.logWarn("[SigNoz] Initialization failed:", error);
44
+ }
45
+ })();
46
+
47
+ this.initPromise = initialization;
48
+
49
+ try {
50
+ await initialization;
51
+ } finally {
52
+ this.initPromise = null;
53
+ }
54
+ }
55
+
56
+ private static async initialize(options: SigNozOptions): Promise<void> {
57
+ const sdkModule = await this.safeImport<any>("@opentelemetry/sdk-node");
58
+ const traceExporterModule = await this.safeImport<any>("@opentelemetry/exporter-trace-otlp-http");
59
+ const resourcesModule = await this.safeImport<any>("@opentelemetry/resources");
60
+ const semanticModule = await this.safeImport<any>("@opentelemetry/semantic-conventions");
61
+
62
+ if (!sdkModule?.NodeSDK || !traceExporterModule?.OTLPTraceExporter || !resourcesModule?.Resource || !semanticModule?.SemanticResourceAttributes) {
63
+ throw new Error(
64
+ "OpenTelemetry packages are missing. Install '@opentelemetry/sdk-node', '@opentelemetry/exporter-trace-otlp-http', '@opentelemetry/resources' and '@opentelemetry/semantic-conventions'."
65
+ );
66
+ }
67
+
68
+ const serviceName =
69
+ options.serviceName ||
70
+ (Config.get("application.serviceName") as string) ||
71
+ (Config.get("application.name") as string) ||
72
+ this.getEnv("SIGNOZ_SERVICE_NAME") ||
73
+ this.getEnv("OTEL_SERVICE_NAME") ||
74
+ "webframez-service";
75
+
76
+ const environment =
77
+ options.environment ||
78
+ (Config.get("application.environment") as string) ||
79
+ this.getEnv("SIGNOZ_ENVIRONMENT") ||
80
+ this.getEnv("NODE_ENV") ||
81
+ "development";
82
+
83
+ const traceEndpoint = this.ensureEndpoint(
84
+ options.endpoint ||
85
+ this.getEnv("SIGNOZ_ENDPOINT") ||
86
+ this.getEnv("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") ||
87
+ this.getEnv("OTEL_EXPORTER_OTLP_ENDPOINT"),
88
+ "http://localhost:4318",
89
+ "/v1/traces"
90
+ );
91
+
92
+ const headers = { ...(options.headers || {}) };
93
+ const apiKey = options.apiKey || this.getEnv("SIGNOZ_API_KEY");
94
+ if (apiKey && !headers["signoz-access-token"]) {
95
+ headers["signoz-access-token"] = apiKey;
96
+ }
97
+
98
+ const { NodeSDK } = sdkModule;
99
+ const { OTLPTraceExporter } = traceExporterModule;
100
+ const { Resource } = resourcesModule;
101
+ const { SemanticResourceAttributes } = semanticModule;
102
+
103
+ const resourceAttributes: Record<string, unknown> = {
104
+ [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
105
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: environment,
106
+ };
107
+
108
+ if (options.resourceAttributes) {
109
+ Object.assign(resourceAttributes, options.resourceAttributes);
110
+ }
111
+
112
+ const resource = new Resource(resourceAttributes);
113
+
114
+ let instrumentations = options.instrumentations ? [...options.instrumentations] : [];
115
+ if (instrumentations.length === 0 && options.autoInstrumentations !== false) {
116
+ const autoModule = await this.safeImport<any>("@opentelemetry/auto-instrumentations-node");
117
+ if (autoModule?.getNodeAutoInstrumentations) {
118
+ instrumentations = [autoModule.getNodeAutoInstrumentations(options.autoInstrumentationConfig || {})];
119
+ } else {
120
+ this.warnMissingDependency("@opentelemetry/auto-instrumentations-node");
121
+ }
122
+ }
123
+
124
+ let traceSampler: any;
125
+ if (typeof options.samplingRatio === "number") {
126
+ const samplerModule = await this.safeImport<any>("@opentelemetry/sdk-trace-base");
127
+ if (samplerModule?.ParentBasedSampler && samplerModule?.TraceIdRatioBasedSampler) {
128
+ const ratio = Math.min(Math.max(options.samplingRatio, 0), 1);
129
+ traceSampler = new samplerModule.ParentBasedSampler({
130
+ root: new samplerModule.TraceIdRatioBasedSampler(ratio),
131
+ });
132
+ } else {
133
+ this.warnMissingDependency("@opentelemetry/sdk-trace-base");
134
+ }
135
+ }
136
+
137
+ const traceExporter = new OTLPTraceExporter({
138
+ url: traceEndpoint,
139
+ headers,
140
+ });
141
+
142
+ const sdkOptions: any = {
143
+ resource,
144
+ traceExporter,
145
+ };
146
+
147
+ if (instrumentations && instrumentations.length > 0) {
148
+ sdkOptions.instrumentations = instrumentations;
149
+ }
150
+ if (traceSampler) {
151
+ sdkOptions.traceSampler = traceSampler;
152
+ }
153
+
154
+ this.sdk = new NodeSDK(sdkOptions);
155
+ await this.sdk.start();
156
+
157
+ if (options.logInitialization !== false) {
158
+ this.logInfo(`[SigNoz] Telemetry enabled (service="${serviceName}", endpoint="${traceEndpoint}")`);
159
+ }
160
+
161
+ this.registerShutdownHooks();
162
+ }
163
+
164
+ static async shutdown(): Promise<void> {
165
+ if (!this.sdk) {
166
+ return;
167
+ }
168
+
169
+ const sdkToShutdown = this.sdk;
170
+ this.sdk = null;
171
+
172
+ try {
173
+ await sdkToShutdown.shutdown();
174
+ } catch (error) {
175
+ this.logWarn("[SigNoz] Shutdown failed:", error);
176
+ }
177
+ }
178
+
179
+ private static async safeImport<T = any>(moduleName: string): Promise<T | null> {
180
+ try {
181
+ const module = await import(moduleName);
182
+ return module as T;
183
+ } catch (error: any) {
184
+ if (error && (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_MODULE_NOT_FOUND")) {
185
+ return null;
186
+ }
187
+ throw error;
188
+ }
189
+ }
190
+
191
+ private static ensureEndpoint(value: string | undefined, fallbackHost: string, defaultPath: string): string {
192
+ const base = value && value.trim() !== "" ? value.trim() : fallbackHost;
193
+ if (base.includes("/v1/") || base.endsWith(defaultPath)) {
194
+ return base;
195
+ }
196
+ return `${base.replace(/\/$/, "")}${defaultPath}`;
197
+ }
198
+
199
+ private static warnMissingDependency(name: string) {
200
+ if (this.missingDependencies.has(name)) {
201
+ return;
202
+ }
203
+ this.missingDependencies.add(name);
204
+ this.logWarn(`[SigNoz] Optional package "${name}" not found. Install it to enable the related feature.`);
205
+ }
206
+
207
+ private static registerShutdownHooks() {
208
+ if (this.shutdownRegistered) {
209
+ return;
210
+ }
211
+ const nodeProcess = this.getProcess();
212
+ if (!nodeProcess) {
213
+ return;
214
+ }
215
+ nodeProcess.once("beforeExit", this.shutdownListener);
216
+ nodeProcess.once("exit", this.shutdownListener);
217
+ this.shutdownRegistered = true;
218
+ }
219
+
220
+ private static getProcess(): any {
221
+ if (typeof globalThis === "undefined") {
222
+ return undefined;
223
+ }
224
+ const candidate = (globalThis as any).process;
225
+ if (candidate && typeof candidate.once === "function") {
226
+ return candidate;
227
+ }
228
+ return undefined;
229
+ }
230
+
231
+ private static getEnv(key: string): string | undefined {
232
+ const nodeProcess = this.getProcess();
233
+ if (!nodeProcess || !nodeProcess.env) {
234
+ return undefined;
235
+ }
236
+ const value = nodeProcess.env[key];
237
+ return typeof value === "string" ? value : undefined;
238
+ }
239
+
240
+ private static getConsole(): any {
241
+ if (typeof globalThis === "undefined") {
242
+ return undefined;
243
+ }
244
+ return (globalThis as any).console;
245
+ }
246
+
247
+ private static logInfo(...args: unknown[]) {
248
+ const target = this.getConsole();
249
+ if (target && typeof target.info === "function") {
250
+ target.info(...args);
251
+ }
252
+ }
253
+
254
+ private static logWarn(...args: unknown[]) {
255
+ const target = this.getConsole();
256
+ if (target && typeof target.warn === "function") {
257
+ target.warn(...args);
258
+ }
259
+ }
260
+ }
@@ -1,9 +1,11 @@
1
+ /// <reference types="node" />
1
2
  import http, { Server } from "http";
2
3
  import { Config } from "./Config";
3
4
  import { Router } from "./Router/Router";
4
5
  import { QueueJobsRegisty } from "./Queue/QueueJobsRegisty";
5
6
  import { DatatableRegistry } from "./Datatable/DatatableRegistry";
6
7
  import { ModulesLoader } from "./Modules/ModulesLoader";
8
+ import { SigNozTelemetry } from "./Telemetry/SigNozTelemetry";
7
9
 
8
10
  export class WebApplication {
9
11
  private server!: Server;
@@ -19,6 +21,10 @@ export class WebApplication {
19
21
  }
20
22
  }
21
23
 
24
+ if (options && options.signoz) {
25
+ void SigNozTelemetry.init(options.signoz);
26
+ }
27
+
22
28
  this.modulesLoader = new ModulesLoader();
23
29
  this.modulesLoader.load(options && options.modules ? options.modules : []);
24
30
 
@@ -45,16 +51,23 @@ export class WebApplication {
45
51
  }
46
52
 
47
53
  const port = options && options.port ? options.port : 3000;
48
- this.server = http.createServer((req, res) => {
54
+ this.server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => {
49
55
  Router.handleRequest(req, res);
50
56
  });
51
57
 
58
+ this.server.on("close", () => {
59
+ void SigNozTelemetry.shutdown();
60
+ });
61
+
52
62
  this.server.listen(port, () => {
53
- console.log(
54
- "Server started and listening on port " +
55
- port +
56
- (options && options.basename ? " (Basename: " + options && options.basename + ")" : "")
57
- );
63
+ const runtimeConsole = typeof globalThis !== "undefined" ? (globalThis as any).console : undefined;
64
+ if (runtimeConsole && typeof runtimeConsole.log === "function") {
65
+ runtimeConsole.log(
66
+ "Server started and listening on port " +
67
+ port +
68
+ (options && options.basename ? " (Basename: " + options && options.basename + ")" : "")
69
+ );
70
+ }
58
71
 
59
72
  if (options && options.onBoot) {
60
73
  options.onBoot(port);
package/src/index.ts CHANGED
@@ -31,4 +31,5 @@ export * from "./Queue/QueueJob";
31
31
  export * from "./Queue/QueueJobsRegisty";
32
32
  export * from "./Commands/ConsoleOutputHelper";
33
33
  export * from "./Modules/ModuleProvider";
34
+ export * from "./Telemetry/SigNozTelemetry";
34
35
  export * from "./info";