Пример #1
0
        public void GetSpanEvent_Generates_ExpecedErrorAttribute(bool hasExpectedError)
        {
            // ARRANGE
            var testError = new ErrorData("error message", "ErrorType", "stack trace", DateTime.UtcNow, null, hasExpectedError);
            var segments  = new List <Segment>()
            {
                _baseGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };

            segments[0].ErrorData = testError;
            var immutableTransaction  = BuildTestTransaction(segments, sampled: true, hasIncomingPayload: true);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttributes = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents    = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttributes).ToList();
            var rootSpanEvent = spanEvents[0];
            var spanEvent     = spanEvents[1];

            // ASSERT
            if (hasExpectedError)
            {
                CollectionAssert.Contains(rootSpanEvent.AgentAttributes().Keys, "error.expected");
                Assert.AreEqual(true, rootSpanEvent.AgentAttributes()["error.expected"]);
                CollectionAssert.Contains(spanEvent.AgentAttributes().Keys, "error.expected");
                Assert.AreEqual(true, spanEvent.AgentAttributes()["error.expected"]);
            }
            else
            {
                CollectionAssert.DoesNotContain(rootSpanEvent.AgentAttributes().Keys, "error.expected");
                CollectionAssert.DoesNotContain(spanEvent.AgentAttributes().Keys, "error.expected");
            }
        }
Пример #2
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_W3CAttributes()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };

            var immutableTransaction = new ImmutableTransactionBuilder()
                                       .WithW3CTracing(DistributedTraceGuid, W3cParentId, VendorStateEntries)
                                       .Build();

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);


            // ACT
            var spanEvents    = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent     = spanEvents.ToList()[1];
            var rootSpanEvent = spanEvents.ToList()[0];

            // ASSERT
            Assert.AreEqual(W3cParentId, (string)rootSpanEvent.IntrinsicAttributes()["parentId"]);
            Assert.AreEqual(DistributedTraceGuid, (string)rootSpanEvent.IntrinsicAttributes()["trustedParentId"]);
            Assert.AreEqual($"{Vendor1},{Vendor2}", (string)rootSpanEvent.IntrinsicAttributes()["tracingVendors"]);
        }
Пример #3
0
        public void GetSpanEvent_DoesNotIncludesErrorAttributes_WhenThereIsAnError_IfErrorCollectionIsDisabled()
        {
            // ARRANGE
            _localConfig.errorCollector.enabled = false;
            PublishConfig();
            var testError = new ErrorData("error message", "ErrorType", "stack trace", DateTime.UtcNow, null, false);
            var segments  = new List <Segment>()
            {
                _baseGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };

            segments[0].ErrorData = testError;
            var immutableTransaction  = BuildTestTransaction(segments, sampled: true, hasIncomingPayload: true);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttributes = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents           = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttributes).ToList();
            var spanEvent            = spanEvents[1];
            var rootSpanEvent        = spanEvents[0];
            var errorEventAttributes = new AttributeValueCollection(transactionAttributes, AttributeDestinations.ErrorEvent);

            // ASSERT
            NrAssert.Multiple(
                () => CollectionAssert.DoesNotContain(errorEventAttributes.GetAttributeValuesDic(AttributeClassification.Intrinsics).Keys, "spanId"),
                () => CollectionAssert.DoesNotContain(spanEvent.AgentAttributes().Keys, "error.class"),
                () => CollectionAssert.DoesNotContain(rootSpanEvent.AgentAttributes().Keys, "error.class")
                );
        }
Пример #4
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_ValidateChildValues()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
                _childGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };

            var immutableTransaction  = BuildTestTransaction(segments, true, false);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent  = spanEvents.ToList()[2]; // look at child span only since it has all the values
            var spanEventIntrinsicAttributes = spanEvent.IntrinsicAttributes();

            // ASSERT
            Assert.AreEqual("Span", (string)spanEventIntrinsicAttributes["type"]);
            Assert.AreEqual(DistributedTraceTraceId, (string)spanEventIntrinsicAttributes["traceId"]);
            Assert.AreEqual(_childGenericSegment.SpanId, (string)spanEventIntrinsicAttributes["guid"]);
            Assert.AreEqual(_baseGenericSegment.SpanId, (string)spanEventIntrinsicAttributes["parentId"]);
            Assert.AreEqual(_transactionGuid, (string)spanEventIntrinsicAttributes["transactionId"]);
            Assert.AreEqual(true, (bool)spanEventIntrinsicAttributes["sampled"]);
            Assert.AreEqual(Priority, (double)spanEventIntrinsicAttributes["priority"]);
            Assert.AreEqual(1531897200001, (long)spanEventIntrinsicAttributes["timestamp"]);
            Assert.AreEqual(0.005, (double)spanEventIntrinsicAttributes["duration"]);
            Assert.AreEqual(SegmentName, (string)spanEventIntrinsicAttributes["name"]);
            Assert.AreEqual(GenericCategory, (string)spanEventIntrinsicAttributes["category"]);
            Assert.False(spanEventIntrinsicAttributes.ContainsKey("nr.entryPoint"));
        }
        public void TransformSegment_TwoTransformCallsSame()
        {
            const string vendor      = "vendor1";
            const string destination = "queueA";
            const MetricNames.MessageBrokerDestinationType destinationType = MetricNames.MessageBrokerDestinationType.Queue;
            const MetricNames.MessageBrokerAction          action          = MetricNames.MessageBrokerAction.Consume;
            var segment = GetSegment(vendor, destinationType, destination, action);
            TransactionMetricName            txName  = new TransactionMetricName("WebTransaction", "Test", false);
            TransactionMetricStatsCollection txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);

            segment.AddMetricStats(txStats, _configurationService);

            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            Assert.AreEqual(1, scoped.Count);
            Assert.AreEqual(1, unscoped.Count);
            const string metricName = "MessageBroker/vendor1/Queue/Consume/Named/queueA";


            Assert.IsTrue(scoped.ContainsKey(metricName));
            Assert.IsTrue(unscoped.ContainsKey(metricName));

            var nameScoped   = scoped[metricName];
            var nameUnscoped = unscoped[metricName];

            Assert.AreEqual(2, nameScoped.Value0);
            Assert.AreEqual(2, nameUnscoped.Value0);
        }
