@payloops/observability 0.0.9 → 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,38 +332,44 @@ 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
374
  const provider = logs2.getLoggerProvider();
370
375
  if (provider.constructor.name === "ProxyLoggerProvider") {
@@ -373,18 +378,17 @@ function emitToOtel(logRecord) {
373
378
  const otelLogger = provider.getLogger(SERVICE_NAME);
374
379
  const span = trace.getActiveSpan();
375
380
  const spanContext = span?.spanContext();
381
+ const config = levelConfig[level];
376
382
  otelLogger.emit({
377
- severityNumber: pinoLevelToOtelSeverity[logRecord.level] || SeverityNumber2.INFO,
378
- severityText: pino.levels.labels[logRecord.level] || "INFO",
379
- body: logRecord.msg,
383
+ severityNumber: config?.severity ?? SeverityNumber.INFO,
384
+ severityText: config?.label ?? "INFO",
385
+ body: message,
380
386
  attributes: {
381
- ...logRecord,
382
- // Remove fields that are part of the log record structure
383
- msg: void 0,
384
- level: void 0,
385
- time: void 0
387
+ service: SERVICE_NAME,
388
+ env: NODE_ENV,
389
+ ...attributes
386
390
  },
387
- timestamp: logRecord.time ? new Date(logRecord.time).getTime() * 1e6 : Date.now() * 1e6,
391
+ timestamp: Date.now() * 1e6,
388
392
  // nanoseconds
389
393
  ...spanContext && {
390
394
  spanId: spanContext.spanId,
@@ -395,65 +399,74 @@ function emitToOtel(logRecord) {
395
399
  } catch {
396
400
  }
397
401
  }
398
- var otelHooks = {
399
- logMethod(inputArgs, method, level) {
400
- method.apply(this, inputArgs);
401
- const [objOrMsg, msgOrUndefined] = inputArgs;
402
- const logRecord = {
403
- level,
404
- 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,
405
412
  service: SERVICE_NAME,
406
- env: NODE_ENV
407
- };
408
- if (typeof objOrMsg === "object" && objOrMsg !== null) {
409
- Object.assign(logRecord, objOrMsg);
410
- logRecord.msg = msgOrUndefined || "";
411
- } else {
412
- logRecord.msg = objOrMsg;
413
- }
414
- Object.assign(logRecord, traceMixin());
415
- emitToOtel(logRecord);
413
+ env: NODE_ENV,
414
+ ...data
415
+ });
416
416
  }
417
- };
418
- var logger = pino(
419
- {
420
- level: NODE_ENV === "production" ? "info" : "debug",
421
- mixin: traceMixin,
422
- base: {
423
- service: SERVICE_NAME,
424
- env: NODE_ENV
425
- },
426
- timestamp: pino.stdTimeFunctions.isoTime,
427
- hooks: otelHooks,
428
- // In development, use pino-pretty for console output
429
- ...NODE_ENV !== "production" && {
430
- transport: {
431
- target: "pino-pretty",
432
- options: { colorize: true }
433
- }
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);
434
449
  }
435
- },
436
- // In production, also write JSON to stdout (in addition to OTLP via hooks)
437
- NODE_ENV === "production" ? pino.destination(1) : void 0
438
- );
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 });
439
462
  function createActivityLogger(activityName, correlationId) {
440
- return logger.child({
441
- activity: activityName,
442
- correlationId
443
- });
463
+ return logger.child({ activity: activityName, correlationId });
444
464
  }
445
465
  function createWorkflowLogger(workflowId, correlationId) {
446
- return logger.child({
447
- workflowId,
448
- correlationId
449
- });
466
+ return logger.child({ workflowId, correlationId });
450
467
  }
451
468
  function createRequestLogger(requestId, method, path) {
452
- return logger.child({
453
- requestId,
454
- method,
455
- path
456
- });
469
+ return logger.child({ requestId, method, path });
457
470
  }
458
471
 
459
472
  // src/lib/metrics.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloops/observability",
3
- "version": "0.0.9",
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"