@aidra/pmx-io 0.0.0-stage → 9.13.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/README.md +69 -2
- package/bin/pmx-io-node.js +143 -0
- package/index.d.ts +381 -0
- package/index.js +27 -0
- package/index.mjs +47 -0
- package/lib/actions.js +120 -0
- package/lib/activate.js +402 -0
- package/lib/application.js +106 -0
- package/lib/bun.js +155 -0
- package/lib/config.js +67 -0
- package/lib/constants.js +17 -0
- package/lib/debug.js +48 -0
- package/lib/esm-hooks.mjs +111 -0
- package/lib/exit.js +79 -0
- package/lib/features/metrics.js +409 -0
- package/lib/features/notify.js +358 -0
- package/lib/features/profiling.js +208 -0
- package/lib/hooks.js +151 -0
- package/lib/inbound.js +174 -0
- package/lib/integrations.js +372 -0
- package/lib/itg/amqplib.js +169 -0
- package/lib/itg/bullmq.js +141 -0
- package/lib/itg/common.js +657 -0
- package/lib/itg/dbcomment.js +114 -0
- package/lib/itg/index.js +103 -0
- package/lib/itg/ioredis.js +212 -0
- package/lib/itg/kafkajs.js +205 -0
- package/lib/itg/mongodb.js +322 -0
- package/lib/itg/mysql2.js +205 -0
- package/lib/itg/nats.js +531 -0
- package/lib/itg/noderedis.js +236 -0
- package/lib/itg/pg.js +253 -0
- package/lib/itg/pgqueue.js +305 -0
- package/lib/itg/postgres.js +252 -0
- package/lib/itg/redis-common.js +265 -0
- package/lib/itg/sql.js +302 -0
- package/lib/metrics/service.js +286 -0
- package/lib/metrics/types.js +342 -0
- package/lib/modules.js +260 -0
- package/lib/node-options.js +62 -0
- package/lib/otel/bridge.js +797 -0
- package/lib/otel/env.js +114 -0
- package/lib/outbound.js +362 -0
- package/lib/pmx.js +757 -0
- package/lib/relay/hub.js +279 -0
- package/lib/relay/transport.js +253 -0
- package/lib/standalone/activate.js +307 -0
- package/lib/standalone/capture.js +55 -0
- package/lib/standalone/container.js +909 -0
- package/lib/standalone/transport.js +1023 -0
- package/lib/tracing/context.js +90 -0
- package/lib/tracing/control.js +124 -0
- package/lib/tracing/exporter.js +115 -0
- package/lib/tracing/index.js +242 -0
- package/lib/tracing/logs.js +176 -0
- package/lib/tracing/options.js +105 -0
- package/lib/tracing/paths.js +34 -0
- package/lib/tracing/tracer.js +850 -0
- package/lib/tracing/w3c.js +415 -0
- package/lib/transport/ipc.js +97 -0
- package/lib/transport/ws.js +511 -0
- package/lib/util.js +109 -0
- package/package.json +48 -4
- package/preload.cjs +26 -0
- package/preload.mjs +25 -0
- package/standalone.cjs +16 -0
- package/standalone.mjs +17 -0
package/lib/itg/nats.js
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
// Copyright (c) 2026 Mike Warriner. All rights reserved. Proprietary — see LICENSE.
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
// NATS and JetStream (82 §9 ITG-202, ITG-203; common rules §4) for `nats` 2.x and the 3.x modular
|
|
5
|
+
// packages (`@nats-io/nats-core`, `@nats-io/jetstream`, through `@nats-io/transport-node`).
|
|
6
|
+
// * NatsConnectionImpl.publish → PRODUCER `publish <subject>`, trace headers in a copy of
|
|
7
|
+
// `options.headers` (a new headers object from the library's own `headers()` factory);
|
|
8
|
+
// request → CLIENT `request <subject>` until the reply (or the timeout, ERROR); requestMany →
|
|
9
|
+
// CLIENT span until the returned iterator is obtained.
|
|
10
|
+
// * subscribe(subject, { callback }) → callback style; a subscription iterated with `for await`
|
|
11
|
+
// → iterator style (QueuedIteratorImpl's async iterator, for subscriptions marked here).
|
|
12
|
+
// * JetStream: JetStreamClientImpl.publish → PRODUCER covering the ack (`messaging.message.id` =
|
|
13
|
+
// the ack's `seq`, `messaging.nats.stream`); consumers' `consume()` → iterator style, or
|
|
14
|
+
// callback style with `consume({ callback })`;
|
|
15
|
+
// `fetch()` → batch pull (`receive <subject>` from the call until the fetch iterator ends,
|
|
16
|
+
// one link per message); `next()` → batch pull of one.
|
|
17
|
+
// Subjects of the protocol itself (`$JS.`, `$KV.`, `$O.`, `$SYS.`, `_INBOX.`: JetStream API calls,
|
|
18
|
+
// acknowledgements, flow control, replies) make no span, like pmx-io.
|
|
19
|
+
|
|
20
|
+
const path = require('path')
|
|
21
|
+
const c = require('./common')
|
|
22
|
+
const ctx = require('../tracing/context')
|
|
23
|
+
|
|
24
|
+
const SYSTEM = 'nats'
|
|
25
|
+
const META = Symbol('pmx-nats-iter')
|
|
26
|
+
const factories = new Map() // package dir → headers()
|
|
27
|
+
|
|
28
|
+
function internal (subject) {
|
|
29
|
+
return typeof subject !== 'string' || /^(\$JS\.|\$KV\.|\$O\.|\$SYS\.|_INBOX\.)/.test(subject)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function peer (nc) {
|
|
33
|
+
const tags = {}
|
|
34
|
+
try {
|
|
35
|
+
const s = typeof nc.getServer === 'function' ? nc.getServer() : ''
|
|
36
|
+
if (s) {
|
|
37
|
+
const i = s.lastIndexOf(':')
|
|
38
|
+
if (i > 0) {
|
|
39
|
+
tags['net.peer.name'] = s.slice(0, i).replace(/^\[|\]$/g, '')
|
|
40
|
+
tags['net.peer.port'] = s.slice(i + 1)
|
|
41
|
+
} else tags['net.peer.name'] = s
|
|
42
|
+
}
|
|
43
|
+
} catch (_) {}
|
|
44
|
+
return tags
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function hdrsObject (h) {
|
|
48
|
+
if (!h) return null
|
|
49
|
+
const o = {}
|
|
50
|
+
try {
|
|
51
|
+
if (typeof h[Symbol.iterator] === 'function') {
|
|
52
|
+
for (const [k, v] of h) o[String(k).toLowerCase()] = Array.isArray(v) ? v[0] : v
|
|
53
|
+
return o
|
|
54
|
+
}
|
|
55
|
+
if (typeof h.keys === 'function' && typeof h.get === 'function') {
|
|
56
|
+
for (const k of h.keys()) o[String(k).toLowerCase()] = h.get(k)
|
|
57
|
+
return o
|
|
58
|
+
}
|
|
59
|
+
} catch (_) {}
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function extractMsg (msg) {
|
|
64
|
+
try {
|
|
65
|
+
const o = hdrsObject(msg && msg.headers)
|
|
66
|
+
return o ? c.extract(o) : null
|
|
67
|
+
} catch (_) {
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function supportsHeaders (nc) {
|
|
73
|
+
try {
|
|
74
|
+
const info = nc && nc.info
|
|
75
|
+
return !(info && info.headers === false)
|
|
76
|
+
} catch (_) {
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A copy of `options` whose `headers` (a new headers object) carries the trace headers. */
|
|
82
|
+
function withTrace (options, span, factory, nc) {
|
|
83
|
+
if (!span) return options
|
|
84
|
+
if (!factory || !supportsHeaders(nc)) {
|
|
85
|
+
span.setAttribute('messaging.pmx.propagation', 'unsupported')
|
|
86
|
+
return options
|
|
87
|
+
}
|
|
88
|
+
const out = Object.assign({}, options || {})
|
|
89
|
+
const h = factory()
|
|
90
|
+
const present = new Set()
|
|
91
|
+
const src = out.headers
|
|
92
|
+
try {
|
|
93
|
+
if (src && typeof src[Symbol.iterator] === 'function') {
|
|
94
|
+
for (const [k, vs] of src) {
|
|
95
|
+
present.add(String(k).toLowerCase())
|
|
96
|
+
for (const v of (Array.isArray(vs) ? vs : [vs])) h.append(k, v)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (_) {}
|
|
100
|
+
for (const [k, v] of c.traceHeaders(span)) if (!present.has(k)) h.append(k, v)
|
|
101
|
+
out.headers = h
|
|
102
|
+
return out
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function bodySize (data) {
|
|
106
|
+
return c.bodySize(data)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// -- core connection --------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
function wrapPublish (factory) {
|
|
112
|
+
return (orig) => function publish (subject, data, options) {
|
|
113
|
+
if (!c.msgTracer() || internal(subject) || c.nested() || nestedHere()) return orig.apply(this, arguments)
|
|
114
|
+
const tags = Object.assign({}, peer(this))
|
|
115
|
+
const size = bodySize(data)
|
|
116
|
+
if (size !== undefined) tags['messaging.message.body.size'] = String(size)
|
|
117
|
+
const span = c.producer(SYSTEM, subject, tags)
|
|
118
|
+
if (!span) return orig.apply(this, arguments)
|
|
119
|
+
let opts = options
|
|
120
|
+
try {
|
|
121
|
+
opts = withTrace(options, span, factory, this)
|
|
122
|
+
} catch (_) {}
|
|
123
|
+
try {
|
|
124
|
+
const r = c.outer(orig, this, [subject, data, opts])
|
|
125
|
+
c.end(span)
|
|
126
|
+
return r
|
|
127
|
+
} catch (err) {
|
|
128
|
+
c.end(span, err)
|
|
129
|
+
throw err
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function wrapRequest (factory, many) {
|
|
135
|
+
return (orig) => function request (subject, data, opts) {
|
|
136
|
+
if (!c.msgTracer() || internal(subject) || c.nested() || nestedHere()) return orig.apply(this, arguments)
|
|
137
|
+
const tags = Object.assign({}, peer(this))
|
|
138
|
+
const size = bodySize(data)
|
|
139
|
+
if (size !== undefined) tags['messaging.message.body.size'] = String(size)
|
|
140
|
+
const span = c.producer(SYSTEM, subject, tags, 'CLIENT', 'request')
|
|
141
|
+
if (!span) return orig.apply(this, arguments)
|
|
142
|
+
const args = Array.prototype.slice.call(arguments)
|
|
143
|
+
try {
|
|
144
|
+
args[2] = withTrace(opts, span, factory, this)
|
|
145
|
+
if (args.length < 3) args.length = 3
|
|
146
|
+
} catch (_) {}
|
|
147
|
+
let p
|
|
148
|
+
try {
|
|
149
|
+
p = c.outer(orig, this, args)
|
|
150
|
+
} catch (err) {
|
|
151
|
+
c.end(span, err)
|
|
152
|
+
throw err
|
|
153
|
+
}
|
|
154
|
+
if (c.isThenable(p)) return c.settle(p, span)
|
|
155
|
+
c.end(span)
|
|
156
|
+
return p
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function wrapSubscribe (orig) {
|
|
161
|
+
return function subscribe (subject, opts) {
|
|
162
|
+
if (!c.msgTracer() || internal(subject)) return orig.apply(this, arguments)
|
|
163
|
+
const nc = this
|
|
164
|
+
const o = opts && typeof opts === 'object' ? opts : {}
|
|
165
|
+
const group = typeof o.queue === 'string' && o.queue ? o.queue : undefined
|
|
166
|
+
if (typeof o.callback === 'function') {
|
|
167
|
+
const cb = o.callback
|
|
168
|
+
const copy = Object.assign({}, o, {
|
|
169
|
+
callback: function (err, msg) {
|
|
170
|
+
if (err || !msg || !c.msgTracer()) return cb.apply(this, arguments)
|
|
171
|
+
const span = consumerSpan(nc, msg, group)
|
|
172
|
+
return c.runConsumer(span, cb, this, arguments)
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
return orig.call(this, subject, copy)
|
|
176
|
+
}
|
|
177
|
+
const sub = orig.apply(this, arguments)
|
|
178
|
+
mark(sub, { mode: 'iterator', nc, group })
|
|
179
|
+
return sub
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function consumerSpan (nc, msg, group, extra) {
|
|
184
|
+
const tags = Object.assign({}, peer(nc), extra || {})
|
|
185
|
+
if (group) tags['messaging.consumer.group.name'] = group
|
|
186
|
+
const size = bodySize(msg && msg.data)
|
|
187
|
+
if (size !== undefined) tags['messaging.message.body.size'] = String(size)
|
|
188
|
+
return c.consumer(SYSTEM, msg && msg.subject, extractMsg(msg), tags)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// -- JetStream --------------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
// JetStream publish runs nc.request asynchronously: a store flag suppresses that inner span
|
|
194
|
+
function nestedHere () {
|
|
195
|
+
const s = ctx.current()
|
|
196
|
+
return Boolean(s && s.itg === SYSTEM)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function wrapJsPublish (factory) {
|
|
200
|
+
return (orig) => function publish (subject, data, opts) {
|
|
201
|
+
if (!c.msgTracer() || internal(subject) || c.nested() || nestedHere()) return orig.apply(this, arguments)
|
|
202
|
+
const nc = this.nc
|
|
203
|
+
const tags = Object.assign({}, nc ? peer(nc) : {})
|
|
204
|
+
const size = bodySize(data)
|
|
205
|
+
if (size !== undefined) tags['messaging.message.body.size'] = String(size)
|
|
206
|
+
const span = c.producer(SYSTEM, subject, tags)
|
|
207
|
+
if (!span) return orig.apply(this, arguments)
|
|
208
|
+
const args = Array.prototype.slice.call(arguments)
|
|
209
|
+
try {
|
|
210
|
+
args[2] = withTrace(opts, span, factory, nc)
|
|
211
|
+
if (args.length < 3) args.length = 3
|
|
212
|
+
} catch (_) {}
|
|
213
|
+
let p
|
|
214
|
+
try {
|
|
215
|
+
const store = ctx.current()
|
|
216
|
+
p = ctx.run({ span, bag: span.bag, server: store && store.server, itg: SYSTEM }, orig, this, args)
|
|
217
|
+
} catch (err) {
|
|
218
|
+
c.end(span, err)
|
|
219
|
+
throw err
|
|
220
|
+
}
|
|
221
|
+
if (!c.isThenable(p)) {
|
|
222
|
+
c.end(span)
|
|
223
|
+
return p
|
|
224
|
+
}
|
|
225
|
+
return c.settle(p, span, (ack) => {
|
|
226
|
+
if (ack && ack.seq !== undefined) span.setAttribute('messaging.message.id', String(ack.seq))
|
|
227
|
+
if (ack && ack.stream) span.setAttribute('messaging.nats.stream', String(ack.stream))
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function consumerName (consumer) {
|
|
233
|
+
try {
|
|
234
|
+
return consumer.name || (consumer._info && consumer._info.name) || undefined
|
|
235
|
+
} catch (_) {
|
|
236
|
+
return undefined
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function jsTags (msg) {
|
|
241
|
+
const tags = {}
|
|
242
|
+
try {
|
|
243
|
+
const info = msg && msg.info
|
|
244
|
+
if (info && info.stream) tags['messaging.nats.stream'] = String(info.stream)
|
|
245
|
+
if (msg && msg.seq !== undefined) tags['messaging.message.id'] = String(msg.seq)
|
|
246
|
+
} catch (_) {}
|
|
247
|
+
return tags
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// nats 2.x ordered consumers deliver through an internal callback given to an inner consume():
|
|
251
|
+
// those callbacks are marked and not traced (the app's callback or iterator is)
|
|
252
|
+
const INTERNAL = Symbol('pmx-nats-internal')
|
|
253
|
+
|
|
254
|
+
function wrapInternalHandler (orig) {
|
|
255
|
+
return function internalHandler () {
|
|
256
|
+
const fn = orig.apply(this, arguments)
|
|
257
|
+
if (typeof fn === 'function') {
|
|
258
|
+
try {
|
|
259
|
+
Object.defineProperty(fn, INTERNAL, { value: true })
|
|
260
|
+
} catch (_) {}
|
|
261
|
+
}
|
|
262
|
+
return fn
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** consume({ callback }): callback style, one CONSUMER span per message (ITG-023). */
|
|
267
|
+
function tracedCallback (cb, meta) {
|
|
268
|
+
const w = function (m) {
|
|
269
|
+
if (!m || !c.msgTracer()) return cb.apply(this, arguments)
|
|
270
|
+
const span = consumerSpan(meta.nc, m, meta.group, jsTags(m))
|
|
271
|
+
return c.runConsumer(span, cb, this, arguments)
|
|
272
|
+
}
|
|
273
|
+
return c.copyMeta(w, cb)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function wrapConsume (orig) {
|
|
277
|
+
return function consume (opts) {
|
|
278
|
+
if (c.msgTracer() && opts && typeof opts === 'object' && typeof opts.callback === 'function' && !opts.callback[INTERNAL]) {
|
|
279
|
+
const meta = { nc: this.api && this.api.nc, group: consumerName(this) }
|
|
280
|
+
const args = Array.prototype.slice.call(arguments)
|
|
281
|
+
args[0] = Object.assign({}, opts, { callback: tracedCallback(opts.callback, meta) })
|
|
282
|
+
return orig.apply(this, args)
|
|
283
|
+
}
|
|
284
|
+
const p = orig.apply(this, arguments)
|
|
285
|
+
if (!c.msgTracer()) return p
|
|
286
|
+
const meta = { mode: 'iterator', nc: this.api && this.api.nc, group: consumerName(this), js: true }
|
|
287
|
+
if (c.isThenable(p)) return p.then((it) => { mark(it, meta); return it })
|
|
288
|
+
mark(p, meta)
|
|
289
|
+
return p
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function wrapFetch (orig) {
|
|
294
|
+
return function fetch () {
|
|
295
|
+
if (!c.msgTracer() || c.nested()) return orig.apply(this, arguments)
|
|
296
|
+
const meta = { mode: 'fetch', nc: this.api && this.api.nc, group: consumerName(this), js: true }
|
|
297
|
+
const tags = Object.assign({}, meta.nc ? peer(meta.nc) : {})
|
|
298
|
+
if (meta.group) tags['messaging.consumer.group.name'] = meta.group
|
|
299
|
+
// created at the call (parent: the current span), kept only when messages came back
|
|
300
|
+
meta.span = c.batchConsumer(SYSTEM, undefined, null, tags, 'receive')
|
|
301
|
+
const p = orig.apply(this, arguments)
|
|
302
|
+
if (c.isThenable(p)) return p.then((it) => { mark(it, meta); return it })
|
|
303
|
+
mark(p, meta)
|
|
304
|
+
return p
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function wrapNext (orig) {
|
|
309
|
+
return function next () {
|
|
310
|
+
if (!c.msgTracer()) return orig.apply(this, arguments)
|
|
311
|
+
const nc = this.api && this.api.nc
|
|
312
|
+
const group = consumerName(this)
|
|
313
|
+
const tags = Object.assign({}, nc ? peer(nc) : {})
|
|
314
|
+
if (group) tags['messaging.consumer.group.name'] = group
|
|
315
|
+
// created now (covers the call), kept only when a message came back (ITG-023)
|
|
316
|
+
const span = c.batchConsumer(SYSTEM, undefined, null, tags, 'receive')
|
|
317
|
+
let p
|
|
318
|
+
try {
|
|
319
|
+
// 3.x implements next() with fetch(): that inner call makes no span of its own
|
|
320
|
+
p = c.outer(orig, this, arguments)
|
|
321
|
+
} catch (err) {
|
|
322
|
+
c.end(span, err)
|
|
323
|
+
throw err
|
|
324
|
+
}
|
|
325
|
+
if (!span || !c.isThenable(p)) return p
|
|
326
|
+
return p.then((msg) => {
|
|
327
|
+
if (msg) {
|
|
328
|
+
try {
|
|
329
|
+
if (msg.subject) {
|
|
330
|
+
span.setAttribute('messaging.destination.name', msg.subject)
|
|
331
|
+
span.updateName('receive ' + msg.subject)
|
|
332
|
+
}
|
|
333
|
+
Object.entries(jsTags(msg)).forEach(([k, v]) => span.setAttribute(k, v))
|
|
334
|
+
c.addLink(span, extractMsg(msg))
|
|
335
|
+
} catch (_) {}
|
|
336
|
+
c.end(span)
|
|
337
|
+
}
|
|
338
|
+
return msg
|
|
339
|
+
}, (err) => {
|
|
340
|
+
c.end(span, err)
|
|
341
|
+
throw err
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// -- iterators (subscriptions, consume(), fetch()) --------------------------------------------
|
|
347
|
+
|
|
348
|
+
function mark (it, meta) {
|
|
349
|
+
if (!it || typeof it !== 'object') return
|
|
350
|
+
try {
|
|
351
|
+
Object.defineProperty(it, META, { value: meta, configurable: true })
|
|
352
|
+
} catch (_) {}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function wrapAsyncIterator (orig) {
|
|
356
|
+
return function asyncIterator () {
|
|
357
|
+
const it = orig.apply(this, arguments)
|
|
358
|
+
const meta = this && this[META]
|
|
359
|
+
if (!meta || !it || typeof it.next !== 'function' || !c.msgTracer()) return it
|
|
360
|
+
return meta.mode === 'fetch' ? fetchIterator(it, meta) : traceIterator(it, meta)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/** Iterator style (ITG-023): one CONSUMER span per message, current for the loop body. */
|
|
365
|
+
function traceIterator (it, meta) {
|
|
366
|
+
const st = c.iterState({})
|
|
367
|
+
const out = {
|
|
368
|
+
next () {
|
|
369
|
+
st.nextRequested()
|
|
370
|
+
let p
|
|
371
|
+
try {
|
|
372
|
+
p = it.next.apply(it, arguments)
|
|
373
|
+
} catch (err) {
|
|
374
|
+
st.closed(true)
|
|
375
|
+
throw err
|
|
376
|
+
}
|
|
377
|
+
return Promise.resolve(p).then((r) => {
|
|
378
|
+
if (r && r.done) st.closed(true)
|
|
379
|
+
else if (r && r.value) {
|
|
380
|
+
try {
|
|
381
|
+
st.delivered(consumerSpan(meta.nc, r.value, meta.group, meta.js ? jsTags(r.value) : undefined))
|
|
382
|
+
} catch (_) {}
|
|
383
|
+
}
|
|
384
|
+
return r
|
|
385
|
+
}, (err) => {
|
|
386
|
+
// the library call itself failed: the open span (if any) is closed by closed()
|
|
387
|
+
st.closed(true)
|
|
388
|
+
throw err
|
|
389
|
+
})
|
|
390
|
+
},
|
|
391
|
+
return () {
|
|
392
|
+
st.closed(true)
|
|
393
|
+
return typeof it.return === 'function' ? it.return.apply(it, arguments) : Promise.resolve({ done: true, value: undefined })
|
|
394
|
+
},
|
|
395
|
+
throw () {
|
|
396
|
+
st.closed(true)
|
|
397
|
+
return typeof it.throw === 'function' ? it.throw.apply(it, arguments) : Promise.reject(arguments[0])
|
|
398
|
+
},
|
|
399
|
+
[Symbol.asyncIterator] () {
|
|
400
|
+
return this
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return out
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** Batch pull over an iterator (`fetch()`): a `receive` span from the call to the end, with links. */
|
|
407
|
+
function fetchIterator (it, meta) {
|
|
408
|
+
const span = meta.span
|
|
409
|
+
const subjects = new Set()
|
|
410
|
+
let count = 0
|
|
411
|
+
let finished = false
|
|
412
|
+
const finish = (err) => {
|
|
413
|
+
if (finished || !span) return
|
|
414
|
+
finished = true
|
|
415
|
+
if (err) return c.end(span, err)
|
|
416
|
+
if (count === 0) return
|
|
417
|
+
try {
|
|
418
|
+
if (subjects.size === 1) {
|
|
419
|
+
const s = Array.from(subjects)[0]
|
|
420
|
+
span.setAttribute('messaging.destination.name', s)
|
|
421
|
+
span.updateName('receive ' + s)
|
|
422
|
+
}
|
|
423
|
+
if (count >= 2) span.setAttribute('messaging.batch.message_count', String(count))
|
|
424
|
+
} catch (_) {}
|
|
425
|
+
c.end(span)
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
next () {
|
|
429
|
+
return Promise.resolve(it.next.apply(it, arguments)).then((r) => {
|
|
430
|
+
if (r && r.done) finish()
|
|
431
|
+
else if (r && r.value) {
|
|
432
|
+
count++
|
|
433
|
+
try {
|
|
434
|
+
if (r.value.subject) subjects.add(r.value.subject)
|
|
435
|
+
c.addLink(span, extractMsg(r.value))
|
|
436
|
+
} catch (_) {}
|
|
437
|
+
}
|
|
438
|
+
return r
|
|
439
|
+
}, (err) => {
|
|
440
|
+
finish(err)
|
|
441
|
+
throw err
|
|
442
|
+
})
|
|
443
|
+
},
|
|
444
|
+
return () {
|
|
445
|
+
finish()
|
|
446
|
+
return typeof it.return === 'function' ? it.return.apply(it, arguments) : Promise.resolve({ done: true, value: undefined })
|
|
447
|
+
},
|
|
448
|
+
throw () {
|
|
449
|
+
finish()
|
|
450
|
+
return typeof it.throw === 'function' ? it.throw.apply(it, arguments) : Promise.reject(arguments[0])
|
|
451
|
+
},
|
|
452
|
+
[Symbol.asyncIterator] () {
|
|
453
|
+
return this
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// -- patches ----------------------------------------------------------------------------------
|
|
459
|
+
|
|
460
|
+
function headersFactory (dir) {
|
|
461
|
+
if (factories.has(dir)) return factories.get(dir)
|
|
462
|
+
let f = null
|
|
463
|
+
for (const rel of ['lib/nats-base-client/headers.js', 'lib/headers.js']) {
|
|
464
|
+
try {
|
|
465
|
+
const m = require(path.join(dir, rel))
|
|
466
|
+
if (typeof m.headers === 'function') {
|
|
467
|
+
f = m.headers
|
|
468
|
+
break
|
|
469
|
+
}
|
|
470
|
+
} catch (_) {}
|
|
471
|
+
}
|
|
472
|
+
factories.set(dir, f)
|
|
473
|
+
return f
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** nats/lib/nats-base-client/nats.js (2.x) and @nats-io/nats-core/lib/nats.js (3.x). */
|
|
477
|
+
function patchConnection (exports, info) {
|
|
478
|
+
const Impl = exports && exports.NatsConnectionImpl
|
|
479
|
+
const proto = Impl && Impl.prototype
|
|
480
|
+
if (!proto || typeof proto.publish !== 'function') {
|
|
481
|
+
c.disabled(info.pkg, 'NatsConnectionImpl.publish not found')
|
|
482
|
+
return
|
|
483
|
+
}
|
|
484
|
+
const factory = headersFactory(info.dir)
|
|
485
|
+
c.wrap(proto, 'publish', wrapPublish(factory))
|
|
486
|
+
if (typeof proto.request === 'function') c.wrap(proto, 'request', wrapRequest(factory, false))
|
|
487
|
+
if (typeof proto.requestMany === 'function') c.wrap(proto, 'requestMany', wrapRequest(factory, true))
|
|
488
|
+
if (typeof proto.subscribe === 'function') c.wrap(proto, 'subscribe', wrapSubscribe)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** queued_iterator.js: QueuedIteratorImpl.prototype[Symbol.asyncIterator]. */
|
|
492
|
+
function patchIterator (exports) {
|
|
493
|
+
const Q = exports && exports.QueuedIteratorImpl
|
|
494
|
+
const proto = Q && Q.prototype
|
|
495
|
+
if (!proto || typeof proto[Symbol.asyncIterator] !== 'function') return
|
|
496
|
+
c.wrap(proto, Symbol.asyncIterator, wrapAsyncIterator)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** nats/lib/jetstream/jsclient.js and @nats-io/jetstream/lib/jsclient.js. */
|
|
500
|
+
function patchJsClient (exports, info) {
|
|
501
|
+
const Impl = exports && exports.JetStreamClientImpl
|
|
502
|
+
const proto = Impl && Impl.prototype
|
|
503
|
+
if (!proto || typeof proto.publish !== 'function') {
|
|
504
|
+
c.disabled(info.pkg, 'JetStreamClientImpl.publish not found')
|
|
505
|
+
return
|
|
506
|
+
}
|
|
507
|
+
// the headers factory lives in the core package: nats (same package) or @nats-io/nats-core
|
|
508
|
+
let factory = headersFactory(info.dir)
|
|
509
|
+
if (!factory) {
|
|
510
|
+
try {
|
|
511
|
+
const core = require.resolve('@nats-io/nats-core', { paths: [info.dir] })
|
|
512
|
+
factory = headersFactory(path.dirname(path.dirname(core)))
|
|
513
|
+
} catch (_) {}
|
|
514
|
+
}
|
|
515
|
+
c.wrap(proto, 'publish', wrapJsPublish(factory))
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/** jetstream consumer.js: PullConsumerImpl / OrderedPullConsumerImpl consume, fetch, next. */
|
|
519
|
+
function patchConsumer (exports) {
|
|
520
|
+
for (const name of ['PullConsumerImpl', 'OrderedPullConsumerImpl']) {
|
|
521
|
+
const K = exports && exports[name]
|
|
522
|
+
const proto = K && K.prototype
|
|
523
|
+
if (!proto) continue
|
|
524
|
+
if (typeof proto.consume === 'function') c.wrap(proto, 'consume', wrapConsume)
|
|
525
|
+
if (typeof proto.internalHandler === 'function') c.wrap(proto, 'internalHandler', wrapInternalHandler)
|
|
526
|
+
if (typeof proto.fetch === 'function') c.wrap(proto, 'fetch', wrapFetch)
|
|
527
|
+
if (typeof proto.next === 'function') c.wrap(proto, 'next', wrapNext)
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
module.exports = { patchConnection, patchIterator, patchJsClient, patchConsumer }
|