Пример #6
0
        public void GetTransactionEvent_ReturnsCorrectDistributedTraceAttributes()
        {
            // ARRANGE

            Mock.Arrange(() => _configurationService.Configuration.DistributedTracingEnabled).Returns(true);

            var immutableTransaction = BuildTestImmutableTransaction(sampled: true, guid: "guid", isDTParticipant: _configurationService.Configuration.DistributedTracingEnabled);

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var txStats    = new TransactionMetricStatsCollection(transactionMetricName);
            var attributes = _transactionAttributeMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15), txStats);

            // ACT
            var transactionEvent    = _transactionEventMaker.GetTransactionEvent(immutableTransaction, attributes);
            var intrinsicAttributes = transactionEvent.IntrinsicAttributes();

            // ASSERT
            NrAssert.Multiple(
                //Test Change:  Moved from 19->18, missing attribute is transactionName which belongs to error events.
                () => Assert.AreEqual(18, intrinsicAttributes.Count, "intrinsicAttributes.Count"),
                () => Assert.Contains("guid", intrinsicAttributes.Keys.ToArray(), "IntrinsicAttributes.Keys.Contains('guid')"),
                () => Assert.AreEqual(immutableTransaction.TracingState.Type.ToString(), intrinsicAttributes["parent.type"], "parent.type"),
                () => Assert.AreEqual(immutableTransaction.TracingState.AppId, intrinsicAttributes["parent.app"], "parent.app"),
                () => Assert.AreEqual(immutableTransaction.TracingState.AccountId, intrinsicAttributes["parent.account"], "parent.account"),
                () => Assert.AreEqual(EnumNameCache <TransportType> .GetName(immutableTransaction.TracingState.TransportType), intrinsicAttributes["parent.transportType"], "parent.transportType"),
                () => Assert.AreEqual(immutableTransaction.TracingState.TransportDuration.TotalSeconds, (double)intrinsicAttributes["parent.transportDuration"], 0.000001d, "parent.transportDuration"),
                () => Assert.AreEqual(immutableTransaction.TracingState.TransactionId, intrinsicAttributes["parentId"], "parentId"),
                () => Assert.AreEqual(immutableTransaction.TracingState.ParentId, intrinsicAttributes["parentSpanId"], "parentSpanId"),
                () => Assert.AreEqual(immutableTransaction.TraceId, intrinsicAttributes["traceId"], "traceId"),
                () => Assert.AreEqual(immutableTransaction.Priority, intrinsicAttributes["priority"], "priority"),
                () => Assert.AreEqual(immutableTransaction.Sampled, intrinsicAttributes["sampled"], "sampled")
                );
        }
        public void TransformSegment_TwoTransformCallsSame()
        {
            const string type    = "type";
            const string method  = "method";
            var          segment = GetSegment(type, method);;

            var txName  = new TransactionMetricName("WebTransaction", "Test", false);
            var txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);
            segment.AddMetricStats(txStats, _configurationService);

            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            Assert.AreEqual(1, scoped.Count);
            Assert.AreEqual(1, unscoped.Count);

            const string metricName = "DotNet/type/method";

            Assert.IsTrue(scoped.ContainsKey(metricName));
            Assert.IsTrue(unscoped.ContainsKey(metricName));

            var nameScoped   = scoped[metricName];
            var nameUnscoped = unscoped[metricName];

            Assert.AreEqual(2, nameScoped.Value0);
            Assert.AreEqual(2, nameUnscoped.Value0);
        }
Пример #8
0
        public void RootSpanEventHasTransactionNameSpecialSpanAttrib()
        {
            var segments = new List <Segment>()
            {
                _baseDatastoreSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
            };

            var immutableTransaction = BuildTestTransaction(segments, true, false);

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var rootSpan   = spanEvents.ToList()[0];

            var rootSpanIntrinsicsDic = rootSpan.GetAttributeValuesDic(AttributeClassification.Intrinsics);

            NrAssert.Multiple
            (
                () => Assert.IsTrue(rootSpanIntrinsicsDic.ContainsKey("transaction.name")),
                () => Assert.AreEqual(transactionMetricName.PrefixedName, rootSpanIntrinsicsDic["transaction.name"])
            );
        }
Пример #9
0
        public void AddMetricStats(TransactionMetricStatsCollection txStats, IConfigurationService configService)
        {
            if (!Duration.HasValue || txStats == null)
            {
                return;
            }

            Data.AddMetricStats(this, TotalChildDuration, txStats, configService);
        }
