@ciq-dev/neoiq-foundation-node 1.0.0 → 1.0.1-beta.0

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.
@@ -1,246 +0,0 @@
1
- "use strict";
2
- /**
3
- * OpenTelemetry initialization for Node.js services.
4
- *
5
- * Follows Groundcover Integration Guide - Option 2 (Via OTEL Collector)
6
- *
7
- * Flow: App → OpenTelemetry SDK → OTEL Collector → Groundcover
8
- *
9
- * Environment Variables:
10
- * OTEL_EXPORTER_OTLP_ENDPOINT: Collector URL (default: cluster OTEL Collector)
11
- * OTEL_SERVICE_NAME: Service name
12
- * OTEL_SERVICE_VERSION: Service version (default: 1.0.0)
13
- * OTEL_ENVIRONMENT: Deployment environment (default: development)
14
- *
15
- * Usage:
16
- * import { init, logger, getMeter } from '@commerceiq/neoiq-foundation-node';
17
- *
18
- * init({ serviceName: 'my-service' });
19
- *
20
- * logger.info({ action: 'startup' }, 'Service started');
21
- *
22
- * const meter = getMeter('my-service');
23
- * const counter = meter.createCounter('requests_total');
24
- */
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.SpanStatusCode = exports.logger = exports.als = void 0;
30
- exports.init = init;
31
- exports.getTracer = getTracer;
32
- exports.getMeter = getMeter;
33
- exports.getRequestContext = getRequestContext;
34
- exports.runWithContext = runWithContext;
35
- exports.getTraceContext = getTraceContext;
36
- exports.shutdown = shutdown;
37
- const sdk_node_1 = require("@opentelemetry/sdk-node");
38
- const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
39
- const exporter_trace_otlp_grpc_1 = require("@opentelemetry/exporter-trace-otlp-grpc");
40
- const exporter_metrics_otlp_grpc_1 = require("@opentelemetry/exporter-metrics-otlp-grpc");
41
- const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
42
- const resources_1 = require("@opentelemetry/resources");
43
- const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
44
- const api_1 = require("@opentelemetry/api");
45
- Object.defineProperty(exports, "SpanStatusCode", { enumerable: true, get: function () { return api_1.SpanStatusCode; } });
46
- const pino_1 = __importDefault(require("pino"));
47
- const async_hooks_1 = require("async_hooks");
48
- // -----------------------------------------------------------------------------
49
- // Configuration
50
- // -----------------------------------------------------------------------------
51
- // Default OTEL Collector endpoint (per Groundcover guide - Kubernetes internal)
52
- const DEFAULT_OTEL_COLLECTOR = 'http://otel-stack-deployment-collector.observability.svc.cluster.local:4317';
53
- exports.als = new async_hooks_1.AsyncLocalStorage();
54
- // -----------------------------------------------------------------------------
55
- // Module State
56
- // -----------------------------------------------------------------------------
57
- let sdk = null;
58
- let meterProvider = null;
59
- let baseLogger;
60
- let serviceName = 'unknown';
61
- let initialized = false;
62
- // -----------------------------------------------------------------------------
63
- // Initialization
64
- // -----------------------------------------------------------------------------
65
- /**
66
- * Initialize OpenTelemetry SDK with traces and metrics.
67
- *
68
- * Sends telemetry to OTEL Collector which forwards to Groundcover.
69
- * Call this at the very start of your application, before other imports.
70
- *
71
- * @example
72
- * init({ serviceName: 'canvas-weaver' });
73
- */
74
- function init(options) {
75
- if (initialized) {
76
- console.warn('[neoiq-foundation-node] Already initialized, skipping...');
77
- return;
78
- }
79
- const { serviceName: svcName, serviceVersion = process.env.OTEL_SERVICE_VERSION || '1.0.0', environment = process.env.OTEL_ENVIRONMENT || 'development', otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_COLLECTOR, logLevel = process.env.LOG_LEVEL || 'info', metricsIntervalMs = 5000, // 5 seconds per Groundcover guide
80
- } = options;
81
- serviceName = svcName;
82
- // 1. Create Resource (attached to all telemetry)
83
- const resource = (0, resources_1.resourceFromAttributes)({
84
- [semantic_conventions_1.ATTR_SERVICE_NAME]: serviceName,
85
- [semantic_conventions_1.ATTR_SERVICE_VERSION]: serviceVersion,
86
- 'deployment.environment': environment,
87
- });
88
- // 2. Setup Metrics Exporter (per Groundcover guide)
89
- const metricExporter = new exporter_metrics_otlp_grpc_1.OTLPMetricExporter({ url: otlpEndpoint });
90
- const metricReader = new sdk_metrics_1.PeriodicExportingMetricReader({
91
- exporter: metricExporter,
92
- exportIntervalMillis: metricsIntervalMs,
93
- });
94
- meterProvider = new sdk_metrics_1.MeterProvider({
95
- resource,
96
- readers: [metricReader],
97
- });
98
- api_1.metrics.setGlobalMeterProvider(meterProvider);
99
- // 3. Setup Trace Exporter
100
- const traceExporter = new exporter_trace_otlp_grpc_1.OTLPTraceExporter({ url: otlpEndpoint });
101
- // 4. Initialize NodeSDK with auto-instrumentation
102
- sdk = new sdk_node_1.NodeSDK({
103
- resource,
104
- traceExporter,
105
- instrumentations: [
106
- (0, auto_instrumentations_node_1.getNodeAutoInstrumentations)({
107
- // Disable fs instrumentation (too noisy)
108
- '@opentelemetry/instrumentation-fs': { enabled: false },
109
- }),
110
- ],
111
- });
112
- sdk.start();
113
- // 5. Setup Pino logger with trace context injection
114
- baseLogger = (0, pino_1.default)({
115
- level: logLevel,
116
- base: {
117
- service: serviceName,
118
- version: serviceVersion,
119
- env: environment,
120
- },
121
- mixin: () => {
122
- // Inject trace context into every log (correlates logs with traces in Groundcover)
123
- const span = api_1.trace.getActiveSpan();
124
- const ctx = exports.als.getStore();
125
- const spanContext = span?.spanContext();
126
- return {
127
- traceId: spanContext?.traceId || ctx?.traceId,
128
- spanId: spanContext?.spanId || ctx?.spanId,
129
- correlationId: ctx?.correlationId,
130
- };
131
- },
132
- formatters: {
133
- level: (label) => ({ level: label }),
134
- },
135
- transport: environment === 'development'
136
- ? { target: 'pino-pretty', options: { colorize: true } }
137
- : undefined,
138
- });
139
- baseLogger.info({
140
- endpoint: otlpEndpoint,
141
- metricsInterval: `${metricsIntervalMs}ms`,
142
- }, `OpenTelemetry initialized. Sending to OTEL Collector.`);
143
- initialized = true;
144
- }
145
- // -----------------------------------------------------------------------------
146
- // Logger API
147
- // -----------------------------------------------------------------------------
148
- /**
149
- * Structured logger with automatic trace context injection.
150
- * All logs include traceId, spanId, and correlationId when available.
151
- */
152
- exports.logger = {
153
- info: (obj, msg) => baseLogger?.info(obj, msg),
154
- error: (obj, msg) => baseLogger?.error(obj, msg),
155
- warn: (obj, msg) => baseLogger?.warn(obj, msg),
156
- debug: (obj, msg) => baseLogger?.debug(obj, msg),
157
- child: (bindings) => baseLogger?.child(bindings),
158
- };
159
- // -----------------------------------------------------------------------------
160
- // Tracer API
161
- // -----------------------------------------------------------------------------
162
- /**
163
- * Get a tracer instance for creating spans.
164
- *
165
- * @param name - Tracer name (defaults to service name)
166
- *
167
- * @example
168
- * const tracer = getTracer();
169
- * tracer.startActiveSpan('db.query', (span) => {
170
- * // ... do work
171
- * span.end();
172
- * });
173
- */
174
- function getTracer(name) {
175
- return api_1.trace.getTracer(name || serviceName);
176
- }
177
- // -----------------------------------------------------------------------------
178
- // Meter API
179
- // -----------------------------------------------------------------------------
180
- /**
181
- * Get a meter instance for creating metrics.
182
- * Metrics are exported to OTEL Collector → Groundcover.
183
- *
184
- * @param name - Meter name (typically service name)
185
- * @param version - Meter version (default: 1.0.0)
186
- *
187
- * @example
188
- * const meter = getMeter('canvas-weaver');
189
- * const counter = meter.createCounter('http.requests.total');
190
- * counter.add(1, { method: 'GET', route: '/api/reports' });
191
- *
192
- * const histogram = meter.createHistogram('http.request.duration');
193
- * histogram.record(150, { method: 'GET', route: '/api/reports' });
194
- */
195
- function getMeter(name, version = '1.0.0') {
196
- return api_1.metrics.getMeter(name, version);
197
- }
198
- // -----------------------------------------------------------------------------
199
- // Context Helpers
200
- // -----------------------------------------------------------------------------
201
- /**
202
- * Get current request context from AsyncLocalStorage.
203
- */
204
- function getRequestContext() {
205
- return exports.als.getStore();
206
- }
207
- /**
208
- * Run a function with a specific context (for manual context propagation).
209
- */
210
- function runWithContext(ctx, fn) {
211
- return exports.als.run(ctx, fn);
212
- }
213
- /**
214
- * Get current trace context as a dictionary.
215
- * Useful for logging or passing to external systems.
216
- */
217
- function getTraceContext() {
218
- const span = api_1.trace.getActiveSpan();
219
- if (!span)
220
- return {};
221
- const ctx = span.spanContext();
222
- return {
223
- traceId: ctx.traceId,
224
- spanId: ctx.spanId,
225
- };
226
- }
227
- // -----------------------------------------------------------------------------
228
- // Shutdown
229
- // -----------------------------------------------------------------------------
230
- /**
231
- * Gracefully shutdown OTEL providers.
232
- * Call this on application shutdown to flush pending telemetry.
233
- */
234
- async function shutdown() {
235
- if (!initialized)
236
- return;
237
- try {
238
- await meterProvider?.shutdown();
239
- await sdk?.shutdown();
240
- console.log('[neoiq-foundation-node] OTEL shutdown complete');
241
- }
242
- catch (error) {
243
- console.error('[neoiq-foundation-node] Error during shutdown:', error);
244
- }
245
- }
246
- //# sourceMappingURL=observability.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"observability.js","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"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"}
package/dist/plugin.d.ts DELETED
@@ -1,40 +0,0 @@
1
- /**
2
- * Fastify Observability Plugin
3
- *
4
- * Automatically handles:
5
- * - Correlation ID extraction/generation (x-request-id header)
6
- * - OpenTelemetry trace context propagation
7
- * - Request/response logging with trace context
8
- * - HTTP server metrics (request count, duration)
9
- *
10
- * Usage:
11
- * import { observabilityPlugin } from '@commerceiq/neoiq-foundation-node';
12
- * app.register(observabilityPlugin, { serviceName: 'my-service' });
13
- */
14
- import { FastifyPluginAsync } from 'fastify';
15
- import { Span } from '@opentelemetry/api';
16
- interface PluginRequestContext {
17
- correlationId: string;
18
- traceId: string;
19
- spanId: string;
20
- startTime: number;
21
- }
22
- export interface PluginOptions {
23
- /**
24
- * Service name for metrics (required).
25
- */
26
- serviceName: string;
27
- /**
28
- * Routes to exclude from tracing/metrics (e.g., ['/health']).
29
- */
30
- excludeRoutes?: string[];
31
- }
32
- declare module 'fastify' {
33
- interface FastifyRequest {
34
- __span?: Span;
35
- __requestContext?: PluginRequestContext;
36
- }
37
- }
38
- export declare const observabilityPlugin: FastifyPluginAsync<PluginOptions>;
39
- export {};
40
- //# sourceMappingURL=plugin.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AAG3E,OAAO,EAA+C,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAOvF,UAAU,oBAAoB;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAGD,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,MAAM,CAAC,EAAE,IAAI,CAAC;QACd,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;KACzC;CACF;AA8LD,eAAO,MAAM,mBAAmB,mCAG9B,CAAC"}
package/dist/plugin.js DELETED
@@ -1,176 +0,0 @@
1
- "use strict";
2
- /**
3
- * Fastify Observability Plugin
4
- *
5
- * Automatically handles:
6
- * - Correlation ID extraction/generation (x-request-id header)
7
- * - OpenTelemetry trace context propagation
8
- * - Request/response logging with trace context
9
- * - HTTP server metrics (request count, duration)
10
- *
11
- * Usage:
12
- * import { observabilityPlugin } from '@commerceiq/neoiq-foundation-node';
13
- * app.register(observabilityPlugin, { serviceName: 'my-service' });
14
- */
15
- var __importDefault = (this && this.__importDefault) || function (mod) {
16
- return (mod && mod.__esModule) ? mod : { "default": mod };
17
- };
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.observabilityPlugin = void 0;
20
- const fastify_plugin_1 = __importDefault(require("fastify-plugin"));
21
- const crypto_1 = require("crypto");
22
- const api_1 = require("@opentelemetry/api");
23
- const observability_1 = require("./observability");
24
- // -----------------------------------------------------------------------------
25
- // Plugin Implementation
26
- // -----------------------------------------------------------------------------
27
- const plugin = async (fastify, options) => {
28
- const { serviceName, excludeRoutes = ['/health', '/health/'] } = options;
29
- const tracer = api_1.trace.getTracer('neoiq-foundation-node');
30
- // Setup metrics (per Groundcover guide)
31
- const meter = (0, observability_1.getMeter)(serviceName);
32
- const requestCounter = meter.createCounter('http.server.requests.total', {
33
- description: 'Total number of HTTP requests',
34
- });
35
- const requestDuration = meter.createHistogram('http.server.request.duration', {
36
- description: 'HTTP request duration in milliseconds',
37
- unit: 'ms',
38
- });
39
- const requestErrors = meter.createCounter('http.server.requests.errors', {
40
- description: 'Total number of HTTP request errors',
41
- });
42
- // ---------------------------------------------------------------------------
43
- // ON REQUEST - Extract context, start span
44
- // ---------------------------------------------------------------------------
45
- fastify.addHook('onRequest', (request, reply, done) => {
46
- // Skip health checks
47
- if (excludeRoutes.some((route) => request.url.startsWith(route))) {
48
- done();
49
- return;
50
- }
51
- // 1. Extract or generate correlation ID from x-request-id header
52
- const correlationId = request.headers['x-request-id'] || (0, crypto_1.randomUUID)();
53
- // 2. Set correlation ID in response header
54
- reply.header('x-request-id', correlationId);
55
- // 3. Extract parent trace context from incoming headers (W3C traceparent)
56
- const parentContext = api_1.propagation.extract(api_1.context.active(), request.headers);
57
- // 4. Start a new span for this request
58
- const span = tracer.startSpan(`${request.method} ${request.routeOptions?.url || request.url}`, {
59
- kind: 1, // SpanKind.SERVER
60
- attributes: {
61
- 'http.method': request.method,
62
- 'http.url': request.url,
63
- 'http.route': request.routeOptions?.url || request.url,
64
- 'http.user_agent': request.headers['user-agent'] || '',
65
- 'http.correlation_id': correlationId,
66
- },
67
- }, parentContext);
68
- // 5. Get trace/span IDs
69
- const spanContext = span.spanContext();
70
- const traceId = spanContext.traceId;
71
- const spanId = spanContext.spanId;
72
- // 6. Store context
73
- const requestContext = {
74
- correlationId,
75
- traceId,
76
- spanId,
77
- startTime: Date.now(),
78
- };
79
- request.__span = span;
80
- request.__requestContext = requestContext;
81
- // 7. Run in AsyncLocalStorage context
82
- observability_1.als.run({ correlationId, traceId, spanId }, () => {
83
- observability_1.logger.info({
84
- correlationId,
85
- traceId,
86
- spanId,
87
- method: request.method,
88
- url: request.url,
89
- route: request.routeOptions?.url,
90
- userAgent: request.headers['user-agent'],
91
- }, 'Request received');
92
- done();
93
- });
94
- });
95
- // ---------------------------------------------------------------------------
96
- // ON RESPONSE - End span, record metrics
97
- // ---------------------------------------------------------------------------
98
- fastify.addHook('onResponse', (request, reply, done) => {
99
- const ctx = request.__requestContext;
100
- const span = request.__span;
101
- if (!ctx) {
102
- done();
103
- return;
104
- }
105
- const durationMs = Date.now() - ctx.startTime;
106
- const route = request.routeOptions?.url || request.url;
107
- const labels = {
108
- method: request.method,
109
- route,
110
- status_code: String(reply.statusCode),
111
- };
112
- // Run in context for proper log correlation
113
- observability_1.als.run({ correlationId: ctx.correlationId, traceId: ctx.traceId, spanId: ctx.spanId }, () => {
114
- // Log response
115
- observability_1.logger.info({
116
- correlationId: ctx.correlationId,
117
- traceId: ctx.traceId,
118
- spanId: ctx.spanId,
119
- method: request.method,
120
- url: request.url,
121
- route,
122
- statusCode: reply.statusCode,
123
- durationMs,
124
- }, 'Request completed');
125
- // Record metrics (per Groundcover guide)
126
- requestCounter.add(1, labels);
127
- requestDuration.record(durationMs, labels);
128
- if (reply.statusCode >= 400) {
129
- requestErrors.add(1, labels);
130
- }
131
- // End span
132
- if (span) {
133
- span.setStatus({
134
- code: reply.statusCode < 400 ? api_1.SpanStatusCode.OK : api_1.SpanStatusCode.ERROR,
135
- });
136
- span.setAttribute('http.status_code', reply.statusCode);
137
- span.setAttribute('http.response_time_ms', durationMs);
138
- span.end();
139
- }
140
- done();
141
- });
142
- });
143
- // ---------------------------------------------------------------------------
144
- // ON ERROR - Record exception on span
145
- // ---------------------------------------------------------------------------
146
- fastify.addHook('onError', (request, reply, error, done) => {
147
- const ctx = request.__requestContext;
148
- const span = request.__span;
149
- if (!ctx) {
150
- done();
151
- return;
152
- }
153
- observability_1.als.run({ correlationId: ctx.correlationId, traceId: ctx.traceId, spanId: ctx.spanId }, () => {
154
- observability_1.logger.error({
155
- correlationId: ctx.correlationId,
156
- traceId: ctx.traceId,
157
- spanId: ctx.spanId,
158
- method: request.method,
159
- url: request.url,
160
- error: error.message,
161
- stack: error.stack,
162
- }, 'Request failed');
163
- if (span) {
164
- span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
165
- span.recordException(error);
166
- }
167
- done();
168
- });
169
- });
170
- };
171
- // Export plugin
172
- exports.observabilityPlugin = (0, fastify_plugin_1.default)(plugin, {
173
- name: 'neoiq-observability',
174
- fastify: '4.x',
175
- });
176
- //# sourceMappingURL=plugin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}