88const { tracingChannel } = require ( 'node:diagnostics_channel' )
99
1010/**
11- * Base class for defining a subscriber.
12- * events property is an array with the following possible event names:
13- * `start`, `end`, `asyncStart`, `asyncEnd`, `error`
14- * @link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel
11+ * The baseline parameters available to all subscribers.
12+ *
13+ * @typedef {object } SubscriberParams
14+ * @property {object } agent A New Relic Node.js agent instance.
15+ * @property {object } logger An agent logger instance.
16+ * @property {string } packageName The npm installable name for the package
17+ * being instrumented. This is what a developer would provide to the `require`
18+ * function.
19+ * @property {string } channelName A unique name for the diagnostics channel
20+ * that will be created and monitored.
21+ */
22+
23+ /**
24+ * @property {object } agent A New Relic Node.js agent instance.
25+ * @property {object } logger An agent logger instance.
26+ * @property {object } config The agent configuration object.
27+ * @property {string } packageName The name of the module being instrumented.
28+ * This is the same string one would pass to the `require` function.
29+ * @property {string } channelName A unique name for the diagnostics channel
30+ * that will be registered.
31+ * @property {string[] } [events=[]] Set of tracing channel event names to
32+ * register handlers for. For any name in the set, a corresponding method
33+ * must exist on the subscriber instance. The method will be passed the
34+ * event object. Possible event names are `start`, `end`, `asyncStart`,
35+ * `asyncEnd`, and `error`. @link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel
36+ * @property {boolean } [opaque=false] If true, any children segments will not be created
37+ * @property {boolean } [internal=false] If true, any children segments from the same library will not be created
38+ * @property {string } [prefix='orchestrion:'] String to prepend to diagnostics
39+ * channel event names. This provides a namespace for the events we are
40+ * injecting into a module.
41+ * @property {boolean } [requireActiveTx=true] If true, the subscriber will only handle events when there is an active transaction.
42+ * @property {string } id A unique identifier for the subscriber, combining the prefix, package name, and channel name.
43+ * @property {TracingChannel } channel The tracing channel instance this subscriber will be monitoring.
44+ * @property {AsyncLocalStorage } store The async local storage instance used for context management.
1545 */
1646class Subscriber {
1747 constructor ( { agent, logger, packageName, channelName } ) {
@@ -22,13 +52,20 @@ class Subscriber {
2252 this . channelName = channelName
2353 this . events = [ ]
2454 this . opaque = false
55+ this . internal = false
2556 this . prefix = 'orchestrion:'
2657 this . requireActiveTx = true
2758 this . id = `${ this . prefix } ${ this . packageName } :${ this . channelName } `
2859 this . channel = tracingChannel ( this . id )
2960 this . store = agent . tracer . _contextManager . _asyncLocalStorage
3061 }
3162
63+ shouldCreateSegment ( parent ) {
64+ return ! ( parent ?. opaque ||
65+ ( this . internal && this . packageName === parent ?. shimId )
66+ )
67+ }
68+
3269 /**
3370 * Creates a segment with a name, parent, transaction and optional recorder.
3471 * If the segment is successfully created, it will be started and added to the context.
@@ -39,15 +76,23 @@ class Subscriber {
3976 * @returns {Context } - The updated context with the new segment or existing context if segment creation fails
4077 */
4178 createSegment ( { name, recorder, ctx } ) {
79+ const parent = ctx ?. segment
80+
81+ if ( this . shouldCreateSegment ( parent ) === false ) {
82+ this . logger . trace ( 'Skipping segment creation for %s, %s(parent) is of the same package: %s and incoming segment is marked as internal' , name , parent ?. name , this . packageName )
83+ return ctx
84+ }
85+
4286 const segment = this . agent . tracer . createSegment ( {
4387 name,
44- parent : ctx ?. segment ,
88+ parent,
4589 recorder,
4690 transaction : ctx ?. transaction ,
4791 } )
4892
4993 if ( segment ) {
5094 segment . opaque = this . opaque
95+ segment . shimId = this . packageName
5196 segment . start ( )
5297 this . logger . trace ( 'Created segment %s' , name )
5398 this . addAttributes ( segment )
0 commit comments