Пример #10
0
        public void RootSpanEventHasTransactionsUserAndAgentAttributes([Values(true, false)] bool transactionEventsEnabled)
        {
            _localConfig.transactionEvents.enabled = false;

            PublishConfig();


            var segments = new List <Segment>()
            {
                _baseDatastoreSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
            };

            var immutableTransaction = BuildTestTransaction(segments, true, false);

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var allAttribValues       = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            _attribDefs.GetCustomAttributeForTransaction("trxCustomAttrib").TrySetValue(allAttribValues, "trxCustomAttribValue");
            _attribDefs.OriginalUrl.TrySetValue(allAttribValues, "http://www.test.com");

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, allAttribValues);
            var rootSpan   = spanEvents.ToList()[0];

            var assertions = new List <Action>();

            foreach (var classification in new[] { AttributeClassification.AgentAttributes, AttributeClassification.UserAttributes })
            {
                var classificationLocal = classification;
                var trxAttribs          = allAttribValues.GetAttributeValues(classification);
                var rootSpanAttribsDic  = rootSpan.GetAttributeValuesDic(classification);

                var hasExistCheck = false;

                foreach (var trxAttrib in trxAttribs)
                {
                    var attribName = trxAttrib.AttributeDefinition.Name;

                    if (trxAttrib.AttributeDefinition.IsAvailableForAny(AttributeDestinations.SpanEvent))
                    {
                        hasExistCheck = true;
                        assertions.Add(() => Assert.IsTrue(rootSpanAttribsDic.ContainsKey(attribName), $"{classificationLocal} attributes should have attribute {attribName}"));
                        assertions.Add(() => Assert.AreEqual(trxAttrib.Value, rootSpanAttribsDic[attribName], $"{classificationLocal} attribute '{attribName}'"));
                    }
                    else
                    {
                        assertions.Add(() => Assert.IsFalse(rootSpanAttribsDic.ContainsKey(attribName), $"{classificationLocal} attributes should have attribute {attribName}"));
                    }
                }

                assertions.Add(() => Assert.IsTrue(hasExistCheck, $"Didn't validate existence of any {classificationLocal} attrib on root span"));
            }

            NrAssert.Multiple(assertions.ToArray());
        }
Пример #11
0
        public void TransformSegment_CreatesNullModelSegmentMetrics()
        {
            var wrapperVendor = Extensions.Providers.Wrapper.DatastoreVendor.MSSQL;
            var model         = null as string;
            var operation     = "INSERT";

            var segment = GetSegment(wrapperVendor, operation, model, 5);


            var txName  = new TransactionMetricName("WebTransaction", "Test", false);
            var txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);


            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            Assert.AreEqual(1, scoped.Count);
            Assert.AreEqual(5, unscoped.Count);

            //no statement metric for null model
            const string statementMetric = "Datastore/statement/MSSQL/MY_TABLE/INSERT";
            const string operationMetric = "Datastore/operation/MSSQL/INSERT";

            Assert.IsTrue(unscoped.ContainsKey("Datastore/all"));
            Assert.IsTrue(unscoped.ContainsKey("Datastore/allWeb"));
            Assert.IsTrue(unscoped.ContainsKey("Datastore/MSSQL/all"));
            Assert.IsTrue(unscoped.ContainsKey("Datastore/MSSQL/allWeb"));
            Assert.IsFalse(unscoped.ContainsKey(statementMetric));
            Assert.IsTrue(unscoped.ContainsKey(operationMetric));

            Assert.IsTrue(scoped.ContainsKey(operationMetric));

            var data = scoped[operationMetric];

            Assert.AreEqual(1, data.Value0);
            Assert.AreEqual(5, data.Value1);
            Assert.AreEqual(5, data.Value2);
            Assert.AreEqual(5, data.Value3);
            Assert.AreEqual(5, data.Value4);

            var unscopedMetricsWithExclusiveTime = new string[] { operationMetric, "Datastore/all", "Datastore/allWeb", "Datastore/MSSQL/all", "Datastore/MSSQL/allWeb" };

            foreach (var current in unscopedMetricsWithExclusiveTime)
            {
                data = unscoped[current];
                Assert.AreEqual(1, data.Value0);
                Assert.AreEqual(5, data.Value1);
                Assert.AreEqual(5, data.Value2);
                Assert.AreEqual(5, data.Value3);
                Assert.AreEqual(5, data.Value4);
            }
        }
        public void TransformSegment_NullTransactionStats()
        {
            const string vendor      = "vendor1";
            const string destination = "queueA";
            const MetricNames.MessageBrokerDestinationType destinationType = MetricNames.MessageBrokerDestinationType.Queue;
            const MetricNames.MessageBrokerAction          action          = MetricNames.MessageBrokerAction.Consume;
            var segment = GetSegment(vendor, destinationType, destination, action);
            TransactionMetricName            txName  = new TransactionMetricName("WebTransaction", "Test", false);
            TransactionMetricStatsCollection txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);
        }
