Skip to content

Commit 23ee241

Browse files
authored
fix: allow the agent to accept multiple versions of legacy NR distributed tracing headers (#1489)
* Initial implementation and unit tests * Remove unreachable and obsolete code and tests associated with AcceptDistributedTracePayload * More cleanup * Forgot one cleanup item
1 parent 41f1eef commit 23ee241

File tree

17 files changed

+75
-2149
lines changed

17 files changed

+75
-2149
lines changed

src/Agent/NewRelic/Agent/Core/Agent.cs

-18
Original file line numberDiff line numberDiff line change
@@ -225,24 +225,6 @@ bool ShouldRunExplain()
225225

226226
#region inbound CAT request, outbound CAT response
227227

228-
public bool TryGetDistributedTracePayloadFromHeaders<T>(IEnumerable<KeyValuePair<string, T>> headers, out T payload) where T : class
229-
{
230-
payload = null;
231-
if (headers != null)
232-
{
233-
foreach (var header in headers)
234-
{
235-
if (header.Key.Equals(Constants.DistributedTracePayloadKey, StringComparison.OrdinalIgnoreCase))
236-
{
237-
payload = header.Value;
238-
return true;
239-
}
240-
}
241-
}
242-
243-
return false;
244-
}
245-
246228
internal void TryProcessCatRequestData<T>(IInternalTransaction transaction, T carrier, Func<T, string, IEnumerable<string>> getter)
247229
{
248230
try

src/Agent/NewRelic/Agent/Core/DistributedTracing/DistributedTracePayloadHandler.cs

+2-23
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ public interface IDistributedTracePayloadHandler
2828

2929
DistributedTracePayload TryDecodeInboundSerializedDistributedTracePayload(string serializedPayload);
3030

31-
ITracingState AcceptDistributedTracePayload(string serializedPayload, TransportType transportType, DateTime transactionStartTime);
32-
3331
ITracingState AcceptDistributedTraceHeaders<T>(T carrier, Func<T, string, IEnumerable<string>> getter, TransportType transportType, DateTime transactionStartTime);
3432

3533
void InsertDistributedTraceHeaders<T>(IInternalTransaction transaction, T carrier, Action<T, string, string> setter);
@@ -68,11 +66,11 @@ public void InsertDistributedTraceHeaders<T>(IInternalTransaction transaction, T
6866
var timestamp = DateTime.UtcNow;
6967
if (!_configurationService.Configuration.ExcludeNewrelicHeader)
7068
{
71-
//set "Newrelic" header
69+
//set "newrelic" header
7270
var distributedTracePayload = GetOutboundHeader(DistributedTraceHeaderType.NewRelic, transaction, timestamp);
7371
if (!string.IsNullOrWhiteSpace(distributedTracePayload))
7472
{
75-
setter(carrier, Constants.DistributedTracePayloadKey, distributedTracePayload);
73+
setter(carrier, Constants.DistributedTracePayloadKeyAllLower, distributedTracePayload);
7674
}
7775
}
7876

@@ -249,25 +247,6 @@ private IDistributedTracePayload TryGetOutboundDistributedTraceApiModelInternal(
249247

250248
#region Incoming/Accept
251249

252-
public ITracingState AcceptDistributedTracePayload(string serializedPayload, TransportType transportType, DateTime transactionStartTime)
253-
{
254-
var tracingState = TracingState.AcceptDistributedTracePayload(serializedPayload, transportType, _configurationService.Configuration.TrustedAccountKey, transactionStartTime);
255-
256-
if (tracingState.IngestErrors != null)
257-
{
258-
ReportIncomingErrors(tracingState.IngestErrors);
259-
}
260-
else
261-
{
262-
if (_configurationService.Configuration.PayloadSuccessMetricsEnabled)
263-
{
264-
_agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadSuccess();
265-
}
266-
}
267-
268-
return tracingState;
269-
}
270-
271250
public ITracingState AcceptDistributedTraceHeaders<T>(T carrier, Func<T, string, IEnumerable<string>> getter, TransportType transportType, DateTime transactionStartTime)
272251
{
273252
if (getter == null)

src/Agent/NewRelic/Agent/Core/DistributedTracing/TracingState.cs

+13-21
Original file line numberDiff line numberDiff line change
@@ -205,25 +205,6 @@ public float? Priority
205205
private DistributedTracePayload _newRelicPayload;
206206
private W3CTraceContext _traceContext;
207207

208-
public static ITracingState AcceptDistributedTracePayload(string encodedPayload, TransportType transportType, string agentTrustKey, DateTime transactionStartTime)
209-
{
210-
var tracingState = new TracingState();
211-
var errors = new List<IngestErrorType>();
212-
tracingState._newRelicPayload = DistributedTracePayload.TryDecodeAndDeserializeDistributedTracePayload(encodedPayload, agentTrustKey, errors);
213-
tracingState.NewRelicPayloadWasAccepted = tracingState._newRelicPayload != null ? true : false;
214-
tracingState._transactionStartTime = tracingState._newRelicPayload != null ? transactionStartTime : default;
215-
216-
if (errors.Any())
217-
{
218-
tracingState.IngestErrors = errors;
219-
}
220-
221-
tracingState.HasDataForAttributes = tracingState.NewRelicPayloadWasAccepted;
222-
tracingState.TransportType = transportType;
223-
224-
return tracingState;
225-
}
226-
227208
public static ITracingState AcceptDistributedTraceHeaders<T>(T carrier, Func<T, string, IEnumerable<string>> getter, TransportType transportType, string agentTrustKey, DateTime transactionStartTime)
228209
{
229210
var tracingState = new TracingState();
@@ -242,8 +223,19 @@ public static ITracingState AcceptDistributedTraceHeaders<T>(T carrier, Func<T,
242223
// if traceparent was present (regardless if valid), ignore newrelic header
243224
if (!tracingState._traceContext.TraceparentPresent)
244225
{
245-
var newRelicHeaderList = getter(carrier, Constants.DistributedTracePayloadKey);
246-
if (newRelicHeaderList?.Count() > 0) // the Newrelic header key was present
226+
// Search for the following header keys in this order: "newrelic", "NEWRELIC", "Newrelic"
227+
// If the getter function makes a case-insensitive search it will find any of the three
228+
// variants on the first call.
229+
var newRelicHeaderList = getter(carrier, Constants.DistributedTracePayloadKeyAllLower);
230+
if (newRelicHeaderList?.Any() == false)
231+
{
232+
newRelicHeaderList = getter(carrier, Constants.DistributedTracePayloadKeyAllUpper);
233+
}
234+
if (newRelicHeaderList?.Any() == false)
235+
{
236+
newRelicHeaderList = getter(carrier, Constants.DistributedTracePayloadKeySingleUpper);
237+
}
238+
if (newRelicHeaderList?.Any() == true) // a NR header key was present
247239
{
248240
tracingState._newRelicPayload = DistributedTracePayload.TryDecodeAndDeserializeDistributedTracePayload(newRelicHeaderList.FirstOrDefault(), agentTrustKey, errors);
249241
tracingState.NewRelicPayloadWasAccepted = tracingState._newRelicPayload != null ? true : false;

src/Agent/NewRelic/Agent/Core/NewRelic.Agent.Core.Metric/ApiSupportabilityMetricCounters.cs

+26-29
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,32 @@ namespace NewRelic.Agent.Core.Metric
1111
{
1212
public enum ApiMethod
1313
{
14-
CreateDistributedTracePayload = 0,
15-
AcceptDistributedTracePayload = 1,
16-
CurrentTransaction = 2,
17-
AddCustomParameter = 3, //To Be replaced by AddCustomAttribute
18-
DisableBrowserMonitoring = 4,
19-
GetBrowserTimingHeader = 5,
20-
IgnoreApdex = 6,
21-
IgnoreTransaction = 7,
22-
IncrementCounter = 8,
23-
NoticeError = 9,
24-
RecordCustomEvent = 10,
25-
RecordMetric = 11,
26-
RecordResponseTimeMetric = 12,
27-
SetApplicationName = 13,
28-
SetTransactionName = 14,
29-
SetUserParameters = 15,
30-
GetBrowserTimingFooter = 16,
31-
StartAgent = 17,
32-
SetTransactionUri = 18,
33-
TraceMetadata = 19,
34-
GetLinkingMetadata = 20,
35-
TransactionAddCustomAttribute = 21,
36-
TransactionGetCurrentSpan = 22,
37-
SpanAddCustomAttribute = 23,
38-
InsertDistributedTraceHeaders = 24,
39-
AcceptDistributedTraceHeaders = 25,
40-
SpanSetName = 26,
41-
SetErrorGroupCallback = 27,
42-
SetUserId = 28
14+
CurrentTransaction = 0,
15+
DisableBrowserMonitoring = 1,
16+
GetBrowserTimingHeader = 2,
17+
IgnoreApdex = 3,
18+
IgnoreTransaction = 4,
19+
IncrementCounter = 5,
20+
NoticeError = 6,
21+
RecordCustomEvent = 7,
22+
RecordMetric = 8,
23+
RecordResponseTimeMetric = 9,
24+
SetApplicationName = 10,
25+
SetTransactionName = 11,
26+
SetUserParameters = 12,
27+
GetBrowserTimingFooter = 13,
28+
StartAgent = 14,
29+
SetTransactionUri = 15,
30+
TraceMetadata = 16,
31+
GetLinkingMetadata = 17,
32+
TransactionAddCustomAttribute = 18,
33+
TransactionGetCurrentSpan = 19,
34+
SpanAddCustomAttribute = 20,
35+
InsertDistributedTraceHeaders = 21,
36+
AcceptDistributedTraceHeaders = 22,
37+
SpanSetName = 23,
38+
SetErrorGroupCallback = 24,
39+
SetUserId = 25
4340
}
4441

4542
public interface IApiSupportabilityMetricCounters : IOutOfBandMetricSource

src/Agent/NewRelic/Agent/Core/Transactions/NoOpTransaction.cs

-5
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,6 @@ public IEnumerable<KeyValuePair<string, string>> GetRequestMetadata()
107107
return Enumerable.Empty<KeyValuePair<string, string>>();
108108
}
109109

110-
public void AcceptDistributedTracePayload(string payload, TransportType transportType)
111-
{
112-
Log.Debug("Tried to accept distributed trace payload, but there was no transaction");
113-
}
114-
115110
public IDistributedTracePayload CreateDistributedTracePayload()
116111
{
117112
Log.Debug("Tried to create distributed trace payload, but there was no transaction");

src/Agent/NewRelic/Agent/Core/Transactions/Transaction.cs

+1-23
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ public IEnumerable<KeyValuePair<string, string>> GetRequestMetadata()
559559
{
560560
return headers;
561561
}
562-
return headers.Concat(new[] { new KeyValuePair<string, string>(Constants.DistributedTracePayloadKey, payload.HttpSafe()) });
562+
return headers.Concat(new[] { new KeyValuePair<string, string>(Constants.DistributedTracePayloadKeyAllLower, payload.HttpSafe()) });
563563
}
564564

565565
// CAT
@@ -607,28 +607,6 @@ private void UpdatePathHash(TransactionMetricName transactionMetricName)
607607
TransactionMetadata.SetCrossApplicationPathHash(pathHash);
608608
}
609609

610-
public void AcceptDistributedTracePayload(string payload, TransportType transportType)
611-
{
612-
if (!_configuration.DistributedTracingEnabled)
613-
{
614-
return;
615-
}
616-
if (TransactionMetadata.HasOutgoingTraceHeaders)
617-
{
618-
Agent._agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadIgnoredCreateBeforeAccept();
619-
return;
620-
}
621-
if (TracingState != null)
622-
{
623-
Agent._agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadIgnoredMultiple();
624-
return;
625-
}
626-
627-
var isUnknownTransportType = transportType < TransportType.Unknown || transportType > TransportType.Other;
628-
629-
TracingState = Agent._distributedTracePayloadHandler.AcceptDistributedTracePayload(payload, isUnknownTransportType ? TransportType.Unknown : transportType, StartTime);
630-
}
631-
632610
public void AcceptDistributedTraceHeaders<T>(T carrier, Func<T, string, IEnumerable<string>> getter, TransportType transportType)
633611
{
634612
if (_configuration.DistributedTracingEnabled)

src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Api/IAgent.cs

-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ public interface IAgent : IAgentExperimental
9292
/// <param name="requestPath">The path of the request</param>
9393
Stream TryGetStreamInjector(Stream stream, Encoding encoding, string contentType, string requestPath);
9494

95-
bool TryGetDistributedTracePayloadFromHeaders<T>(IEnumerable<KeyValuePair<string, T>> headers, out T payload) where T : class;
96-
9795
/// <summary>
9896
/// Returns the Trace Metadata of the currently executing transaction.
9997
/// </summary>

src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Api/ITransaction.cs

-6
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,6 @@ public interface ITransaction
112112
/// <returns>Collection of key value pairs representing the response metadata</returns>
113113
IEnumerable<KeyValuePair<string, string>> GetResponseMetadata();
114114

115-
/// <summary>
116-
/// Processes incoming distributed trace request.
117-
/// </summary>
118-
/// <param name="payload">Serialized incoming distributed trace payload. May or may not be Base64 Encoded.</param>
119-
void AcceptDistributedTracePayload(string payload, TransportType transportType);
120-
121115
/// <summary>
122116
/// Returns the distributed trace payload model that is attached to the outbound request.
123117
/// </summary>

src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Providers/Wrapper/Constants.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
using System.Collections.Concurrent;
5-
using System.Linq;
65
using System.Text;
76

87
namespace NewRelic.Agent.Extensions.Providers.Wrapper
@@ -14,8 +13,11 @@ public static class Constants
1413
{
1514
/// <summary>
1615
/// This is the key-part that the agent recognizes when trying to find a DistributedTracePayload, typically passed as a KeyValuePair in the header of a request.
16+
/// Per the agent specs, the agent should accept the following variants of the header key name: newrelic, NEWRELIC, Newrelic
1717
/// </summary>
18-
public const string DistributedTracePayloadKey = "newrelic";
18+
public const string DistributedTracePayloadKeyAllLower = "newrelic";
19+
public const string DistributedTracePayloadKeyAllUpper = "NEWRELIC";
20+
public const string DistributedTracePayloadKeySingleUpper = "Newrelic";
1921

2022
public const string TraceParentHeaderKey = "traceparent";
2123

src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/RabbitMq/RabbitMqHelper.cs

-13
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,6 @@ public static string ResolveDestinationName(MessageBrokerDestinationType destina
5151
: queueNameOrRoutingKey;
5252
}
5353

54-
public static bool TryGetPayloadFromHeaders(Dictionary<string, object> messageHeaders, IAgent agent,
55-
out string serializedPayload)
56-
{
57-
if (agent.TryGetDistributedTracePayloadFromHeaders(messageHeaders, out var payload))
58-
{
59-
serializedPayload = Encoding.UTF8.GetString((byte[])(payload));
60-
return true;
61-
}
62-
63-
serializedPayload = null;
64-
return false;
65-
}
66-
6754
public static ISegment CreateSegmentForPublishWrappers(InstrumentedMethodCall instrumentedMethodCall, ITransaction transaction, int basicPropertiesIndex)
6855
{
6956
// ATTENTION: We have validated that the use of dynamic here is appropriate based on the visibility of the data we're working with.

tests/Agent/IntegrationTests/Applications/DistributedTracingApiApplication/Program.cs

+1-24
Original file line numberDiff line numberDiff line change
@@ -68,36 +68,13 @@ static void Main(string[] args)
6868
}
6969
else
7070
{
71-
var dtPayload = CallCreateDTPayload();
72-
CallAcceptDTPayload(dtPayload);
71+
throw new NotImplementedException();
7372
}
7473

7574
// wait for the test harness to tell us to shut down
7675
eventWaitHandle.WaitOne(TimeSpan.FromMinutes(5));
7776
}
7877

79-
[Transaction]
80-
[MethodImpl(MethodImplOptions.NoInlining)]
81-
private static IDistributedTracePayload CallCreateDTPayload()
82-
{
83-
var currentTransaction = _agent.CurrentTransaction;
84-
// As long as this deprecated API is still shipping, we still need to test it
85-
#pragma warning disable CS0618 // Type or member is obsolete
86-
return currentTransaction.CreateDistributedTracePayload();
87-
#pragma warning restore CS0618 // Type or member is obsolete
88-
}
89-
90-
[Transaction]
91-
[MethodImpl(MethodImplOptions.NoInlining)]
92-
private static void CallAcceptDTPayload(IDistributedTracePayload payload)
93-
{
94-
var currentTransaction = _agent.CurrentTransaction;
95-
// As long as this deprecated API is still shipping, we still need to test it
96-
#pragma warning disable CS0618 // Type or member is obsolete
97-
currentTransaction.AcceptDistributedTracePayload(payload.HttpSafe());
98-
#pragma warning restore CS0618 // Type or member is obsolete
99-
}
100-
10178
[Transaction]
10279
[MethodImpl(MethodImplOptions.NoInlining)]
10380
private static void CallInsertDTHeaders()

tests/Agent/UnitTests/CompositeTests/CompositeTests.csproj

-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@
4343
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
4444
</ItemGroup>
4545
<ItemGroup>
46-
<None Update="CrossAgentTests\DistributedTracing\distributed_tracing.json">
47-
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
48-
</None>
4946
<None Update="CrossAgentTests\DistributedTracing\trace_context.json">
5047
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
5148
</None>

0 commit comments

Comments
 (0)