@payloops/observability 0.0.8 → 0.0.11

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/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { NodeSDK } from '@opentelemetry/sdk-node';
2
- import pino from 'pino';
3
2
  import * as _opentelemetry_api from '@opentelemetry/api';
4
3
 
5
4
  interface TelemetryConfig {
@@ -16,24 +15,37 @@ interface TelemetryConfig {
16
15
  declare function initTelemetry(config: TelemetryConfig | string, serviceVersion?: string): NodeSDK;
17
16
  declare function shutdownTelemetry(): Promise<void>;
18
17
 
18
+ interface Logger {
19
+ trace(msg: string): void;
20
+ trace(data: Record<string, unknown>, msg: string): void;
21
+ debug(msg: string): void;
22
+ debug(data: Record<string, unknown>, msg: string): void;
23
+ info(msg: string): void;
24
+ info(data: Record<string, unknown>, msg: string): void;
25
+ warn(msg: string): void;
26
+ warn(data: Record<string, unknown>, msg: string): void;
27
+ error(msg: string): void;
28
+ error(data: Record<string, unknown>, msg: string): void;
29
+ fatal(msg: string): void;
30
+ fatal(data: Record<string, unknown>, msg: string): void;
31
+ child(bindings: Record<string, unknown>): Logger;
32
+ }
19
33
  /**
20
- * Base logger with trace context mixin
21
- * In development: pretty print to console + OTLP
22
- * In production: JSON to stdout + OTLP
34
+ * Base logger instance
23
35
  */
24
- declare const logger: pino.Logger<never, boolean>;
36
+ declare const logger: Logger;
25
37
  /**
26
38
  * Create a child logger for a specific activity
27
39
  */
28
- declare function createActivityLogger(activityName: string, correlationId?: string): pino.Logger<never, boolean>;
40
+ declare function createActivityLogger(activityName: string, correlationId?: string): Logger;
29
41
  /**
30
42
  * Create a child logger for a specific workflow
31
43
  */
32
- declare function createWorkflowLogger(workflowId: string, correlationId?: string): pino.Logger<never, boolean>;
44
+ declare function createWorkflowLogger(workflowId: string, correlationId?: string): Logger;
33
45
  /**
34
46
  * Create a child logger for HTTP requests
35
47
  */
36
- declare function createRequestLogger(requestId: string, method: string, path: string): pino.Logger<never, boolean>;
48
+ declare function createRequestLogger(requestId: string, method: string, path: string): Logger;
37
49
 
38
50
  /**
39
51
  * Correlation context for tracking requests across services
package/dist/index.js CHANGED
@@ -284,9 +284,8 @@ function shutdownTelemetry() {
284
284
  }
285
285
 
286
286
  // src/lib/logger.ts
287
- import pino from "pino";
288
287
  import { trace } from "@opentelemetry/api";
289
- import { logs as logs2, SeverityNumber as SeverityNumber2 } from "@opentelemetry/api-logs";
288
+ import { logs as logs2, SeverityNumber } from "@opentelemetry/api-logs";
290
289
 
291
290
  // src/lib/context.ts
292
291
  import { AsyncLocalStorage } from "async_hooks";
@@ -333,54 +332,63 @@ function createContextFromMemo(memo) {
333
332
  // src/lib/logger.ts
334
333
  var NODE_ENV = process.env.NODE_ENV || "development";
335
334
  var SERVICE_NAME = process.env.OTEL_SERVICE_NAME || "loop";
336
- var pinoLevelToOtelSeverity = {
337
- 10: SeverityNumber2.TRACE,
338
- // trace
339
- 20: SeverityNumber2.DEBUG,
340
- // debug
341
- 30: SeverityNumber2.INFO,
342
- // info
343
- 40: SeverityNumber2.WARN,
344
- // warn
345
- 50: SeverityNumber2.ERROR,
346
- // error
347
- 60: SeverityNumber2.FATAL
348
- // fatal
335
+ var LOG_LEVEL = process.env.LOG_LEVEL || (NODE_ENV === "production" ? "info" : "debug");
336
+ var colors = {
337
+ reset: "\x1B[0m",
338
+ dim: "\x1B[2m",
339
+ red: "\x1B[31m",
340
+ green: "\x1B[32m",
341
+ yellow: "\x1B[33m",
342
+ blue: "\x1B[34m",
343
+ magenta: "\x1B[35m",
344
+ cyan: "\x1B[36m"
349
345
  };
350
- var traceMixin = () => {
351
- const mixinData = {};
346
+ var levelConfig = {
347
+ trace: { severity: SeverityNumber.TRACE, color: colors.dim, label: "TRACE", priority: 0 },
348
+ debug: { severity: SeverityNumber.DEBUG, color: colors.blue, label: "DEBUG", priority: 1 },
349
+ info: { severity: SeverityNumber.INFO, color: colors.green, label: "INFO", priority: 2 },
350
+ warn: { severity: SeverityNumber.WARN, color: colors.yellow, label: "WARN", priority: 3 },
351
+ error: { severity: SeverityNumber.ERROR, color: colors.red, label: "ERROR", priority: 4 },
352
+ fatal: { severity: SeverityNumber.FATAL, color: colors.magenta, label: "FATAL", priority: 5 }
353
+ };
354
+ var currentLevelPriority = levelConfig[LOG_LEVEL]?.priority ?? 2;
355
+ function getContext() {
356
+ const ctx = {};
352
357
  const span = trace.getActiveSpan();
353
358
  if (span) {
354
359
  const spanContext = span.spanContext();
355
- mixinData.trace_id = spanContext.traceId;
356
- mixinData.span_id = spanContext.spanId;
360
+ ctx.trace_id = spanContext.traceId;
361
+ ctx.span_id = spanContext.spanId;
357
362
  }
358
363
  const correlationCtx = getCorrelationContext();
359
364
  if (correlationCtx) {
360
- mixinData.correlation_id = correlationCtx.correlationId;
361
- if (correlationCtx.merchantId) mixinData.merchant_id = correlationCtx.merchantId;
362
- if (correlationCtx.orderId) mixinData.order_id = correlationCtx.orderId;
363
- if (correlationCtx.workflowId) mixinData.workflow_id = correlationCtx.workflowId;
365
+ ctx.correlation_id = correlationCtx.correlationId;
366
+ if (correlationCtx.merchantId) ctx.merchant_id = correlationCtx.merchantId;
367
+ if (correlationCtx.orderId) ctx.order_id = correlationCtx.orderId;
368
+ if (correlationCtx.workflowId) ctx.workflow_id = correlationCtx.workflowId;
364
369
  }
365
- return mixinData;
366
- };
367
- function emitToOtel(logRecord) {
370
+ return ctx;
371
+ }
372
+ function emitToOtel(level, message, attributes) {
368
373
  try {
369
- const otelLogger = logs2.getLogger(SERVICE_NAME);
374
+ const provider = logs2.getLoggerProvider();
375
+ if (provider.constructor.name === "ProxyLoggerProvider") {
376
+ return;
377
+ }
378
+ const otelLogger = provider.getLogger(SERVICE_NAME);
370
379
  const span = trace.getActiveSpan();
371
380
  const spanContext = span?.spanContext();
381
+ const config = levelConfig[level];
372
382
  otelLogger.emit({
373
- severityNumber: pinoLevelToOtelSeverity[logRecord.level] || SeverityNumber2.INFO,
374
- severityText: pino.levels.labels[logRecord.level] || "INFO",
375
- body: logRecord.msg,
383
+ severityNumber: config?.severity ?? SeverityNumber.INFO,
384
+ severityText: config?.label ?? "INFO",
385
+ body: message,
376
386
  attributes: {
377
- ...logRecord,
378
- // Remove fields that are part of the log record structure
379
- msg: void 0,
380
- level: void 0,
381
- time: void 0
387
+ service: SERVICE_NAME,
388
+ env: NODE_ENV,
389
+ ...attributes
382
390
  },
383
- timestamp: logRecord.time ? new Date(logRecord.time).getTime() * 1e6 : Date.now() * 1e6,
391
+ timestamp: Date.now() * 1e6,
384
392
  // nanoseconds
385
393
  ...spanContext && {
386
394
  spanId: spanContext.spanId,
@@ -391,65 +399,74 @@ function emitToOtel(logRecord) {
391
399
  } catch {
392
400
  }
393
401
  }
394
- var otelHooks = {
395
- logMethod(inputArgs, method, level) {
396
- method.apply(this, inputArgs);
397
- const [objOrMsg, msgOrUndefined] = inputArgs;
398
- const logRecord = {
399
- level,
400
- time: (/* @__PURE__ */ new Date()).toISOString(),
402
+ function formatConsole(level, message, data) {
403
+ const config = levelConfig[level];
404
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
405
+ const color = config?.color ?? colors.reset;
406
+ const label = config?.label ?? level.toUpperCase();
407
+ if (NODE_ENV === "production") {
408
+ return JSON.stringify({
409
+ time: timestamp,
410
+ level: label,
411
+ msg: message,
401
412
  service: SERVICE_NAME,
402
- env: NODE_ENV
403
- };
404
- if (typeof objOrMsg === "object" && objOrMsg !== null) {
405
- Object.assign(logRecord, objOrMsg);
406
- logRecord.msg = msgOrUndefined || "";
407
- } else {
408
- logRecord.msg = objOrMsg;
409
- }
410
- Object.assign(logRecord, traceMixin());
411
- emitToOtel(logRecord);
413
+ env: NODE_ENV,
414
+ ...data
415
+ });
412
416
  }
413
- };
414
- var logger = pino(
415
- {
416
- level: NODE_ENV === "production" ? "info" : "debug",
417
- mixin: traceMixin,
418
- base: {
419
- service: SERVICE_NAME,
420
- env: NODE_ENV
421
- },
422
- timestamp: pino.stdTimeFunctions.isoTime,
423
- hooks: otelHooks,
424
- // In development, use pino-pretty for console output
425
- ...NODE_ENV !== "production" && {
426
- transport: {
427
- target: "pino-pretty",
428
- options: { colorize: true }
429
- }
417
+ const timeStr = `${colors.dim}[${timestamp.split("T")[1].slice(0, -1)}]${colors.reset}`;
418
+ const levelStr = `${color}${label.padEnd(5)}${colors.reset}`;
419
+ const msgStr = `${color}${message}${colors.reset}`;
420
+ const dataEntries = Object.entries(data).filter(([, v]) => v !== void 0);
421
+ const dataStr = dataEntries.length > 0 ? "\n" + dataEntries.map(([k, v]) => ` ${colors.magenta}${k}${colors.reset}: ${JSON.stringify(v)}`).join("\n") : "";
422
+ return `${timeStr} ${levelStr}: ${msgStr}${dataStr}`;
423
+ }
424
+ function log(level, msgOrData, msg) {
425
+ const config = levelConfig[level];
426
+ if (!config || config.priority < currentLevelPriority) {
427
+ return;
428
+ }
429
+ let message;
430
+ let data;
431
+ if (typeof msgOrData === "string") {
432
+ message = msgOrData;
433
+ data = {};
434
+ } else {
435
+ message = msg ?? "";
436
+ data = msgOrData;
437
+ }
438
+ const context2 = getContext();
439
+ const enrichedData = { ...data, ...context2 };
440
+ console.log(formatConsole(level, message, enrichedData));
441
+ emitToOtel(level, message, enrichedData);
442
+ }
443
+ function createLogger(bindings = {}) {
444
+ const boundLog = (level, msgOrData, msg) => {
445
+ if (typeof msgOrData === "string") {
446
+ log(level, { ...bindings }, msgOrData);
447
+ } else {
448
+ log(level, { ...bindings, ...msgOrData }, msg);
430
449
  }
431
- },
432
- // In production, also write JSON to stdout (in addition to OTLP via hooks)
433
- NODE_ENV === "production" ? pino.destination(1) : void 0
434
- );
450
+ };
451
+ return {
452
+ trace: (msgOrData, msg) => boundLog("trace", msgOrData, msg),
453
+ debug: (msgOrData, msg) => boundLog("debug", msgOrData, msg),
454
+ info: (msgOrData, msg) => boundLog("info", msgOrData, msg),
455
+ warn: (msgOrData, msg) => boundLog("warn", msgOrData, msg),
456
+ error: (msgOrData, msg) => boundLog("error", msgOrData, msg),
457
+ fatal: (msgOrData, msg) => boundLog("fatal", msgOrData, msg),
458
+ child: (childBindings) => createLogger({ ...bindings, ...childBindings })
459
+ };
460
+ }
461
+ var logger = createLogger({ service: SERVICE_NAME, env: NODE_ENV });
435
462
  function createActivityLogger(activityName, correlationId) {
436
- return logger.child({
437
- activity: activityName,
438
- correlationId
439
- });
463
+ return logger.child({ activity: activityName, correlationId });
440
464
  }