Пример #13
0
        public void GetTransactionEvent_ReturnsCorrectAttributes()
        {
            // ARRANGE
            var transaction = BuildTestTransaction(statusCode: 200, uri: "http://foo.com");

            transaction.AddCustomAttribute("foo", "bar");
            var errorData = MakeErrorData();

            transaction.TransactionMetadata.TransactionErrorState.AddCustomErrorData(errorData);

            var immutableTransaction  = transaction.ConvertToImmutableTransaction();
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var txStats    = new TransactionMetricStatsCollection(transactionMetricName);
            var attributes = _transactionAttributeMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15), txStats);

            // ACT
            var transactionEvent    = _transactionEventMaker.GetTransactionEvent(immutableTransaction, attributes);
            var agentAttributes     = transactionEvent.AgentAttributes();
            var intrinsicAttributes = transactionEvent.IntrinsicAttributes();
            var userAttributes      = transactionEvent.UserAttributes();

            // Change Notes
            // Originally the test was looking for 29 attribute values.  These are not yet filtered, even though they are attacched to
            // the transaction event.  The equivalent here is the 'attributes' value, which is not filtered.  It has 31 attributes.
            // The two extra are type and timestamp for error events.


            var unfilteredIntrinsicsDic = attributes.GetAttributeValues(AttributeClassification.Intrinsics)
                                          .Where(x => x.AttributeDefinition.IsAvailableForAny(AttributeDestinations.TransactionEvent))
                                          .GroupBy(x => x.AttributeDefinition)
                                          .ToDictionary(x => x.Key, x => x.Last());

            var filteredIntrinsicsDic = transactionEvent.AttributeValues.GetAttributeValues(AttributeClassification.Intrinsics)
                                        .GroupBy(x => x.AttributeDefinition)
                                        .ToDictionary(x => x.Key, x => x.Last());

            // ASSERT
            NrAssert.Multiple(
                () => CollectionAssert.AreEquivalent(unfilteredIntrinsicsDic.Keys, filteredIntrinsicsDic.Keys),
                () => Assert.AreEqual(19, intrinsicAttributes.Count),
                () => Assert.AreEqual("Transaction", intrinsicAttributes["type"]),
                () => Assert.AreEqual(4, agentAttributes.Count),
                () => Assert.AreEqual("200", agentAttributes["response.status"]),
                () => Assert.AreEqual(200, agentAttributes["http.statusCode"]),
                () => Assert.AreEqual("http://foo.com", agentAttributes["request.uri"]),
                () => Assert.IsTrue(agentAttributes.ContainsKey("host.displayName")),
                () => Assert.AreEqual(1, userAttributes.Count),
                () => Assert.AreEqual("bar", userAttributes["foo"])
                //This should be on the error event
                //() => Assert.AreEqual("baz", userAttributes["fiz"])
                );
        }
Пример #14
0
        public void GetTransactionEvent_ReturnsSyntheticEvent()
        {
            // ARRANGE
            var transaction = BuildTestTransaction(isSynthetics: true);

            var immutableTransaction  = transaction.ConvertToImmutableTransaction();
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var txStats    = new TransactionMetricStatsCollection(transactionMetricName);
            var attributes = _transactionAttributeMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15), txStats);

            // ACT
            var transactionEvent = _transactionEventMaker.GetTransactionEvent(immutableTransaction, attributes);

            // ASSERT
            Assert.NotNull(transactionEvent);
            Assert.IsTrue(transactionEvent.IsSynthetics);
        }
Пример #15
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_HttpCategory()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseHttpSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };
            var immutableTransaction  = BuildTestTransaction(segments, true, false);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent  = spanEvents.ToList()[1];

            // ASSERT
            Assert.AreEqual(HttpCategory, (string)spanEvent.IntrinsicAttributes()["category"]);
        }
Пример #16
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_NoHttpStatusCode()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseHttpSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };
            var immutableTransaction  = BuildTestTransaction(segments, true, false);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent  = spanEvents.ToList()[1];

            // ASSERT
            CollectionAssert.DoesNotContain(spanEvent.AgentAttributes().Keys, "http.statusCode");
        }
