public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { //reader should be positioned at the start of the object "{" if (reader.TokenType != JsonToken.StartObject) { throw new DistributedTraceAcceptPayloadParseException( $"expected to find beginning of DistributedTracePayload object. Found token: {Enum.GetName(typeof(JsonToken), reader.TokenType)}"); } var parsedPayload = new DistributedTracePayload(); var jObject = JObject.Load(reader); foreach (var constraint in _validationConstraints) { constraint.ParseAndThrowOnFailure(jObject, parsedPayload); } if (string.IsNullOrEmpty(parsedPayload.Guid) && string.IsNullOrEmpty(parsedPayload.TransactionId)) { throw new DistributedTraceAcceptPayloadParseException( $"expected either the Guid or the TransactionId to be present. Found: neither"); } return(parsedPayload); }
public void DistributedTracePayload_RoundTrip( [Values("App", "Mobile")] string type, [Values("12345")] string accountId, [Values("1111")] string appId, [Random(0ul, 0xfffffffffffffffful, 1), Values(ulong.MinValue, ulong.MaxValue)] ulong parentId, [Random(0ul, 0xfffffffffffffffful, 1), Values(ulong.MinValue, ulong.MaxValue)] ulong guid, [Random(0ul, 0xfffffffffffffffful, 1), Values(ulong.MinValue, ulong.MaxValue)] ulong traceId, [Values("56789")] string trustKey, [Random(0f, 1.0f, 1), Values(0.0f, 1.0f, 0.1234567f)] float priority, [Values(true, false)] bool sampled, [Values(new[] { 1970, 1, 1, 0, 0, 1 }, new[] { 2018, 12, 31, 23, 59, 59 })] int[] time, [Random(0ul, 0xfffffffffffffffful, 1), Values(ulong.MinValue, ulong.MaxValue)] ulong _transactionId) { var input = DistributedTracePayload.TryBuildOutgoingPayload(type, accountId, appId, $"{guid:X8}", $"{traceId:X8}", trustKey, priority, sampled, new DateTime(time[0], time[1], time[2], time[3], time[4], time[5], DateTimeKind.Utc), $"{_transactionId:X8}"); var serialized = input.ToJson(); var deserialized = DistributedTracePayload.TryBuildIncomingPayloadFromJson(serialized); Assert.That(deserialized.Version, Is.Not.Null); Assert.That(deserialized.Version, Has.Exactly(2).Items); Assert.That(deserialized.Version[0], Is.EqualTo(0)); Assert.That(deserialized.Version[1], Is.EqualTo(1)); Assert.That(deserialized.Type, Is.EqualTo(input.Type)); Assert.That(deserialized.AccountId, Is.EqualTo(input.AccountId)); Assert.That(deserialized.AppId, Is.EqualTo(input.AppId)); Assert.That(deserialized.Guid, Is.EqualTo(input.Guid)); Assert.That(deserialized.TraceId, Is.EqualTo(input.TraceId)); Assert.That(deserialized.TrustKey, Is.EqualTo(input.TrustKey)); Assert.That(deserialized.Sampled, Is.EqualTo(input.Sampled)); Assert.That(deserialized.Timestamp, Is.EqualTo(input.Timestamp)); Assert.That(deserialized.TransactionId, Is.EqualTo(input.TransactionId)); }
public void TryDecodeAndDeserializeDistributedTracePayload_ThrowsException_IfEncodedAsInvalidType() { // The following base64 string isn't an encoding of a DistributedTracePayload but it is valid base64. var encodedString = "eyJ2IjpbMCwxXSwiZCI6eyJEaWZmZXJlbnQiOiJUeXBlIiwidHkiOiJBcHAiLCJhYyI6IjkxMjMiLCJhcCI6IjUxNDI0IiwiaWQiOiI1ZjQ3NGQ2NGI5Y2M5YjJhIiwidHIiOiIzMjIxYmYwOWFhMGJjZjBkIiwidGsiOiIxMjM0NSIsInByIjowLjEyMzQsInNhIjpmYWxzZSwidGkiOjE1Mjk0MjQxMzA2MDMsInR4IjoiMjc4NTZmNzBkM2QzMTRiNyJ9fQ=="; Assert.Throws <DistributedTraceAcceptPayloadParseException>(() => DistributedTracePayload.TryDecodeAndDeserializeDistributedTracePayload(encodedString)); }
public void TryBuildOutgoingPayload_ReturnsNull_WhenDoesNotContainGuidOrTransactionId(string guid, string transactionId) { var payload = DistributedTracePayload.TryBuildOutgoingPayload(TransportType, AccountId, AppId, guid, TraceId, TrustKey, Priority, Sampled, Timestamp, transactionId); Assert.Null(payload); }
private bool IsValidPayload(DistributedTracePayload payload) { if (payload == null) { return(false); } return(HasTraceablePayload(payload) && HasTrustedAccountKey(payload)); }
public void TryDecodeAndDeserializeDistributedTracePayload_ThrowsException_IfInvalidVersion() { var payload = BuildSampleDistributedTracePayload(); payload.Version = new int[] { 9999, 1 }; var encodedString = DistributedTracePayload.SerializeAndEncodeDistributedTracePayload(payload); Assert.Throws <DistributedTraceAcceptPayloadVersionException>(() => DistributedTracePayload.TryDecodeAndDeserializeDistributedTracePayload(encodedString)); }
public void SerializeAndEncodeDistributedTracePayload_CreatesCorrectEncodedString() { var payload = BuildSampleDistributedTracePayload(); var jsonString = payload.ToJson(); var encodedJsonString = Strings.Base64Encode(jsonString); var serializedPayload = DistributedTracePayload.SerializeAndEncodeDistributedTracePayload(payload); Assert.AreEqual(encodedJsonString, serializedPayload); }
public void TestDistributedTraceInstrinsicsShowUpIn_ErrorEvents_ErrorTraces_SpanEvent_AnalyticEvent() { var dtPayload = new DistributedTracePayload { Type = "App", AccountId = "test-accountid", AppId = "test-appid", Guid = "test-guid", TraceId = "test-traceid", TrustKey = "test-trustkey", Priority = 1.0F, Sampled = true, Timestamp = DateTime.Now, TransactionId = "test-transactionid", }; var tags = new Dictionary <string, string> { { "newrelic", dtPayload.SerializeAndEncodeDistributedTracePayload() } }; var tracer = LambdaTracer.Instance; var lambdaPayloadContext = (LambdaPayloadContext)tracer.Extract(BuiltinFormats.TextMap, new TextMapExtractAdapter(tags)); var startTime = DateTimeOffset.UtcNow; var span = TestUtil.CreateRootSpan("operationName", startTime, new Dictionary <string, object>(), "testGuid", logger: _logger); span.RootSpan.DistributedTracingState.SetInboundDistributedTracePayload(lambdaPayloadContext.GetPayload()); span.RootSpan.DistributedTracingState.SetTransportDurationInMillis(1000); span.RootSpan.PrioritySamplingState.Priority = (span.RootSpan.DistributedTracingState.InboundPayload.Priority.HasValue) ? span.RootSpan.DistributedTracingState.InboundPayload.Priority.Value : LambdaTracer.TracePriorityManager.Create(); span.RootSpan.PrioritySamplingState.Sampled = span.RootSpan.DistributedTracingState.InboundPayload.Sampled.Value; var exception = new CustomException("my exception.", "this is a stack trace."); var errorAttributes = CreateSpanErrorAttributes(exception, exception.Message, exception.StackTrace); span.Log(errorAttributes); span.Finish(); var deserializedPayload = JsonConvert.DeserializeObject <object[]>(_logger.LastLogMessage); var data = TestUtil.DecodeAndDecompressNewRelicPayload(deserializedPayload[3] as string); Assert.IsTrue(data.Contains("analytic_event_data")); Assert.IsTrue(data.Contains("\"error\":true")); Assert.IsTrue(data.Contains("\"error_event_data\":[")); Assert.IsTrue(data.Contains("\"error_data\":[null,[[")); Assert.AreEqual(4, TestUtil.CountStringOccurrences(data, "\"parent.type\":\"App\"")); Assert.AreEqual(4, TestUtil.CountStringOccurrences(data, "\"parent.account\":\"test-accountid\"")); Assert.AreEqual(4, TestUtil.CountStringOccurrences(data, "\"parent.app\":\"test-appid\"")); Assert.AreEqual(4, TestUtil.CountStringOccurrences(data, "\"parent.transportType\":\"Unknown\"")); Assert.AreEqual(4, TestUtil.CountStringOccurrences(data, "\"parent.transportDuration\":1000.0")); }
private bool HasTraceablePayload(DistributedTracePayload payload) { if ((payload.Guid == null) && (payload.TransactionId == null)) { Log.Debug("Incoming Guid and TransactionId were null, which is invalid for a Distributed Trace payload."); _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadParseException(); return(false); } return(true); }
private static void ParseVersion(JToken selection, DistributedTracePayload payload) { payload.Version = selection.ToObject <int[]>(); var payloadMajorVersion = payload.Version[0]; var payloadMinorVersion = payload.Version[1]; if (payloadMajorVersion > DistributedTracePayload.SupportedMajorVersion) { throw new DistributedTraceAcceptPayloadVersionException( $"unsupported DistributedTracePayload version. Expected: {DistributedTracePayload.SupportedMajorVersion}.{DistributedTracePayload.SupportedMinorVersion} Found: {payloadMajorVersion}.{payloadMinorVersion}"); } }
private bool HasTrustedAccountKey(DistributedTracePayload payload) { var incomingTrustKey = payload.TrustKey ?? payload.AccountId; var isTrusted = incomingTrustKey == _configurationService.Configuration.TrustedAccountKey; if (!isTrusted) { Log.Debug($"Incoming trustKey or accountId [{incomingTrustKey}] not trusted, distributed trace payload will be ignored."); _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadIgnoredUntrustedAccount(); } return(isTrusted); }
private static DistributedTracePayload BuildSampleDistributedTracePayload() { return(DistributedTracePayload.TryBuildOutgoingPayload( Type.ToString(), AccountId, AppId, Guid, TraceId, TrustKey, Priority, Sampled, Timestamp, TransactionId)); }
public void DistributedTracePayloadWithZeroBasedTimestampThrows() { var type = "App"; var accountId = "12345"; var appId = "1111"; var parentId = $"{0xfffffffffffffffful:X9}"; var guid = $"{0xfffffffffffffffful:X9}"; var traceId = $"{0xfffffffffffffffful:X9}"; var trustKey = "56789"; var priority = 0f; var sampled = true; var time = new int[] { 1970, 1, 1, 0, 0, 0 }; var timestamp = new DateTime(time[0], time[1], time[2], time[3], time[4], time[5], DateTimeKind.Utc); var transactionId = $"{0xfffffffffffffffful:X9}"; var input = DistributedTracePayload.TryBuildOutgoingPayload(type, accountId, appId, $"{guid:X8}", $"{traceId:X8}", trustKey, priority, sampled, timestamp, transactionId); var serialized = input.ToJson(); Assert.Throws <DistributedTraceAcceptPayloadParseException>(() => DistributedTracePayload.TryBuildIncomingPayloadFromJson(serialized)); }
public void AcceptDistributedTraceHeadersHydratesValidNewRelicPayload() { var encodedPayload = DistributedTracePayload.SerializeAndEncodeDistributedTracePayload(BuildSampleDistributedTracePayload()); var headers = new Dictionary <string, string>() { { NewRelicPayloadHeaderName, encodedPayload } }; var tracingState = TracingState.AcceptDistributedTraceHeaders(carrier: headers, getter: GetHeader, transportType: TransportType.AMQP, agentTrustKey: TrustKey, transactionStartTime: DateTime.UtcNow.Add(TimeSpan.FromMilliseconds(1))); Assert.IsNotNull(tracingState); Assert.AreEqual(Type, tracingState.Type); Assert.AreEqual(AccountId, tracingState.AccountId); Assert.AreEqual(AppId, tracingState.AppId); Assert.AreEqual(Guid, tracingState.Guid); Assert.AreEqual(TraceId, tracingState.TraceId); Assert.AreEqual(Priority, tracingState.Priority); Assert.AreEqual(Sampled, tracingState.Sampled); Assert.AreEqual(TransactionId, tracingState.TransactionId); Assert.IsTrue(tracingState.Timestamp != default, $"Timestamp should not be {(DateTime)default}");
public void OneTimeSetUp() { // type, accountId, appId, guid, traceId, trustKey, priority, sampled, timestamp, transactionId _dtPayload = new DistributedTracePayload { Type = "App", AccountId = "test-accountid", AppId = "test-appid", Guid = "test-guid", TraceId = "test-traceid", TrustKey = "test-trustkey", Priority = 1.0F, Sampled = true, Timestamp = DateTime.Now, TransactionId = "test-transactionid" }; _tags = new Dictionary <string, string> { { "newrelic", _dtPayload.SerializeAndEncodeDistributedTracePayload() } }; }
public void Inject <TCarrier>(ISpanContext spanContext, IFormat <TCarrier> format, TCarrier carrier) { var context = (LambdaSpanContext)spanContext; var span = context.GetSpan(); var payload = DistributedTracePayload.TryBuildOutgoingPayload( type: "App", accountId: AccountId, appId: PrimaryApplicationId, guid: span.Guid(), traceId: span.RootSpan.DistributedTracingState.InboundPayload?.TraceId ?? span.RootSpan.TransactionState.TransactionId, trustKey: TrustedAccountKey, priority: span.RootSpan.PrioritySamplingState.Priority, sampled: span.RootSpan.PrioritySamplingState.Sampled, timestamp: span.TimeStamp.DateTime, transactionId: span.RootSpan.TransactionState.TransactionId ); // If we couldnt build a payload just return if (payload == null) { return; } if (format.Equals(BuiltinFormats.TextMap)) { // "text" version of payload ((ITextMap)carrier).Set(NEWRELIC_TRACE_HEADER, payload.ToJson()); } else if (format.Equals(BuiltinFormats.HttpHeaders)) { // "httpSafe" version of payload ((ITextMap)carrier).Set(NEWRELIC_TRACE_HEADER, payload.SerializeAndEncodeDistributedTracePayload()); } //else if (format.Equals(BuiltinFormats.Binary)) //{ // var payloadBytes = Encoding.UTF8.GetBytes(payload.ToJson()); // ((MemoryStream)carrier).Write(payloadBytes, 0, payloadBytes.Length); //} }
public ISpanContext Extract <TCarrier>(IFormat <TCarrier> format, TCarrier carrier) { var payload = GetPayloadString(format, carrier); if (string.IsNullOrEmpty(payload)) { return(null); } var distributedTracePayload = DistributedTracePayload.TryDecodeAndDeserializeDistributedTracePayload(payload); if (distributedTracePayload == null) { var message = $"{NEWRELIC_TRACE_HEADER} header value was not accepted."; _logger.Log(message, false, "ERROR"); throw new ArgumentNullException(message); } var transportDurationInMillis = (DateTimeOffset.UtcNow - distributedTracePayload.Timestamp).TotalMilliseconds; return(new LambdaPayloadContext(distributedTracePayload, transportDurationInMillis)); }
public DistributedTracePayload TryDecodeInboundSerializedDistributedTracePayload(string serializedPayload) { DistributedTracePayload payload = null; try { payload = DistributedTracePayload.TryDecodeAndDeserializeDistributedTracePayload(serializedPayload); } catch (DistributedTraceAcceptPayloadVersionException) { _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadIgnoredMajorVersion(); } catch (DistributedTraceAcceptPayloadNullException) { _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadIgnoredNull(); } catch (DistributedTraceAcceptPayloadParseException) { _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadParseException(); } catch (Exception) { _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadException(); } if (!IsValidPayload(payload)) { return(null); } if (_configurationService.Configuration.PayloadSuccessMetricsEnabled) { _agentHealthReporter.ReportSupportabilityDistributedTraceAcceptPayloadSuccess(); } return(payload); }
private static void TestPayloadInfoMatchesSpanInfo(DistributedTracePayload payload, ISpanEventWireModel rootSpan, ISpanEventWireModel actualSpan) { Assert.NotNull(rootSpan); var rootSpanIntrinsicAttributes = rootSpan.IntrinsicAttributes(); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.TraceId, rootSpanIntrinsicAttributes["traceId"])); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.Priority, rootSpanIntrinsicAttributes["priority"])); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.Sampled, rootSpanIntrinsicAttributes["sampled"])); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.Guid, rootSpanIntrinsicAttributes["parentId"])); Assert.IsTrue(AttributeComparer.IsEqualTo("generic", rootSpanIntrinsicAttributes["category"])); Assert.IsTrue(AttributeComparer.IsEqualTo(true, rootSpanIntrinsicAttributes["nr.entryPoint"])); Assert.NotNull(actualSpan); var actualSpanIntrinsicAttributes = actualSpan.IntrinsicAttributes(); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.TraceId, actualSpanIntrinsicAttributes["traceId"])); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.Priority, actualSpanIntrinsicAttributes["priority"])); Assert.IsTrue(AttributeComparer.IsEqualTo(payload.Sampled, actualSpanIntrinsicAttributes["sampled"])); Assert.IsTrue(AttributeComparer.IsEqualTo(rootSpanIntrinsicAttributes["guid"], actualSpanIntrinsicAttributes["parentId"])); Assert.IsTrue(AttributeComparer.IsEqualTo(rootSpanIntrinsicAttributes["transactionId"], actualSpanIntrinsicAttributes["transactionId"])); Assert.IsTrue(AttributeComparer.IsEqualTo("datastore", actualSpanIntrinsicAttributes["category"])); }
public void SetInboundDistributedTracePayload(DistributedTracePayload payload) { InboundPayload = payload; }
public void DistributedTracePayload_OptionalAndRequired(string json, IConstraint constraint) { Assert.That(() => DistributedTracePayload.TryBuildIncomingPayloadFromJson(json), constraint); }
public void BuildOutgoingPayload_ReturnsNull_WhenRequiredFieldsNotPresent(string type, string accountId, string appId, string traceId) { var payload = DistributedTracePayload.TryBuildOutgoingPayload(type, accountId, appId, Guid, traceId, TrustKey, Priority, Sampled, Timestamp, TransactionId); Assert.Null(payload); }
public LambdaPayloadContext(DistributedTracePayload payload, double transportDurationInMillis) { _payload = payload; _transportDurationInMillis = transportDurationInMillis; }
private IDistributedTracePayload TryGetOutboundDistributedTraceApiModelInternal(IInternalTransaction transaction, ISegment segment, DateTime timestamp) { var accountId = _configurationService.Configuration.AccountId; var appId = _configurationService.Configuration.PrimaryApplicationId; if (!_configurationService.Configuration.SpanEventsEnabled && !_configurationService.Configuration.TransactionEventsEnabled) { Log.Finest("Did not generate payload because Span Events and Transaction Events were both disabled, preventing a traceable payload."); return(DistributedTraceApiModel.EmptyModel); } transaction.SetSampled(_adaptiveSampler); var transactionIsSampled = transaction.Sampled; if (transactionIsSampled.HasValue == false) { Log.Error("Did not generate payload because transaction sampled value was null."); return(DistributedTraceApiModel.EmptyModel); } var payloadGuid = _configurationService.Configuration.SpanEventsEnabled ? segment?.SpanId : null; var trustKey = _configurationService.Configuration.TrustedAccountKey; var transactionId = (_configurationService.Configuration.TransactionEventsEnabled) ? transaction.Guid : null; var traceId = transaction.TraceId; var distributedTracePayload = DistributedTracePayload.TryBuildOutgoingPayload( DistributedTraceTypeDefault, accountId, appId, payloadGuid, traceId, trustKey, transaction.Priority, transactionIsSampled, timestamp, transactionId); if (distributedTracePayload == null) { return(DistributedTraceApiModel.EmptyModel); } string encodedPayload; try { encodedPayload = DistributedTracePayload.SerializeAndEncodeDistributedTracePayload(distributedTracePayload); } catch (Exception ex) { Log.Error($"Failed to get encoded distributed trace headers for outbound request: {ex}"); _agentHealthReporter.ReportSupportabilityDistributedTraceCreatePayloadException(); return(DistributedTraceApiModel.EmptyModel); } transaction.TransactionMetadata.HasOutgoingTraceHeaders = true; if (_configurationService.Configuration.PayloadSuccessMetricsEnabled) { _agentHealthReporter.ReportSupportabilityDistributedTraceCreatePayloadSuccess(); } return(new DistributedTraceApiModel(encodedPayload)); }