441
465
  function createWorkflowLogger(workflowId, correlationId) {
442
- return logger.child({
443
- workflowId,
444
- correlationId
445
- });
466
+ return logger.child({ workflowId, correlationId });
446
467
  }
447
468
  function createRequestLogger(requestId, method, path) {
448
- return logger.child({
449
- requestId,
450
- method,
451
- path
452
- });
469
+ return logger.child({ requestId, method, path });
453
470
  }
454
471
 
455
472
  // src/lib/metrics.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloops/observability",
3
- "version": "0.0.8",
3
+ "version": "0.0.11",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,14 +36,12 @@
36
36
  "@opentelemetry/sdk-metrics": "^1.30.1",
37
37
  "@opentelemetry/sdk-node": "^0.57.0",
38
38
  "@opentelemetry/semantic-conventions": "^1.28.0",
39
- "nanoid": "^5.0.9",
40
- "pino": "^9.6.0"
39
+ "nanoid": "^5.0.9"
41
40
  },
42
41
  "devDependencies": {
43
42
  "@eslint/js": "^9.39.2",
44
43
  "@types/node": "^22.0.0",
45
44
  "eslint": "^9.0.0",
46
- "pino-pretty": "^13.0.0",
47
45
  "tsup": "^8.3.5",
48
46
  "typescript": "^5.9.3",
49
47
  "typescript-eslint": "^8.53.0"