Пример #17
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_DatastoreTruncateLongStatement()
        {
            var customerStmt = new string[]
            {
                new string('U', 2015),                          //1-byte per char
                new string('仮', 1015)                           //3-bytes per char
            };

            var expectedStmtTrunc = new string[]
            {
                new string('U', 1996) + "...",          //1-byte per char
                new string('仮', 666) + "..."            //3-bytes per char
            };

            for (int i = 0; i < customerStmt.Length; i++)
            {
                // ARRANGE
                var longSqlStatement     = new ParsedSqlStatement(DatastoreVendor.MSSQL, customerStmt[i], "select");
                var longDatastoreSegment = new Segment(CreateTransactionSegmentState(3, null, 777), new MethodCallData(MethodCallType, MethodCallMethod, 1));
                longDatastoreSegment.SetSegmentData(new DatastoreSegmentData(_databaseService, longSqlStatement, customerStmt[i], _connectionInfo));

                var segments = new List <Segment>()
                {
                    longDatastoreSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
                };
                var immutableTransaction  = BuildTestTransaction(segments, true, false);
                var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
                var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
                var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

                // ACT
                var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
                var spanEvent  = spanEvents.ToList()[1];

                // ASSERT
                var attribStatement    = (string)spanEvent.AgentAttributes()["db.statement"];
                var attribStmtLenBytes = Encoding.UTF8.GetByteCount(attribStatement);

                Assert.AreEqual(expectedStmtTrunc[i], attribStatement);
                Assert.True(attribStmtLenBytes <= 1999);
                Assert.True(attribStmtLenBytes >= 1996);
            }
        }
        public void GetErrorEvent_InTransaction_WithException_ContainsCorrectAttributes()
        {
            var transaction = BuildTestTransaction(statusCode: 404, uri: "http://www.newrelic.com/test?param=value", isSynthetics: false, isCAT: false, referrerUri: "http://referrer.uri");

            transaction.NoticeError(new OutOfMemoryException("Out of Memory Message"));
            var immutableTransaction = transaction.ConvertToImmutableTransaction();

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var txStats = new TransactionMetricStatsCollection(transactionMetricName);

            var attributes = _transactionAttributeMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(10),
                                                                      TimeSpan.FromSeconds(15), txStats);

            var errorEvent = _errorEventMaker.GetErrorEvent(immutableTransaction, attributes);

            var intrinsicAttributes = errorEvent.IntrinsicAttributes().Keys.ToArray();
            var agentAttributes     = errorEvent.AgentAttributes().Keys.ToArray();
            var userAttributes      = errorEvent.UserAttributes().Keys.ToArray();

            NrAssert.Multiple(
                () => Assert.AreEqual(false, errorEvent.IsSynthetics),
                () => Assert.AreEqual(7, agentAttributes.Length),
                () => Assert.AreEqual(7, intrinsicAttributes.Length),
                () => Assert.AreEqual(0, userAttributes.Length),

                () => Assert.Contains("queue_wait_time_ms", agentAttributes),
                () => Assert.Contains("response.status", agentAttributes),
                () => Assert.Contains("original_url", agentAttributes),
                () => Assert.Contains("request.uri", agentAttributes),
                () => Assert.Contains("http.statusCode", agentAttributes),
                () => Assert.Contains("request.referer", agentAttributes),
                () => Assert.Contains("host.displayName", agentAttributes),

                () => Assert.Contains("duration", intrinsicAttributes),
                () => Assert.Contains("error.class", intrinsicAttributes),
                () => Assert.Contains("error.message", intrinsicAttributes),
                () => Assert.Contains("queueDuration", intrinsicAttributes),
                () => Assert.Contains("transactionName", intrinsicAttributes),
                () => Assert.Contains("timestamp", intrinsicAttributes),
                () => Assert.Contains("type", intrinsicAttributes)
                );
        }
        public void TransformSegment_TwoTransformCallsDifferent()
        {
            const string name    = "name";
            var          segment = GetSegment(name);

            const string name1    = "otherName";
            var          segment1 = GetSegment(name1);

            var txName  = new TransactionMetricName("WebTransaction", "Test", false);
            var txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);
            segment1.AddMetricStats(txStats, _configurationService);

            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            Assert.AreEqual(2, scoped.Count);
            Assert.AreEqual(2, unscoped.Count);

            const string metricName = "DotNet/name";

            Assert.IsTrue(scoped.ContainsKey(metricName));
            Assert.IsTrue(unscoped.ContainsKey(metricName));

            var nameScoped   = scoped[metricName];
            var nameUnscoped = unscoped[metricName];

            Assert.AreEqual(1, nameScoped.Value0);
            Assert.AreEqual(1, nameUnscoped.Value0);

            const string metricName1 = "DotNet/otherName";

            Assert.IsTrue(scoped.ContainsKey(metricName1));
            Assert.IsTrue(unscoped.ContainsKey(metricName1));

            nameScoped   = scoped[metricName1];
            nameUnscoped = unscoped[metricName1];

            Assert.AreEqual(1, nameScoped.Value0);
            Assert.AreEqual(1, nameUnscoped.Value0);
        }
        public void TransformSegment_CreatesWebWithCat()
        {
            const string host   = "www.bar.com";
            var          uri    = $"http://{host}/foo";
            const string method = "GET";
            var          externalCrossProcessId  = "cpId";
            var          externalTransactionName = "otherTxName";
            var          catResponseData         = new CrossApplicationResponseData(externalCrossProcessId, externalTransactionName, 1.1f, 2.2f, 3, "guid", false);

            var segment = GetSegment(uri, method, catResponseData);


            var txName  = new TransactionMetricName("WebTransaction", "Test", false);
            var txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);

            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            Assert.AreEqual(1, scoped.Count);
            Assert.AreEqual(6, unscoped.Count);

            const string segmentMetric = "External/www.bar.com/Stream/GET";
            const string txMetric      = "ExternalTransaction/www.bar.com/cpId/otherTxName";

            Assert.IsTrue(unscoped.ContainsKey("External/all"));
            Assert.IsTrue(unscoped.ContainsKey("External/allWeb"));
            Assert.IsTrue(unscoped.ContainsKey("External/www.bar.com/all"));
            Assert.IsTrue(unscoped.ContainsKey(segmentMetric));
            Assert.IsTrue(unscoped.ContainsKey(txMetric));
            Assert.IsTrue(unscoped.ContainsKey("ExternalApp/www.bar.com/cpId/all"));

            Assert.IsFalse(scoped.ContainsKey(segmentMetric));
            Assert.IsTrue(scoped.ContainsKey(txMetric));

            var nameScoped   = scoped[txMetric];
            var nameUnscoped = unscoped[txMetric];

            Assert.AreEqual(1, nameScoped.Value0);
            Assert.AreEqual(1, nameUnscoped.Value0);
        }
Пример #21
0
        public void RootSpanAttribFiltering_SpanFiltersIndependentOfTransactionFilters()
        {
            _localConfig.transactionEvents.attributes.exclude = new List <string> {
                "filterOnTrx*"
            };
            _localConfig.spanEvents.attributes.exclude = new List <string> {
                "filterOnSpan*"
            };

            PublishConfig();

            var segments = new List <Segment>()
            {
                _baseDatastoreSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
            };

            var immutableTransaction = BuildTestTransaction(segments, true, false);

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            _attribDefs.GetCustomAttributeForTransaction("filterOnTrx").TrySetValue(transactionAttribs, "trxCustomAttribValue1");
            _attribDefs.GetCustomAttributeForTransaction("filterOnSpan").TrySetValue(transactionAttribs, "trxCustomAttribValue2");

            var trxEvent   = _transactionEventMaker.GetTransactionEvent(immutableTransaction, transactionAttribs);
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);

            var rootSpan = spanEvents.ToList()[0];

            var rootSpanUserAttribDic = rootSpan.GetAttributeValuesDic(AttributeClassification.UserAttributes);
            var trxUserAttribDic      = trxEvent.AttributeValues.GetAttributeValuesDic(AttributeClassification.UserAttributes);

            NrAssert.Multiple
            (
                () => Assert.IsFalse(trxUserAttribDic.ContainsKey("filterOnTrx")),
                () => Assert.IsTrue(trxUserAttribDic.ContainsKey("filterOnSpan")),

                () => Assert.IsTrue(rootSpanUserAttribDic.ContainsKey("filterOnTrx")),
                () => Assert.IsFalse(rootSpanUserAttribDic.ContainsKey("filterOnSpan"))
            );
        }
