@justanalyticsapp/node 0.1.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.
- package/dist/client.d.ts +286 -0
- package/dist/client.js +681 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +126 -0
- package/dist/context.js +170 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +135 -0
- package/dist/errors.js +180 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +314 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/express.d.ts +77 -0
- package/dist/integrations/express.js +87 -0
- package/dist/integrations/express.js.map +1 -0
- package/dist/integrations/http.d.ts +129 -0
- package/dist/integrations/http.js +465 -0
- package/dist/integrations/http.js.map +1 -0
- package/dist/integrations/metrics.d.ts +110 -0
- package/dist/integrations/metrics.js +313 -0
- package/dist/integrations/metrics.js.map +1 -0
- package/dist/integrations/next.d.ts +252 -0
- package/dist/integrations/next.js +480 -0
- package/dist/integrations/next.js.map +1 -0
- package/dist/integrations/pg.d.ts +169 -0
- package/dist/integrations/pg.js +616 -0
- package/dist/integrations/pg.js.map +1 -0
- package/dist/integrations/pino.d.ts +52 -0
- package/dist/integrations/pino.js +153 -0
- package/dist/integrations/pino.js.map +1 -0
- package/dist/integrations/redis.d.ts +190 -0
- package/dist/integrations/redis.js +597 -0
- package/dist/integrations/redis.js.map +1 -0
- package/dist/integrations/winston.d.ts +48 -0
- package/dist/integrations/winston.js +99 -0
- package/dist/integrations/winston.js.map +1 -0
- package/dist/logger.d.ts +148 -0
- package/dist/logger.js +162 -0
- package/dist/logger.js.map +1 -0
- package/dist/span.d.ts +192 -0
- package/dist/span.js +197 -0
- package/dist/span.js.map +1 -0
- package/dist/transport.d.ts +246 -0
- package/dist/transport.js +654 -0
- package/dist/transport.js.map +1 -0
- package/dist/utils/headers.d.ts +60 -0
- package/dist/utils/headers.js +93 -0
- package/dist/utils/headers.js.map +1 -0
- package/dist/utils/id.d.ts +23 -0
- package/dist/utils/id.js +36 -0
- package/dist/utils/id.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file packages/node-sdk/src/integrations/winston.ts
|
|
4
|
+
* @description Winston transport for JustAnalytics log integration.
|
|
5
|
+
*
|
|
6
|
+
* Implements Story 046 - SDK Log Integration
|
|
7
|
+
*
|
|
8
|
+
* Pipes Winston log entries through the JustAnalytics SDK logger,
|
|
9
|
+
* automatically attaching trace context and batching for transport.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import winston from 'winston';
|
|
14
|
+
* import { JustAnalyticsWinstonTransport } from '@justanalyticsapp/node/winston';
|
|
15
|
+
*
|
|
16
|
+
* const logger = winston.createLogger({
|
|
17
|
+
* transports: [
|
|
18
|
+
* new winston.transports.Console(),
|
|
19
|
+
* new JustAnalyticsWinstonTransport(),
|
|
20
|
+
* ],
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* The transport requires `winston` and `winston-transport` as peer dependencies.
|
|
25
|
+
* Install them separately: `npm install winston winston-transport`
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.JustAnalyticsWinstonTransport = void 0;
|
|
29
|
+
/** Winston to JustAnalytics level mapping */
|
|
30
|
+
const DEFAULT_LEVEL_MAP = {
|
|
31
|
+
error: 'error',
|
|
32
|
+
warn: 'warn',
|
|
33
|
+
info: 'info',
|
|
34
|
+
http: 'debug',
|
|
35
|
+
verbose: 'debug',
|
|
36
|
+
debug: 'debug',
|
|
37
|
+
silly: 'debug',
|
|
38
|
+
fatal: 'fatal',
|
|
39
|
+
};
|
|
40
|
+
// Dynamically load winston-transport at runtime (optional peer dependency)
|
|
41
|
+
let TransportStreamBase;
|
|
42
|
+
try {
|
|
43
|
+
TransportStreamBase = require('winston-transport');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// winston-transport not installed -- class will throw on construction
|
|
47
|
+
TransportStreamBase = null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Winston transport that forwards log entries to JustAnalytics.
|
|
51
|
+
*
|
|
52
|
+
* Extracts message, level, and metadata from Winston info objects
|
|
53
|
+
* and pipes them through JA.logger for batched transport with
|
|
54
|
+
* automatic trace context attachment.
|
|
55
|
+
*/
|
|
56
|
+
class JustAnalyticsWinstonTransport {
|
|
57
|
+
constructor(opts) {
|
|
58
|
+
if (!TransportStreamBase) {
|
|
59
|
+
throw new Error('[JustAnalytics] winston-transport is required for the Winston integration. ' +
|
|
60
|
+
'Install it with: npm install winston-transport');
|
|
61
|
+
}
|
|
62
|
+
// Call the parent TransportStream constructor
|
|
63
|
+
TransportStreamBase.call(this, opts);
|
|
64
|
+
this.levelMap = opts?.levelMap
|
|
65
|
+
? { ...DEFAULT_LEVEL_MAP, ...opts.levelMap }
|
|
66
|
+
: { ...DEFAULT_LEVEL_MAP };
|
|
67
|
+
}
|
|
68
|
+
log(info, callback) {
|
|
69
|
+
try {
|
|
70
|
+
// Strip ANSI escape codes from the level string
|
|
71
|
+
const winstonLevel = (info.level || 'info').replace(/\u001b\[\d+m/g, '');
|
|
72
|
+
const mappedLevel = this.levelMap[winstonLevel] || 'info';
|
|
73
|
+
const message = info.message || '';
|
|
74
|
+
// Extract attributes (everything except level, message, and Winston symbols)
|
|
75
|
+
const attributes = {};
|
|
76
|
+
for (const key of Object.keys(info)) {
|
|
77
|
+
if (key !== 'level' && key !== 'message') {
|
|
78
|
+
attributes[key] = info[key];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Lazy require to avoid circular dependency at module load time
|
|
82
|
+
const JA = require('../index').default;
|
|
83
|
+
if (JA && JA.logger) {
|
|
84
|
+
JA.logger.log(mappedLevel, message, attributes);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Never throw from a transport
|
|
89
|
+
}
|
|
90
|
+
callback();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.JustAnalyticsWinstonTransport = JustAnalyticsWinstonTransport;
|
|
94
|
+
// Set up prototype chain to extend TransportStream
|
|
95
|
+
if (TransportStreamBase) {
|
|
96
|
+
// Inherit from TransportStream
|
|
97
|
+
Object.setPrototypeOf(JustAnalyticsWinstonTransport.prototype, TransportStreamBase.prototype);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=winston.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"winston.js","sourceRoot":"","sources":["../../src/integrations/winston.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAIH,6CAA6C;AAC7C,MAAM,iBAAiB,GAA6B;IAClD,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;CACf,CAAC;AAaF,2EAA2E;AAC3E,IAAI,mBAAwB,CAAC;AAC7B,IAAI,CAAC;IACH,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACrD,CAAC;AAAC,MAAM,CAAC;IACP,sEAAsE;IACtE,mBAAmB,GAAG,IAAI,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,MAAa,6BAA6B;IAGxC,YAAY,IAA2C;QACrD,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,6EAA6E;gBAC7E,gDAAgD,CACjD,CAAC;QACJ,CAAC;QAED,8CAA8C;QAC9C,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAErC,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAE,QAAQ;YAC5B,CAAC,CAAC,EAAE,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE;YAC5C,CAAC,CAAC,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,IAAS,EAAE,QAAoB;QACjC,IAAI,CAAC;YACH,gDAAgD;YAChD,MAAM,YAAY,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;YACzE,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC;YAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;YAEnC,6EAA6E;YAC7E,MAAM,UAAU,GAA4B,EAAE,CAAC;YAC/C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;oBACzC,UAAU,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;YAED,gEAAgE;YAChE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;YACvC,IAAI,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;gBACpB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QAED,QAAQ,EAAE,CAAC;IACb,CAAC;CACF;AA7CD,sEA6CC;AAED,mDAAmD;AACnD,IAAI,mBAAmB,EAAE,CAAC;IACxB,+BAA+B;IAC/B,MAAM,CAAC,cAAc,CACnB,6BAA6B,CAAC,SAAS,EACvC,mBAAmB,CAAC,SAAS,CAC9B,CAAC;AACJ,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/node-sdk/src/logger.ts
|
|
3
|
+
* @description Structured logger with automatic trace context correlation.
|
|
4
|
+
*
|
|
5
|
+
* Implements Story 046 - SDK Log Integration
|
|
6
|
+
*
|
|
7
|
+
* The Logger class provides structured logging methods (debug, info, warn, error, fatal)
|
|
8
|
+
* that automatically attach traceId and spanId from the AsyncLocalStorage context.
|
|
9
|
+
* Log entries are buffered in the BatchTransport and flushed periodically to
|
|
10
|
+
* POST /api/ingest/logs.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* JA.logger.info('User logged in', { userId: 'u123', method: 'oauth' });
|
|
15
|
+
* JA.logger.error('Payment failed', { orderId, amount, reason });
|
|
16
|
+
* JA.logger.debug('Cache hit', { key: 'prefs:u123', ttl: 3600 });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* All methods are no-ops when the SDK is not initialized or disabled.
|
|
20
|
+
* All methods are fail-safe (never throw).
|
|
21
|
+
*
|
|
22
|
+
* References:
|
|
23
|
+
* - src/app/api/ingest/logs/route.ts (target endpoint and expected payload format)
|
|
24
|
+
* - Story 045 (Log Ingestion Model and API)
|
|
25
|
+
*/
|
|
26
|
+
import type { BatchTransport } from './transport';
|
|
27
|
+
/**
|
|
28
|
+
* Valid log severity levels matching the POST /api/ingest/logs Zod schema.
|
|
29
|
+
*/
|
|
30
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
31
|
+
/**
|
|
32
|
+
* Serialized log entry payload matching the logEntrySchema in POST /api/ingest/logs.
|
|
33
|
+
*
|
|
34
|
+
* This is the wire format sent to the server. Field names and types match
|
|
35
|
+
* the Zod validation schema in src/app/api/ingest/logs/route.ts exactly.
|
|
36
|
+
*/
|
|
37
|
+
export interface LogPayload {
|
|
38
|
+
/** Log severity level */
|
|
39
|
+
level: LogLevel;
|
|
40
|
+
/** Log message (1-10000 chars, per server Zod schema) */
|
|
41
|
+
message: string;
|
|
42
|
+
/** Service name from SDK init config (1-128 chars) */
|
|
43
|
+
serviceName: string;
|
|
44
|
+
/** ISO 8601 timestamp of when the log was created */
|
|
45
|
+
timestamp: string;
|
|
46
|
+
/** 32-char hex trace ID from AsyncLocalStorage context, or null */
|
|
47
|
+
traceId: string | null;
|
|
48
|
+
/** 16-char hex span ID from AsyncLocalStorage context, or null */
|
|
49
|
+
spanId: string | null;
|
|
50
|
+
/** Arbitrary key-value metadata */
|
|
51
|
+
attributes: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Internal configuration for the Logger instance.
|
|
55
|
+
* Created by JustAnalyticsClient during init().
|
|
56
|
+
*/
|
|
57
|
+
export interface LoggerConfig {
|
|
58
|
+
/** Service name from SDK init config */
|
|
59
|
+
serviceName: string;
|
|
60
|
+
/** BatchTransport reference for enqueuing logs (null when disabled) */
|
|
61
|
+
transport: BatchTransport | null;
|
|
62
|
+
/** Whether debug logging is enabled */
|
|
63
|
+
debug: boolean;
|
|
64
|
+
/** Whether the SDK is enabled */
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
/** Deployment environment (optional, attached as attribute) */
|
|
67
|
+
environment?: string;
|
|
68
|
+
/** Release version (optional, attached as attribute) */
|
|
69
|
+
release?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Logger provides structured logging methods with automatic trace correlation.
|
|
73
|
+
*
|
|
74
|
+
* Log entries are buffered in the BatchTransport and flushed periodically
|
|
75
|
+
* to POST /api/ingest/logs. traceId and spanId are automatically attached
|
|
76
|
+
* from the AsyncLocalStorage context when logging inside a traced scope.
|
|
77
|
+
*
|
|
78
|
+
* All methods are no-ops when the SDK is not initialized or disabled.
|
|
79
|
+
* All methods are fail-safe (never throw).
|
|
80
|
+
*/
|
|
81
|
+
export declare class Logger {
|
|
82
|
+
private readonly _serviceName;
|
|
83
|
+
private readonly _transport;
|
|
84
|
+
private readonly _debug;
|
|
85
|
+
private readonly _enabled;
|
|
86
|
+
private readonly _environment?;
|
|
87
|
+
private readonly _release?;
|
|
88
|
+
constructor(config: LoggerConfig);
|
|
89
|
+
/**
|
|
90
|
+
* Log a debug-level message.
|
|
91
|
+
*
|
|
92
|
+
* @param message - Log message string
|
|
93
|
+
* @param attributes - Optional key-value metadata
|
|
94
|
+
*/
|
|
95
|
+
debug(message: string, attributes?: Record<string, unknown>): void;
|
|
96
|
+
/**
|
|
97
|
+
* Log an info-level message.
|
|
98
|
+
*
|
|
99
|
+
* @param message - Log message string
|
|
100
|
+
* @param attributes - Optional key-value metadata
|
|
101
|
+
*/
|
|
102
|
+
info(message: string, attributes?: Record<string, unknown>): void;
|
|
103
|
+
/**
|
|
104
|
+
* Log a warn-level message.
|
|
105
|
+
*
|
|
106
|
+
* @param message - Log message string
|
|
107
|
+
* @param attributes - Optional key-value metadata
|
|
108
|
+
*/
|
|
109
|
+
warn(message: string, attributes?: Record<string, unknown>): void;
|
|
110
|
+
/**
|
|
111
|
+
* Log an error-level message.
|
|
112
|
+
*
|
|
113
|
+
* @param message - Log message string
|
|
114
|
+
* @param attributes - Optional key-value metadata
|
|
115
|
+
*/
|
|
116
|
+
error(message: string, attributes?: Record<string, unknown>): void;
|
|
117
|
+
/**
|
|
118
|
+
* Log a fatal-level message.
|
|
119
|
+
*
|
|
120
|
+
* @param message - Log message string
|
|
121
|
+
* @param attributes - Optional key-value metadata
|
|
122
|
+
*/
|
|
123
|
+
fatal(message: string, attributes?: Record<string, unknown>): void;
|
|
124
|
+
/**
|
|
125
|
+
* Log a message at the specified level.
|
|
126
|
+
*
|
|
127
|
+
* Generic method for programmatic level selection. All level-specific
|
|
128
|
+
* methods (debug, info, warn, error, fatal) delegate to this.
|
|
129
|
+
*
|
|
130
|
+
* @param level - Log severity level
|
|
131
|
+
* @param message - Log message string
|
|
132
|
+
* @param attributes - Optional key-value metadata
|
|
133
|
+
*/
|
|
134
|
+
log(level: LogLevel, message: string, attributes?: Record<string, unknown>): void;
|
|
135
|
+
/**
|
|
136
|
+
* Internal log method that constructs the LogPayload and enqueues it.
|
|
137
|
+
*
|
|
138
|
+
* Reads traceId and spanId from the AsyncLocalStorage context automatically.
|
|
139
|
+
* Enriches attributes with environment and release if configured.
|
|
140
|
+
*
|
|
141
|
+
* Never throws -- all errors are caught and logged in debug mode.
|
|
142
|
+
*
|
|
143
|
+
* @param level - Log severity level
|
|
144
|
+
* @param message - Log message string
|
|
145
|
+
* @param attributes - Optional key-value metadata
|
|
146
|
+
*/
|
|
147
|
+
private _log;
|
|
148
|
+
}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file packages/node-sdk/src/logger.ts
|
|
4
|
+
* @description Structured logger with automatic trace context correlation.
|
|
5
|
+
*
|
|
6
|
+
* Implements Story 046 - SDK Log Integration
|
|
7
|
+
*
|
|
8
|
+
* The Logger class provides structured logging methods (debug, info, warn, error, fatal)
|
|
9
|
+
* that automatically attach traceId and spanId from the AsyncLocalStorage context.
|
|
10
|
+
* Log entries are buffered in the BatchTransport and flushed periodically to
|
|
11
|
+
* POST /api/ingest/logs.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* JA.logger.info('User logged in', { userId: 'u123', method: 'oauth' });
|
|
16
|
+
* JA.logger.error('Payment failed', { orderId, amount, reason });
|
|
17
|
+
* JA.logger.debug('Cache hit', { key: 'prefs:u123', ttl: 3600 });
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* All methods are no-ops when the SDK is not initialized or disabled.
|
|
21
|
+
* All methods are fail-safe (never throw).
|
|
22
|
+
*
|
|
23
|
+
* References:
|
|
24
|
+
* - src/app/api/ingest/logs/route.ts (target endpoint and expected payload format)
|
|
25
|
+
* - Story 045 (Log Ingestion Model and API)
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.Logger = void 0;
|
|
29
|
+
const context_1 = require("./context");
|
|
30
|
+
/**
|
|
31
|
+
* Logger provides structured logging methods with automatic trace correlation.
|
|
32
|
+
*
|
|
33
|
+
* Log entries are buffered in the BatchTransport and flushed periodically
|
|
34
|
+
* to POST /api/ingest/logs. traceId and spanId are automatically attached
|
|
35
|
+
* from the AsyncLocalStorage context when logging inside a traced scope.
|
|
36
|
+
*
|
|
37
|
+
* All methods are no-ops when the SDK is not initialized or disabled.
|
|
38
|
+
* All methods are fail-safe (never throw).
|
|
39
|
+
*/
|
|
40
|
+
class Logger {
|
|
41
|
+
constructor(config) {
|
|
42
|
+
this._serviceName = config.serviceName;
|
|
43
|
+
this._transport = config.transport;
|
|
44
|
+
this._debug = config.debug;
|
|
45
|
+
this._enabled = config.enabled;
|
|
46
|
+
this._environment = config.environment;
|
|
47
|
+
this._release = config.release;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Log a debug-level message.
|
|
51
|
+
*
|
|
52
|
+
* @param message - Log message string
|
|
53
|
+
* @param attributes - Optional key-value metadata
|
|
54
|
+
*/
|
|
55
|
+
debug(message, attributes) {
|
|
56
|
+
this._log('debug', message, attributes);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Log an info-level message.
|
|
60
|
+
*
|
|
61
|
+
* @param message - Log message string
|
|
62
|
+
* @param attributes - Optional key-value metadata
|
|
63
|
+
*/
|
|
64
|
+
info(message, attributes) {
|
|
65
|
+
this._log('info', message, attributes);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Log a warn-level message.
|
|
69
|
+
*
|
|
70
|
+
* @param message - Log message string
|
|
71
|
+
* @param attributes - Optional key-value metadata
|
|
72
|
+
*/
|
|
73
|
+
warn(message, attributes) {
|
|
74
|
+
this._log('warn', message, attributes);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Log an error-level message.
|
|
78
|
+
*
|
|
79
|
+
* @param message - Log message string
|
|
80
|
+
* @param attributes - Optional key-value metadata
|
|
81
|
+
*/
|
|
82
|
+
error(message, attributes) {
|
|
83
|
+
this._log('error', message, attributes);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Log a fatal-level message.
|
|
87
|
+
*
|
|
88
|
+
* @param message - Log message string
|
|
89
|
+
* @param attributes - Optional key-value metadata
|
|
90
|
+
*/
|
|
91
|
+
fatal(message, attributes) {
|
|
92
|
+
this._log('fatal', message, attributes);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Log a message at the specified level.
|
|
96
|
+
*
|
|
97
|
+
* Generic method for programmatic level selection. All level-specific
|
|
98
|
+
* methods (debug, info, warn, error, fatal) delegate to this.
|
|
99
|
+
*
|
|
100
|
+
* @param level - Log severity level
|
|
101
|
+
* @param message - Log message string
|
|
102
|
+
* @param attributes - Optional key-value metadata
|
|
103
|
+
*/
|
|
104
|
+
log(level, message, attributes) {
|
|
105
|
+
this._log(level, message, attributes);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Internal log method that constructs the LogPayload and enqueues it.
|
|
109
|
+
*
|
|
110
|
+
* Reads traceId and spanId from the AsyncLocalStorage context automatically.
|
|
111
|
+
* Enriches attributes with environment and release if configured.
|
|
112
|
+
*
|
|
113
|
+
* Never throws -- all errors are caught and logged in debug mode.
|
|
114
|
+
*
|
|
115
|
+
* @param level - Log severity level
|
|
116
|
+
* @param message - Log message string
|
|
117
|
+
* @param attributes - Optional key-value metadata
|
|
118
|
+
*/
|
|
119
|
+
_log(level, message, attributes) {
|
|
120
|
+
// No-op if SDK is disabled or no transport
|
|
121
|
+
if (!this._enabled || !this._transport)
|
|
122
|
+
return;
|
|
123
|
+
// Validate message: must be a non-empty string
|
|
124
|
+
if (!message || typeof message !== 'string' || message.length === 0)
|
|
125
|
+
return;
|
|
126
|
+
try {
|
|
127
|
+
// Read trace context from AsyncLocalStorage
|
|
128
|
+
const activeSpan = (0, context_1.getActiveSpan)();
|
|
129
|
+
const traceId = (0, context_1.getActiveTraceId)();
|
|
130
|
+
const spanId = activeSpan?.id ?? null;
|
|
131
|
+
// Build enriched attributes
|
|
132
|
+
const enrichedAttributes = { ...(attributes || {}) };
|
|
133
|
+
if (this._environment) {
|
|
134
|
+
enrichedAttributes['environment'] = this._environment;
|
|
135
|
+
}
|
|
136
|
+
if (this._release) {
|
|
137
|
+
enrichedAttributes['release'] = this._release;
|
|
138
|
+
}
|
|
139
|
+
const payload = {
|
|
140
|
+
level,
|
|
141
|
+
message,
|
|
142
|
+
serviceName: this._serviceName,
|
|
143
|
+
timestamp: new Date().toISOString(),
|
|
144
|
+
traceId: traceId ?? null,
|
|
145
|
+
spanId: spanId ?? null,
|
|
146
|
+
attributes: enrichedAttributes,
|
|
147
|
+
};
|
|
148
|
+
if (this._debug) {
|
|
149
|
+
console.debug(`[JustAnalytics Logger] ${level.toUpperCase()} "${message}" traceId=${traceId || 'none'}`);
|
|
150
|
+
}
|
|
151
|
+
this._transport.enqueueLog(payload);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
if (this._debug) {
|
|
155
|
+
console.debug('[JustAnalytics Logger] Internal error:', err);
|
|
156
|
+
}
|
|
157
|
+
// Never throw from logger methods
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.Logger = Logger;
|
|
162
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAEH,uCAA4D;AAkD5D;;;;;;;;;GASG;AACH,MAAa,MAAM;IAQjB,YAAY,MAAoB;QAC9B,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;IACjC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAe,EAAE,UAAoC;QACzD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAe,EAAE,UAAoC;QACxD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,OAAe,EAAE,UAAoC;QACxD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAe,EAAE,UAAoC;QACzD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAe,EAAE,UAAoC;QACzD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;;;;OASG;IACH,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,UAAoC;QACxE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;;;;;OAWG;IACK,IAAI,CAAC,KAAe,EAAE,OAAe,EAAE,UAAoC;QACjF,2CAA2C;QAC3C,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO;QAE/C,+CAA+C;QAC/C,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE5E,IAAI,CAAC;YACH,4CAA4C;YAC5C,MAAM,UAAU,GAAG,IAAA,uBAAa,GAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAA,0BAAgB,GAAE,CAAC;YACnC,MAAM,MAAM,GAAG,UAAU,EAAE,EAAE,IAAI,IAAI,CAAC;YAEtC,4BAA4B;YAC5B,MAAM,kBAAkB,GAA4B,EAAE,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;YAC9E,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACtB,kBAAkB,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;YACxD,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,kBAAkB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;YAChD,CAAC;YAED,MAAM,OAAO,GAAe;gBAC1B,KAAK;gBACL,OAAO;gBACP,WAAW,EAAE,IAAI,CAAC,YAAY;gBAC9B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,OAAO,EAAE,OAAO,IAAI,IAAI;gBACxB,MAAM,EAAE,MAAM,IAAI,IAAI;gBACtB,UAAU,EAAE,kBAAkB;aAC/B,CAAC;YAEF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CACX,0BAA0B,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,aAAa,OAAO,IAAI,MAAM,EAAE,CAC1F,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;YAC/D,CAAC;YACD,kCAAkC;QACpC,CAAC;IACH,CAAC;CACF;AA3ID,wBA2IC"}
|
package/dist/span.d.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/node-sdk/src/span.ts
|
|
3
|
+
* @description Span class for distributed tracing with high-resolution timing.
|
|
4
|
+
*
|
|
5
|
+
* Implements Story 035 - Node.js SDK Core
|
|
6
|
+
*
|
|
7
|
+
* Each Span records a timed operation within a trace. Spans are created by
|
|
8
|
+
* `JA.startSpan()` and automatically ended when the callback completes.
|
|
9
|
+
* The `toJSON()` method serializes the span to the exact format expected by
|
|
10
|
+
* `POST /api/ingest/spans` (see the Zod schema in route.ts).
|
|
11
|
+
*
|
|
12
|
+
* Timing uses `process.hrtime.bigint()` for nanosecond-resolution monotonic
|
|
13
|
+
* measurement, then converts to integer milliseconds via Math.round.
|
|
14
|
+
*
|
|
15
|
+
* References:
|
|
16
|
+
* - src/app/api/ingest/spans/route.ts (Zod schema the payload must match)
|
|
17
|
+
* - W3C Trace Context (traceId/spanId format)
|
|
18
|
+
*/
|
|
19
|
+
/** Valid span kinds (OpenTelemetry-compatible) */
|
|
20
|
+
export type SpanKind = 'client' | 'server' | 'producer' | 'consumer' | 'internal';
|
|
21
|
+
/** Valid span statuses */
|
|
22
|
+
export type SpanStatus = 'ok' | 'error' | 'unset';
|
|
23
|
+
/** Options for creating a new span via JA.startSpan() */
|
|
24
|
+
export interface SpanOptions {
|
|
25
|
+
/** Span kind (default: 'internal') */
|
|
26
|
+
kind?: SpanKind;
|
|
27
|
+
/** Initial attributes to set on the span */
|
|
28
|
+
attributes?: Record<string, unknown>;
|
|
29
|
+
/** Explicit parent span (overrides AsyncLocalStorage context) */
|
|
30
|
+
parentSpan?: Span;
|
|
31
|
+
}
|
|
32
|
+
/** A timestamped event attached to a span */
|
|
33
|
+
export interface SpanEvent {
|
|
34
|
+
/** Event name */
|
|
35
|
+
name: string;
|
|
36
|
+
/** ISO 8601 timestamp of the event */
|
|
37
|
+
timestamp: string;
|
|
38
|
+
/** Optional event attributes */
|
|
39
|
+
attributes?: Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
/** Serialized span payload matching the /api/ingest/spans Zod schema */
|
|
42
|
+
export interface SpanPayload {
|
|
43
|
+
id: string;
|
|
44
|
+
traceId: string;
|
|
45
|
+
parentSpanId: string | null;
|
|
46
|
+
operationName: string;
|
|
47
|
+
serviceName: string;
|
|
48
|
+
kind: SpanKind;
|
|
49
|
+
startTime: string;
|
|
50
|
+
endTime: string | null;
|
|
51
|
+
duration: number | null;
|
|
52
|
+
status: SpanStatus;
|
|
53
|
+
statusMessage: string | null;
|
|
54
|
+
attributes: Record<string, unknown>;
|
|
55
|
+
events: SpanEvent[];
|
|
56
|
+
}
|
|
57
|
+
/** Parameters for constructing a Span */
|
|
58
|
+
export interface SpanConstructorParams {
|
|
59
|
+
/** Operation/span name (e.g. "POST /api/users", "db.query") */
|
|
60
|
+
operationName: string;
|
|
61
|
+
/** Service that produced this span (e.g. "api-server", "worker") */
|
|
62
|
+
serviceName: string;
|
|
63
|
+
/** Span kind */
|
|
64
|
+
kind: SpanKind;
|
|
65
|
+
/** Trace ID (32-char hex) -- inherited from parent or newly generated */
|
|
66
|
+
traceId: string;
|
|
67
|
+
/** Parent span ID (16-char hex) or null for root spans */
|
|
68
|
+
parentSpanId: string | null;
|
|
69
|
+
/** Initial attributes */
|
|
70
|
+
attributes?: Record<string, unknown>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Span represents a single timed operation within a distributed trace.
|
|
74
|
+
*
|
|
75
|
+
* Spans are created by `JA.startSpan()` and ended either automatically
|
|
76
|
+
* when the callback completes, or manually via `span.end()`.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* JA.startSpan('process-order', (span) => {
|
|
81
|
+
* span.setAttribute('order.id', '12345');
|
|
82
|
+
* span.addEvent('payment.processed');
|
|
83
|
+
* // span.end() is called automatically
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare class Span {
|
|
88
|
+
/** 16-character hex span ID */
|
|
89
|
+
readonly id: string;
|
|
90
|
+
/** 32-character hex trace ID (shared across all spans in a trace) */
|
|
91
|
+
readonly traceId: string;
|
|
92
|
+
/** Parent span ID, or null for root spans */
|
|
93
|
+
readonly parentSpanId: string | null;
|
|
94
|
+
/** Operation name (e.g. "POST /api/users", "db.query") */
|
|
95
|
+
readonly operationName: string;
|
|
96
|
+
/** Service name (e.g. "api-server") */
|
|
97
|
+
readonly serviceName: string;
|
|
98
|
+
/** Span kind */
|
|
99
|
+
readonly kind: SpanKind;
|
|
100
|
+
/** Wall-clock start time */
|
|
101
|
+
readonly startTime: Date;
|
|
102
|
+
/** High-resolution monotonic start time (nanoseconds) for precise duration */
|
|
103
|
+
readonly startHrTime: bigint;
|
|
104
|
+
private _endTime;
|
|
105
|
+
private _duration;
|
|
106
|
+
private _status;
|
|
107
|
+
private _statusMessage;
|
|
108
|
+
private _attributes;
|
|
109
|
+
private _events;
|
|
110
|
+
private _ended;
|
|
111
|
+
constructor(params: SpanConstructorParams);
|
|
112
|
+
/**
|
|
113
|
+
* Set a single attribute on the span.
|
|
114
|
+
*
|
|
115
|
+
* @param key - Attribute key (e.g. "http.method", "db.statement")
|
|
116
|
+
* @param value - Attribute value
|
|
117
|
+
* @returns this (for chaining)
|
|
118
|
+
*/
|
|
119
|
+
setAttribute(key: string, value: unknown): this;
|
|
120
|
+
/**
|
|
121
|
+
* Set multiple attributes on the span.
|
|
122
|
+
*
|
|
123
|
+
* @param attrs - Key-value pairs to merge into attributes
|
|
124
|
+
* @returns this (for chaining)
|
|
125
|
+
*/
|
|
126
|
+
setAttributes(attrs: Record<string, unknown>): this;
|
|
127
|
+
/**
|
|
128
|
+
* Set the span's status.
|
|
129
|
+
*
|
|
130
|
+
* @param status - One of 'ok', 'error', 'unset'
|
|
131
|
+
* @param message - Optional status message (typically for errors)
|
|
132
|
+
* @returns this (for chaining)
|
|
133
|
+
*/
|
|
134
|
+
setStatus(status: SpanStatus, message?: string): this;
|
|
135
|
+
/**
|
|
136
|
+
* Add a timestamped event to the span.
|
|
137
|
+
*
|
|
138
|
+
* Events represent notable moments during the span's lifetime
|
|
139
|
+
* (e.g. "cache.miss", "retry.attempt", "payment.processed").
|
|
140
|
+
*
|
|
141
|
+
* @param name - Event name
|
|
142
|
+
* @param attributes - Optional event attributes
|
|
143
|
+
* @returns this (for chaining)
|
|
144
|
+
*/
|
|
145
|
+
addEvent(name: string, attributes?: Record<string, unknown>): this;
|
|
146
|
+
/**
|
|
147
|
+
* Update the operation name after span creation.
|
|
148
|
+
*
|
|
149
|
+
* Used by auto-instrumentation integrations to refine the operation name
|
|
150
|
+
* after additional context is available (e.g., Express route matching
|
|
151
|
+
* provides `/api/users/:id` instead of the raw URL `/api/users/42`).
|
|
152
|
+
*
|
|
153
|
+
* No-op if the span has already ended.
|
|
154
|
+
*
|
|
155
|
+
* @param name - The new operation name
|
|
156
|
+
* @returns this (for chaining)
|
|
157
|
+
*/
|
|
158
|
+
updateOperationName(name: string): this;
|
|
159
|
+
/**
|
|
160
|
+
* Mark the span as ended.
|
|
161
|
+
*
|
|
162
|
+
* Calculates duration using `process.hrtime.bigint()` for sub-millisecond
|
|
163
|
+
* precision, then rounds to an integer millisecond value to match the
|
|
164
|
+
* server's `z.number().int()` Zod validation.
|
|
165
|
+
*
|
|
166
|
+
* Calling `end()` multiple times is a no-op (idempotent).
|
|
167
|
+
*/
|
|
168
|
+
end(): void;
|
|
169
|
+
/** Whether this span has been ended */
|
|
170
|
+
get isEnded(): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Serialize the span to the JSON payload format expected by
|
|
173
|
+
* `POST /api/ingest/spans`.
|
|
174
|
+
*
|
|
175
|
+
* The output matches the Zod schema defined in
|
|
176
|
+
* `src/app/api/ingest/spans/route.ts` exactly:
|
|
177
|
+
* - `id`: 16-char hex
|
|
178
|
+
* - `traceId`: 32-char hex
|
|
179
|
+
* - `parentSpanId`: 16-char hex or null
|
|
180
|
+
* - `operationName`: string (1-256 chars)
|
|
181
|
+
* - `serviceName`: string (1-128 chars)
|
|
182
|
+
* - `kind`: one of the SpanKind values
|
|
183
|
+
* - `startTime`: ISO 8601 string
|
|
184
|
+
* - `endTime`: ISO 8601 string or null
|
|
185
|
+
* - `duration`: integer milliseconds or null
|
|
186
|
+
* - `status`: one of the SpanStatus values
|
|
187
|
+
* - `statusMessage`: string or null
|
|
188
|
+
* - `attributes`: object
|
|
189
|
+
* - `events`: array of event objects
|
|
190
|
+
*/
|
|
191
|
+
toJSON(): SpanPayload;
|
|
192
|
+
}
|