@platformatic/itc 3.53.0-alpha.0 → 3.53.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/lib/index.d.ts +43 -0
- package/lib/index.js +19 -6
- package/lib/telemetry.js +220 -0
- package/package.json +2 -1
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Context } from '@opentelemetry/api'
|
|
1
2
|
import { EventEmitter } from 'node:events'
|
|
2
3
|
import { MessagePort } from 'node:worker_threads'
|
|
3
4
|
|
|
@@ -10,6 +11,22 @@ export interface ITCConstructorOptions {
|
|
|
10
11
|
throwOnMissingHandler?: boolean
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
export interface OutgoingMessagingSpanOptions {
|
|
15
|
+
telemetryContext?: Context
|
|
16
|
+
telemetryMetadata?: Record<string, string>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface OutgoingMessagingSpan {
|
|
20
|
+
meta: {
|
|
21
|
+
mode: string
|
|
22
|
+
sourceApplication?: string
|
|
23
|
+
targetApplication?: string
|
|
24
|
+
telemetry: Record<string, string>
|
|
25
|
+
} | null
|
|
26
|
+
run<T>(callback: () => T): T
|
|
27
|
+
end(error?: Error | null): void
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
export class ITC extends EventEmitter {
|
|
14
31
|
constructor (options: ITCConstructorOptions)
|
|
15
32
|
|
|
@@ -20,3 +37,29 @@ export class ITC extends EventEmitter {
|
|
|
20
37
|
listen (): void
|
|
21
38
|
close (): void
|
|
22
39
|
}
|
|
40
|
+
|
|
41
|
+
export function initializeITCTelemetry (): Promise<any>
|
|
42
|
+
|
|
43
|
+
export function startOutgoingMessagingSpan (
|
|
44
|
+
mode: string,
|
|
45
|
+
sourceApplication: string,
|
|
46
|
+
targetApplication: string,
|
|
47
|
+
messageName: string,
|
|
48
|
+
options?: OutgoingMessagingSpanOptions
|
|
49
|
+
): OutgoingMessagingSpan | null
|
|
50
|
+
|
|
51
|
+
export function startOutgoingMessagingSpanSync (
|
|
52
|
+
mode: string,
|
|
53
|
+
sourceApplication: string,
|
|
54
|
+
targetApplication: string,
|
|
55
|
+
messageName: string,
|
|
56
|
+
options?: OutgoingMessagingSpanOptions
|
|
57
|
+
): OutgoingMessagingSpan | null
|
|
58
|
+
|
|
59
|
+
export function traceIncomingMessagingHandler (
|
|
60
|
+
applicationId: string,
|
|
61
|
+
messageName: string,
|
|
62
|
+
handler: Handler,
|
|
63
|
+
data: any,
|
|
64
|
+
handlerContext?: Record<string, any>
|
|
65
|
+
): any
|
package/lib/index.js
CHANGED
|
@@ -49,18 +49,24 @@ export function parseResponse (response) {
|
|
|
49
49
|
return response
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export function generateRequest (name, data) {
|
|
52
|
+
export function generateRequest (name, data, meta) {
|
|
53
53
|
if (typeof name !== 'string') {
|
|
54
54
|
throw new RequestNameIsNotString(name.toString())
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
const request = {
|
|
58
58
|
type: PLT_ITC_REQUEST_TYPE,
|
|
59
59
|
version: PLT_ITC_VERSION,
|
|
60
60
|
reqId: randomUUID(),
|
|
61
61
|
name,
|
|
62
62
|
data
|
|
63
63
|
}
|
|
64
|
+
|
|
65
|
+
if (typeof meta !== 'undefined') {
|
|
66
|
+
request.meta = meta
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return request
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
export function generateResponse (request, error, data) {
|
|
@@ -74,13 +80,19 @@ export function generateResponse (request, error, data) {
|
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
82
|
|
|
77
|
-
export function generateNotification (name, data) {
|
|
78
|
-
|
|
83
|
+
export function generateNotification (name, data, meta) {
|
|
84
|
+
const notification = {
|
|
79
85
|
type: PLT_ITC_NOTIFICATION_TYPE,
|
|
80
86
|
version: PLT_ITC_VERSION,
|
|
81
87
|
name,
|
|
82
88
|
data
|
|
83
89
|
}
|
|
90
|
+
|
|
91
|
+
if (typeof meta !== 'undefined') {
|
|
92
|
+
notification.meta = meta
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return notification
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
export function generateUnhandledErrorResponse (error) {
|
|
@@ -298,7 +310,7 @@ export class ITC extends EventEmitter {
|
|
|
298
310
|
try {
|
|
299
311
|
this._enableKeepAlive()
|
|
300
312
|
|
|
301
|
-
const request = generateRequest(name, message)
|
|
313
|
+
const request = generateRequest(name, message, options?.meta)
|
|
302
314
|
this._send(request, options)
|
|
303
315
|
|
|
304
316
|
const promiseWithResolvers = Promise.withResolvers()
|
|
@@ -317,7 +329,7 @@ export class ITC extends EventEmitter {
|
|
|
317
329
|
}
|
|
318
330
|
|
|
319
331
|
notify (name, message, options) {
|
|
320
|
-
this._send(generateNotification(name, message), options)
|
|
332
|
+
this._send(generateNotification(name, message, options?.meta), options)
|
|
321
333
|
}
|
|
322
334
|
|
|
323
335
|
handle (message, handler) {
|
|
@@ -471,3 +483,4 @@ export class ITC extends EventEmitter {
|
|
|
471
483
|
}
|
|
472
484
|
|
|
473
485
|
export * as errors from './errors.js'
|
|
486
|
+
export * from './telemetry.js'
|
package/lib/telemetry.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { ROOT_CONTEXT, SpanKind, SpanStatusCode, context, propagation, trace } from '@opentelemetry/api'
|
|
2
|
+
|
|
3
|
+
let tracer = null
|
|
4
|
+
let telemetryInitialization = null
|
|
5
|
+
|
|
6
|
+
function createMessagingSpanName (type, application, messageName) {
|
|
7
|
+
return `ITC ${type} ${application}.${messageName}`
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function createMessagingAttributes ({ mode, sourceApplication, targetApplication, messageName }) {
|
|
11
|
+
const attributes = {
|
|
12
|
+
'messaging.system': 'platformatic-itc',
|
|
13
|
+
'messaging.operation': mode,
|
|
14
|
+
'messaging.message.name': messageName
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (targetApplication) {
|
|
18
|
+
attributes['messaging.destination.name'] = targetApplication
|
|
19
|
+
attributes['platformatic.messaging.target'] = targetApplication
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (sourceApplication) {
|
|
23
|
+
attributes['platformatic.messaging.source'] = sourceApplication
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return attributes
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createOutgoingMessagingMeta (mode, sourceApplication, targetApplication, telemetryMetadata) {
|
|
30
|
+
if (!telemetryMetadata || Object.keys(telemetryMetadata).length === 0) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
mode,
|
|
36
|
+
sourceApplication,
|
|
37
|
+
targetApplication,
|
|
38
|
+
telemetry: telemetryMetadata
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setSpanError (span, error) {
|
|
43
|
+
span.setAttributes({
|
|
44
|
+
'error.name': error.name,
|
|
45
|
+
'error.message': error.message,
|
|
46
|
+
'error.stack': error.stack
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
span.setStatus({
|
|
50
|
+
code: SpanStatusCode.ERROR,
|
|
51
|
+
message: error.message
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function endSpan (span, error) {
|
|
56
|
+
if (error) {
|
|
57
|
+
setSpanError(span, error)
|
|
58
|
+
} else {
|
|
59
|
+
span.setStatus({ code: SpanStatusCode.OK })
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
span.end()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getTracer () {
|
|
66
|
+
if (tracer) {
|
|
67
|
+
return tracer
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const tracerProvider = globalThis.platformatic?.tracerProvider
|
|
71
|
+
if (!tracerProvider) {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
tracer = tracerProvider.getTracer('@platformatic/itc')
|
|
76
|
+
return tracer
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function initializeITCTelemetry () {
|
|
80
|
+
if (telemetryInitialization) {
|
|
81
|
+
return telemetryInitialization
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
telemetryInitialization = Promise.resolve(globalThis.platformatic?.telemetryReady)
|
|
85
|
+
.catch(() => {
|
|
86
|
+
// Ignore telemetry initialization failures and fall back to untraced messaging.
|
|
87
|
+
})
|
|
88
|
+
.then(() => getTracer())
|
|
89
|
+
|
|
90
|
+
return telemetryInitialization
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function createNoopOutgoingTelemetry (mode, sourceApplication, targetApplication, telemetryMetadata) {
|
|
94
|
+
const meta = createOutgoingMessagingMeta(mode, sourceApplication, targetApplication, telemetryMetadata)
|
|
95
|
+
|
|
96
|
+
if (!meta) {
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
meta,
|
|
102
|
+
run (callback) {
|
|
103
|
+
return callback()
|
|
104
|
+
},
|
|
105
|
+
end () {}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getParentContext (telemetryContext, telemetryMetadata) {
|
|
110
|
+
if (telemetryContext) {
|
|
111
|
+
return telemetryContext
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (telemetryMetadata && Object.keys(telemetryMetadata).length > 0) {
|
|
115
|
+
return propagation.extract(ROOT_CONTEXT, telemetryMetadata)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return context.active()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function createOutgoingMessagingSpan (tracer, mode, sourceApplication, targetApplication, messageName, options = {}) {
|
|
122
|
+
const parentContext = getParentContext(options.telemetryContext, options.telemetryMetadata)
|
|
123
|
+
const spanType = mode === 'notify' ? 'notify' : 'send'
|
|
124
|
+
const spanKind = mode === 'notify' ? SpanKind.PRODUCER : SpanKind.CLIENT
|
|
125
|
+
const span = tracer.startSpan(
|
|
126
|
+
createMessagingSpanName(spanType, targetApplication, messageName),
|
|
127
|
+
{
|
|
128
|
+
kind: spanKind,
|
|
129
|
+
attributes: createMessagingAttributes({
|
|
130
|
+
mode,
|
|
131
|
+
sourceApplication,
|
|
132
|
+
targetApplication,
|
|
133
|
+
messageName
|
|
134
|
+
})
|
|
135
|
+
},
|
|
136
|
+
parentContext
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
const spanContext = trace.setSpan(parentContext, span)
|
|
140
|
+
const telemetryMetadata = {}
|
|
141
|
+
propagation.inject(spanContext, telemetryMetadata)
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
meta: createOutgoingMessagingMeta(mode, sourceApplication, targetApplication, telemetryMetadata),
|
|
145
|
+
run (callback) {
|
|
146
|
+
return context.with(spanContext, callback)
|
|
147
|
+
},
|
|
148
|
+
end (error) {
|
|
149
|
+
endSpan(span, error)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function startOutgoingMessagingSpan (mode, sourceApplication, targetApplication, messageName, options = {}) {
|
|
155
|
+
const activeTracer = getTracer()
|
|
156
|
+
if (!activeTracer) {
|
|
157
|
+
return createNoopOutgoingTelemetry(mode, sourceApplication, targetApplication, options.telemetryMetadata)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return createOutgoingMessagingSpan(activeTracer, mode, sourceApplication, targetApplication, messageName, options)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function startOutgoingMessagingSpanSync (mode, sourceApplication, targetApplication, messageName, options = {}) {
|
|
164
|
+
return startOutgoingMessagingSpan(mode, sourceApplication, targetApplication, messageName, options)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function traceIncomingMessagingHandler (applicationId, messageName, handler, data, handlerContext = {}) {
|
|
168
|
+
const activeTracer = getTracer()
|
|
169
|
+
if (!activeTracer) {
|
|
170
|
+
return handler(data, handlerContext)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const request = handlerContext.message ?? {}
|
|
174
|
+
const metadata = request.meta ?? {}
|
|
175
|
+
const mode = handlerContext.notification ? 'notify' : metadata.mode ?? 'send'
|
|
176
|
+
const sourceApplication = metadata.sourceApplication
|
|
177
|
+
const telemetryCarrier = metadata.telemetry ?? {}
|
|
178
|
+
const parentContext = propagation.extract(ROOT_CONTEXT, telemetryCarrier)
|
|
179
|
+
const spanType = handlerContext.notification ? 'consume' : 'handle'
|
|
180
|
+
const spanKind = handlerContext.notification ? SpanKind.CONSUMER : SpanKind.SERVER
|
|
181
|
+
const span = activeTracer.startSpan(
|
|
182
|
+
createMessagingSpanName(spanType, sourceApplication ?? 'unknown', messageName),
|
|
183
|
+
{
|
|
184
|
+
kind: spanKind,
|
|
185
|
+
attributes: createMessagingAttributes({
|
|
186
|
+
mode,
|
|
187
|
+
sourceApplication,
|
|
188
|
+
targetApplication: applicationId,
|
|
189
|
+
messageName
|
|
190
|
+
})
|
|
191
|
+
},
|
|
192
|
+
parentContext
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
const spanContext = trace.setSpan(parentContext, span)
|
|
196
|
+
let result
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
result = context.with(spanContext, () => handler(data, handlerContext))
|
|
200
|
+
} catch (error) {
|
|
201
|
+
endSpan(span, error)
|
|
202
|
+
throw error
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (result?.then) {
|
|
206
|
+
return result.then(
|
|
207
|
+
value => {
|
|
208
|
+
endSpan(span)
|
|
209
|
+
return value
|
|
210
|
+
},
|
|
211
|
+
error => {
|
|
212
|
+
endSpan(span, error)
|
|
213
|
+
throw error
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
endSpan(span)
|
|
219
|
+
return result
|
|
220
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/itc",
|
|
3
|
-
"version": "3.53.0
|
|
3
|
+
"version": "3.53.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@fastify/error": "^4.0.0",
|
|
28
|
+
"@opentelemetry/api": "^1.9.0",
|
|
28
29
|
"@watchable/unpromise": "^1.0.2"
|
|
29
30
|
},
|
|
30
31
|
"engines": {
|