Пример #22
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_ParentIdIsDistributedTraceGuid_FirstSegmentWithPayload()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };
            var immutableTransaction  = BuildTestTransaction(segments, true, true);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents    = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs).ToList();
            var spanEvent     = spanEvents[1];
            var rootSpanEvent = spanEvents[0];

            // ASSERT
            Assert.AreEqual((string)rootSpanEvent.IntrinsicAttributes()["guid"], (string)spanEvent.IntrinsicAttributes()["parentId"]);
        }
Пример #23
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_ValidateCount()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
                _childGenericSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };
            var immutableTransaction = BuildTestTransaction(segments, sampled: true, hasIncomingPayload: false);

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);

            // ASSERT
            // +1 is for the faux root segment.
            Assert.AreEqual(segments.Count + 1, spanEvents.Count());
        }
        public void TransformSegment_CreatesCustomSegmentMetrics()
        {
            const string type    = "type";
            const string method  = "method";
            var          segment = GetSegment(type, method, 5);

            segment.ChildFinished(GetSegment("kid", "method", 2));

            var txName  = new TransactionMetricName("WebTransaction", "Test", false);
            var txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);


            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            Assert.AreEqual(1, scoped.Count);
            Assert.AreEqual(1, unscoped.Count);

            const string metricName = "DotNet/type/method";

            Assert.IsTrue(scoped.ContainsKey(metricName));
            Assert.IsTrue(unscoped.ContainsKey(metricName));

            var data = scoped[metricName];

            Assert.AreEqual(1, data.Value0);
            Assert.AreEqual(5, data.Value1);
            Assert.AreEqual(3, data.Value2);
            Assert.AreEqual(5, data.Value3);
            Assert.AreEqual(5, data.Value4);

            data = unscoped[metricName];
            Assert.AreEqual(1, data.Value0);
            Assert.AreEqual(5, data.Value1);
            Assert.AreEqual(3, data.Value2);
            Assert.AreEqual(5, data.Value3);
            Assert.AreEqual(5, data.Value4);
        }
Пример #25
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_HasHttpStatusCode()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseHttpSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >())
            };
            var externalSegmentData = segments[0].Data as ExternalSegmentData;

            externalSegmentData.SetHttpStatusCode(200);

            var immutableTransaction  = BuildTestTransaction(segments, true, false);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent  = spanEvents.ToList()[1];

            // ASSERT
            Assert.AreEqual(200, spanEvent.AgentAttributes()["http.statusCode"]);
        }
        public void TransformSegment_TwoTransformCallsSame()
        {
            const string name    = "name";
            var          segment = GetSegment(name, 5);

            segment.ChildFinished(GetSegment("kid", 2));

            var txName  = new TransactionMetricName("WebTransaction", "Test", false);
            var txStats = new TransactionMetricStatsCollection(txName);

            segment.AddMetricStats(txStats, _configurationService);
            segment.ChildFinished(GetSegment("kid", 2));
            segment.AddMetricStats(txStats, _configurationService);

            var scoped   = txStats.GetScopedForTesting();
            var unscoped = txStats.GetUnscopedForTesting();

            const string metricName = "Custom/name";

            Assert.IsTrue(scoped.ContainsKey(metricName));
            Assert.IsTrue(unscoped.ContainsKey(metricName));

            var data = scoped[metricName];

            Assert.AreEqual(2, data.Value0);
            Assert.AreEqual(10, data.Value1);
            Assert.AreEqual(4, data.Value2);
            Assert.AreEqual(5, data.Value3);
            Assert.AreEqual(5, data.Value4);

            data = unscoped[metricName];
            Assert.AreEqual(2, data.Value0);
            Assert.AreEqual(10, data.Value1);
            Assert.AreEqual(4, data.Value2);
            Assert.AreEqual(5, data.Value3);
            Assert.AreEqual(5, data.Value4);
        }
        private void Transform(ImmutableTransaction immutableTransaction, TransactionMetricName transactionMetricName)
        {
            if (!immutableTransaction.Segments.Any())
            {
                throw new ArgumentException("Transaction does not have any segments");
            }

            FinishSegments(immutableTransaction.Segments);

            TryGenerateExplainPlans(immutableTransaction.Segments);

            var totalTime = GetTotalExclusiveTime(immutableTransaction.Segments);
            var transactionApdexMetricName = MetricNames.GetTransactionApdex(transactionMetricName);
            var apdexT = GetApdexT(immutableTransaction, transactionMetricName.PrefixedName);

            var txStats = new TransactionMetricStatsCollection(transactionMetricName);

            GenerateAndCollectSqlTrace(immutableTransaction, transactionMetricName, txStats);
            GenerateAndCollectMetrics(immutableTransaction, apdexT, transactionApdexMetricName, totalTime, txStats);

            // defer the creation of attributes until something asks for them.
            Func <IAttributeValueCollection> attributes = () => _transactionAttributeMaker.GetAttributes(immutableTransaction, transactionMetricName, apdexT, totalTime, txStats);

            attributes = attributes.Memoize();

            // Must generate errors first so other wire models get attribute updates
            if (immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
            {
                GenerateAndCollectErrorEventTracesAndEvents(immutableTransaction, attributes.Invoke(), transactionMetricName);
            }

            GenerateAndCollectTransactionEvent(immutableTransaction, attributes);

            GenerateAndCollectTransactionTrace(immutableTransaction, transactionMetricName, attributes);

            GenerateAndCollectSpanEvents(immutableTransaction, transactionMetricName.PrefixedName, attributes);
        }
Пример #28
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_ValidateDatastoreValues()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseDatastoreSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
            };

            var immutableTransaction = BuildTestTransaction(segments, true, false);

            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent  = spanEvents.ToList()[1];
            var spanEventIntrinsicAttributes = spanEvent.IntrinsicAttributes();
            var spanEventAgentAttributes     = spanEvent.AgentAttributes();

            // ASSERT
            NrAssert.Multiple
            (
                () => Assert.AreEqual(DatastoreCategory, (string)spanEventIntrinsicAttributes["category"]),
                () => Assert.AreEqual(DatastoreVendor.MSSQL.ToString(), (string)spanEventIntrinsicAttributes["component"]),
                () => Assert.AreEqual(_parsedSqlStatement.Model, (string)spanEventAgentAttributes["db.collection"]),

                //This also tests the lazy instantiation on span event attrib values
                () => Assert.AreEqual(_obfuscatedSql, (string)spanEventAgentAttributes["db.statement"]),

                () => Assert.AreEqual(_connectionInfo.DatabaseName, (string)spanEventAgentAttributes["db.instance"]),
                () => Assert.AreEqual($"{_connectionInfo.Host}:{_connectionInfo.PortPathOrId}", (string)spanEventAgentAttributes["peer.address"]),
                () => Assert.AreEqual(_connectionInfo.Host, (string)spanEventAgentAttributes["peer.hostname"]),
                () => Assert.AreEqual("client", (string)spanEventIntrinsicAttributes["span.kind"])
            );
        }
