@redthreadlabs/tracelog 1.5.0 → 1.5.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.
@@ -710,6 +710,14 @@ Instrumentation.prototype.addEndedTransaction = function (transaction) {
710
710
  trans: transaction.id,
711
711
  trace: transaction.traceId,
712
712
  });
713
+ // The transaction's name is final now, so held spans can be routed
714
+ // even though the transaction record itself was dropped.
715
+ this._drainPendingChannelSpans(
716
+ transaction,
717
+ agent._channelForTransactionName(
718
+ transaction._customName || transaction._defaultName,
719
+ ),
720
+ );
713
721
  return;
714
722
  }
715
723
 
@@ -718,6 +726,9 @@ Instrumentation.prototype.addEndedTransaction = function (transaction) {
718
726
  trace: transaction.traceId,
719
727
  });
720
728
  const channel = agent._channelForTransactionName(payload.name);
729
+ // Spans held while this transaction's name was unresolved follow the
730
+ // same routing decision as the transaction itself.
731
+ this._drainPendingChannelSpans(transaction, channel);
721
732
  if (channel && typeof agent._apmClient.sendToChannel === 'function') {
722
733
  agent._apmClient.sendToChannel(channel, 'transaction', payload);
723
734
  } else {
@@ -725,6 +736,31 @@ Instrumentation.prototype.addEndedTransaction = function (transaction) {
725
736
  }
726
737
  };
727
738
 
739
+ // Send any span payloads that were held on the transaction because the
740
+ // transaction's name (and so its channel routing) was not yet resolved
741
+ // when the span ended. See `_encodeAndSendSpan`.
742
+ Instrumentation.prototype._drainPendingChannelSpans = function (
743
+ transaction,
744
+ channel,
745
+ ) {
746
+ const agent = this._agent;
747
+ const pending = transaction._pendingChannelSpans;
748
+ if (!pending) {
749
+ return;
750
+ }
751
+ transaction._pendingChannelSpans = null;
752
+ if (!agent._apmClient) {
753
+ return;
754
+ }
755
+ for (const payload of pending) {
756
+ if (channel && typeof agent._apmClient.sendToChannel === 'function') {
757
+ agent._apmClient.sendToChannel(channel, 'span', payload);
758
+ } else {
759
+ agent._apmClient.sendSpan(payload);
760
+ }
761
+ }
762
+ };
763
+
728
764
  Instrumentation.prototype.addEndedSpan = function (span) {
729
765
  var agent = this._agent;
730
766
 
@@ -847,15 +883,38 @@ Instrumentation.prototype._encodeAndSendSpan = function (span) {
847
883
  });
848
884
  if (agent._apmClient) {
849
885
  // Spans follow their transaction's channel. The transaction name
850
- // may not be final until the transaction ends, so this routing is
851
- // best-effort for spans that end before the route is resolved.
852
- const channel = agent._channelForTransactionName(
853
- span.transaction && span.transaction.name,
854
- );
855
- if (channel && typeof agent._apmClient.sendToChannel === 'function') {
856
- agent._apmClient.sendToChannel(channel, 'span', payload);
857
- } else {
886
+ // is only meaningful for routing once *resolved* (custom or
887
+ // framework-set); the `name` getter must not be used here, since
888
+ // until the transaction ends it falls back to
889
+ // '<METHOD> unknown route (unnamed)', which would spuriously
890
+ // match rules aimed at unmatched-route traffic. When routing is
891
+ // configured and the name is not yet resolved (e.g. Express only
892
+ // names transactions when the request finishes), hold the span on
893
+ // its transaction; addEndedTransaction() drains held spans with
894
+ // the transaction's final routing decision.
895
+ const trans = span.transaction;
896
+ const routingEnabled =
897
+ agent._conf.transactionChannelRules &&
898
+ agent._conf.transactionChannelRules.length > 0 &&
899
+ typeof agent._apmClient.sendToChannel === 'function';
900
+ if (!routingEnabled) {
858
901
  agent._apmClient.sendSpan(payload);
902
+ } else {
903
+ const resolvedName =
904
+ trans && (trans._customName || trans._defaultName);
905
+ if (!resolvedName && trans && !trans.ended) {
906
+ if (!trans._pendingChannelSpans) {
907
+ trans._pendingChannelSpans = [];
908
+ }
909
+ trans._pendingChannelSpans.push(payload);
910
+ } else {
911
+ const channel = agent._channelForTransactionName(resolvedName);
912
+ if (channel) {
913
+ agent._apmClient.sendToChannel(channel, 'span', payload);
914
+ } else {
915
+ agent._apmClient.sendSpan(payload);
916
+ }
917
+ }
859
918
  }
860
919
  }
861
920
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redthreadlabs/tracelog",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Node.js APM instrumentation that writes traces to JSONL files",
5
5
  "publishConfig": {
6
6
  "access": "public"