navis.js 2.0.0 → 3.0.1

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.
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Distributed Tracer
3
+ * v3: Basic distributed tracing support
4
+ */
5
+
6
+ class Tracer {
7
+ constructor(options = {}) {
8
+ this.serviceName = options.serviceName || 'navis-service';
9
+ this.enabled = options.enabled !== false;
10
+ this.spans = new Map();
11
+ this.traceId = null;
12
+ }
13
+
14
+ /**
15
+ * Start a new trace
16
+ * @param {string} operationName - Operation name
17
+ * @param {Object} context - Trace context
18
+ * @returns {string} - Trace ID
19
+ */
20
+ startTrace(operationName, context = {}) {
21
+ if (!this.enabled) return null;
22
+
23
+ const traceId = this._generateId();
24
+ const spanId = this._generateId();
25
+
26
+ this.traceId = traceId;
27
+
28
+ const span = {
29
+ traceId,
30
+ spanId,
31
+ operationName,
32
+ startTime: Date.now(),
33
+ tags: context.tags || {},
34
+ logs: [],
35
+ childSpans: [],
36
+ };
37
+
38
+ this.spans.set(spanId, span);
39
+ return traceId;
40
+ }
41
+
42
+ /**
43
+ * Start a new span
44
+ * @param {string} operationName - Operation name
45
+ * @param {Object} options - Span options
46
+ * @returns {string} - Span ID
47
+ */
48
+ startSpan(operationName, options = {}) {
49
+ if (!this.enabled) return null;
50
+
51
+ const spanId = this._generateId();
52
+ const parentSpanId = options.parentSpanId || this._getCurrentSpanId();
53
+ const traceId = options.traceId || this.traceId || this.startTrace(operationName);
54
+
55
+ const span = {
56
+ traceId,
57
+ spanId,
58
+ parentSpanId,
59
+ operationName,
60
+ startTime: Date.now(),
61
+ tags: options.tags || {},
62
+ logs: [],
63
+ childSpans: [],
64
+ };
65
+
66
+ this.spans.set(spanId, span);
67
+
68
+ // Add as child span if parent exists
69
+ if (parentSpanId) {
70
+ const parentSpan = this.spans.get(parentSpanId);
71
+ if (parentSpan) {
72
+ parentSpan.childSpans.push(spanId);
73
+ }
74
+ }
75
+
76
+ return spanId;
77
+ }
78
+
79
+ /**
80
+ * Finish a span
81
+ * @param {string} spanId - Span ID
82
+ * @param {Object} options - Finish options
83
+ */
84
+ finishSpan(spanId, options = {}) {
85
+ if (!this.enabled || !spanId) return;
86
+
87
+ const span = this.spans.get(spanId);
88
+ if (!span) return;
89
+
90
+ span.endTime = Date.now();
91
+ span.duration = span.endTime - span.startTime;
92
+ span.status = options.status || 'ok';
93
+ span.error = options.error || null;
94
+
95
+ if (options.tags) {
96
+ span.tags = { ...span.tags, ...options.tags };
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Add tag to span
102
+ * @param {string} spanId - Span ID
103
+ * @param {string} key - Tag key
104
+ * @param {*} value - Tag value
105
+ */
106
+ addTag(spanId, key, value) {
107
+ if (!this.enabled || !spanId) return;
108
+
109
+ const span = this.spans.get(spanId);
110
+ if (span) {
111
+ span.tags[key] = value;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Add log to span
117
+ * @param {string} spanId - Span ID
118
+ * @param {string} message - Log message
119
+ * @param {Object} fields - Log fields
120
+ */
121
+ addLog(spanId, message, fields = {}) {
122
+ if (!this.enabled || !spanId) return;
123
+
124
+ const span = this.spans.get(spanId);
125
+ if (span) {
126
+ span.logs.push({
127
+ timestamp: Date.now(),
128
+ message,
129
+ fields,
130
+ });
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Get trace data
136
+ * @param {string} traceId - Trace ID
137
+ * @returns {Object} - Trace data
138
+ */
139
+ getTrace(traceId) {
140
+ const traceSpans = Array.from(this.spans.values()).filter(
141
+ span => span.traceId === traceId
142
+ );
143
+
144
+ return {
145
+ traceId,
146
+ spans: traceSpans,
147
+ duration: traceSpans.length > 0
148
+ ? Math.max(...traceSpans.map(s => s.endTime || Date.now())) -
149
+ Math.min(...traceSpans.map(s => s.startTime))
150
+ : 0,
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Get all traces
156
+ * @returns {Array} - All traces
157
+ */
158
+ getAllTraces() {
159
+ const traceIds = new Set();
160
+ for (const span of this.spans.values()) {
161
+ traceIds.add(span.traceId);
162
+ }
163
+
164
+ return Array.from(traceIds).map(traceId => this.getTrace(traceId));
165
+ }
166
+
167
+ /**
168
+ * Clear old spans (keep last N)
169
+ * @param {number} keepCount - Number of spans to keep
170
+ */
171
+ clearOldSpans(keepCount = 1000) {
172
+ const spans = Array.from(this.spans.entries());
173
+ if (spans.length > keepCount) {
174
+ // Sort by start time and keep most recent
175
+ spans.sort((a, b) => b[1].startTime - a[1].startTime);
176
+ const toKeep = spans.slice(0, keepCount);
177
+ this.spans.clear();
178
+ for (const [id, span] of toKeep) {
179
+ this.spans.set(id, span);
180
+ }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Get current span ID
186
+ * @private
187
+ */
188
+ _getCurrentSpanId() {
189
+ // Return the most recently created span
190
+ const spans = Array.from(this.spans.values());
191
+ if (spans.length === 0) return null;
192
+ return spans[spans.length - 1].spanId;
193
+ }
194
+
195
+ /**
196
+ * Generate unique ID
197
+ * @private
198
+ */
199
+ _generateId() {
200
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
201
+ }
202
+ }
203
+
204
+ module.exports = Tracer;
205
+