Пример #29
0
        public void GetSpanEvent_ReturnsSpanEventPerSegment_ValidateHttpValues()
        {
            // ARRANGE
            var segments = new List <Segment>()
            {
                _baseHttpSegment.CreateSimilar(TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(5), new List <KeyValuePair <string, object> >()),
            };
            var immutableTransaction  = BuildTestTransaction(segments, true, false);
            var transactionMetricName = _transactionMetricNameMaker.GetTransactionMetricName(immutableTransaction.TransactionName);
            var metricStatsCollection = new TransactionMetricStatsCollection(transactionMetricName);
            var transactionAttribs    = _transactionAttribMaker.GetAttributes(immutableTransaction, transactionMetricName, TimeSpan.FromSeconds(1), immutableTransaction.Duration, metricStatsCollection);

            // ACT
            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, TransactionName, transactionAttribs);
            var spanEvent  = spanEvents.ToList()[1];
            var spanEventIntrinsicAttributes = spanEvent.IntrinsicAttributes();
            var spanEventAgentAttributes     = spanEvent.AgentAttributes();

            // ASSERT
            Assert.AreEqual(HttpUri, (string)spanEventAgentAttributes["http.url"]);
            Assert.AreEqual(HttpMethod, (string)spanEventAgentAttributes["http.method"]);
            Assert.AreEqual("type", (string)spanEventIntrinsicAttributes["component"]);
            Assert.AreEqual("client", (string)spanEventIntrinsicAttributes["span.kind"]);
        }
Пример #30
0
        private void SetIntrinsicAttributes(IAttributeValueCollection attribValues, ImmutableTransaction immutableTransaction, TransactionMetricName transactionMetricName, TimeSpan?apdexT, TimeSpan totalTime, TransactionMetricStatsCollection txStats)
        {
            // Required transaction attributes
            _attribDefs.GetTypeAttribute(TypeAttributeValue.Transaction).TrySetDefault(attribValues);
            _attribDefs.Timestamp.TrySetValue(attribValues, immutableTransaction.StartTime);

            _attribDefs.TransactionName.TrySetValue(attribValues, transactionMetricName.PrefixedName);
            _attribDefs.TransactionNameForError.TrySetValue(attribValues, transactionMetricName.PrefixedName);

            // Duration is just EndTime minus StartTime for non-web transactions and response time otherwise
            _attribDefs.Duration.TrySetValue(attribValues, immutableTransaction.ResponseTimeOrDuration);

            // Total time is the total amount of time spent, even when work is happening parallel, which means it is the sum of all exclusive times.
            // https://source.datanerd.us/agents/agent-specs/blob/master/Total-Time-Async.md
            _attribDefs.TotalTime.TrySetValue(attribValues, totalTime);

            // CPU time is the total time spent actually doing work rather than waiting. Basically, it's TotalTime minus TimeSpentWaiting.
            // Our agent does not yet the ability to calculate time spent waiting, so we cannot generate this metric.
            // https://source.datanerd.us/agents/agent-specs/blob/master/Total-Time-Async.md
            //attributes.Add(Attribute.BuildCpuTime(immutableTransaction.Duration));

            // Optional transaction attributes
            _attribDefs.QueueDuration.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.QueueTime);
            _attribDefs.ApdexPerfZone.TrySetValue(attribValues, ApdexStats.GetApdexPerfZoneOrNull(immutableTransaction.ResponseTimeOrDuration, apdexT));


            if (immutableTransaction.IsWebTransaction())
            {
                _attribDefs.WebDuration.TrySetValue(attribValues, immutableTransaction.ResponseTimeOrDuration);
            }

            var externalData = txStats.GetUnscopedStat(MetricNames.ExternalAll);

            if (externalData != null)
            {
                _attribDefs.ExternalDuration.TrySetValue(attribValues, externalData.Value1);
                _attribDefs.ExternalCallCount.TrySetValue(attribValues, (float)externalData.Value0);
            }

            var databaseData = txStats.GetUnscopedStat(MetricNames.DatastoreAll);

            if (databaseData != null)
            {
                _attribDefs.DatabaseDuration.TrySetValue(attribValues, databaseData.Value1);
                _attribDefs.DatabaseCallCount.TrySetValue(attribValues, databaseData.Value0);
            }

            if (_configurationService.Configuration.ErrorCollectorEnabled && immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
            {
                var errorData = immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData;

                _attribDefs.GetTypeAttribute(TypeAttributeValue.TransactionError).TrySetDefault(attribValues);

                _attribDefs.TimestampForError.TrySetValue(attribValues, errorData.NoticedAt);
                _attribDefs.ErrorClass.TrySetValue(attribValues, errorData.ErrorTypeName);
                _attribDefs.ErrorType.TrySetValue(attribValues, errorData.ErrorTypeName);
                _attribDefs.ErrorMessage.TrySetValue(attribValues, errorData.ErrorMessage);
                _attribDefs.ErrorDotMessage.TrySetValue(attribValues, errorData.ErrorMessage);
                _attribDefs.IsError.TrySetValue(attribValues, true);
                _attribDefs.ErrorEventSpanId.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorDataSpanId);

                if (errorData.IsExpected)
                {
                    _attribDefs.IsErrorExpected.TrySetValue(attribValues, true);
                }
            }

            var isCatParticipant              = IsCatParticipant(immutableTransaction);
            var isSyntheticsParticipant       = IsSyntheticsParticipant(immutableTransaction);
            var isDistributedTraceParticipant = immutableTransaction.TracingState != null && immutableTransaction.TracingState.HasDataForAttributes;

            // Add the tripId attribute unconditionally, when DT disabled, so it can be used to correlate with
            // this app's PageView events. If CrossApplicationReferrerTripId is null then this transaction started the first external request,
            // so use its guid.
            if (!_configurationService.Configuration.DistributedTracingEnabled)
            {
                var tripId = immutableTransaction.TransactionMetadata.CrossApplicationReferrerTripId ?? immutableTransaction.Guid;
                _attribDefs.TripId.TrySetValue(attribValues, tripId);
                _attribDefs.CatNrTripId.TrySetValue(attribValues, tripId);
            }

            if (isCatParticipant)
            {
                _attribDefs.NrGuid.TrySetValue(attribValues, immutableTransaction.Guid);
                _attribDefs.CatReferringPathHash.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationReferrerPathHash);
                _attribDefs.CatPathHash.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationPathHash);
                _attribDefs.CatNrPathHash.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationPathHash);
                _attribDefs.ClientCrossProcessId.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationReferrerProcessId);
                _attribDefs.CatReferringTransactionGuidForEvents.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationReferrerTransactionGuid);
                _attribDefs.CatReferringTransactionGuidForTraces.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationReferrerTransactionGuid);
                _attribDefs.CatAlternativePathHashes.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.CrossApplicationAlternatePathHashes);
            }
            else if (isDistributedTraceParticipant)
            {
                _attribDefs.ParentSpanId.TrySetValue(attribValues, immutableTransaction.TracingState.ParentId ?? immutableTransaction.TracingState.Guid);
                _attribDefs.ParentTransportType.TrySetValue(attribValues, immutableTransaction.TracingState.TransportType);
                _attribDefs.ParentTransportTypeForSpan.TrySetValue(attribValues, immutableTransaction.TracingState.TransportType);

                if (immutableTransaction.TracingState.HasDataForParentAttributes)
                {
                    _attribDefs.ParentTypeForDistributedTracing.TrySetValue(attribValues, immutableTransaction.TracingState.Type);
                    _attribDefs.ParentApp.TrySetValue(attribValues, immutableTransaction.TracingState.AppId);
                    _attribDefs.ParentAccount.TrySetValue(attribValues, immutableTransaction.TracingState.AccountId);
                    _attribDefs.ParentId.TrySetValue(attribValues, immutableTransaction.TracingState.TransactionId);
                    _attribDefs.ParentTransportDuration.TrySetValue(attribValues, immutableTransaction.TracingState.TransportDuration);

                    _attribDefs.ParentTypeForDistributedTracingForSpan.TrySetValue(attribValues, immutableTransaction.TracingState.Type);
                    _attribDefs.ParentAppForSpan.TrySetValue(attribValues, immutableTransaction.TracingState.AppId);
                    _attribDefs.ParentAccountForSpan.TrySetValue(attribValues, immutableTransaction.TracingState.AccountId);
                    _attribDefs.ParentTransportDurationForSpan.TrySetValue(attribValues, immutableTransaction.TracingState.TransportDuration);
                }
            }

            if (_configurationService.Configuration.DistributedTracingEnabled)
            {
                _attribDefs.Guid.TrySetValue(attribValues, immutableTransaction.Guid);
                _attribDefs.DistributedTraceId.TrySetValue(attribValues, immutableTransaction.TraceId);
                _attribDefs.Priority.TrySetValue(attribValues, immutableTransaction.Priority);
                _attribDefs.Sampled.TrySetValue(attribValues, immutableTransaction.Sampled);
            }

            if (isSyntheticsParticipant)
            {
                _attribDefs.NrGuid.TrySetValue(attribValues, immutableTransaction.Guid);

                _attribDefs.SyntheticsResourceId.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.SyntheticsResourceId);
                _attribDefs.SyntheticsResourceIdForTraces.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.SyntheticsResourceId);

                _attribDefs.SyntheticsJobId.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.SyntheticsJobId);
                _attribDefs.SyntheticsJobIdForTraces.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.SyntheticsJobId);

                _attribDefs.SyntheticsMonitorId.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.SyntheticsMonitorId);
                _attribDefs.SyntheticsMonitorIdForTraces.TrySetValue(attribValues, immutableTransaction.TransactionMetadata.SyntheticsMonitorId);
            }
        }