private void GenerateAndCollectSpanEvents(ImmutableTransaction immutableTransaction, string transactionName, Func <IAttributeValueCollection> attributes)
        {
            var useInfiniteTracing    = _spanEventAggregatorInfiniteTracing.IsServiceEnabled && _spanEventAggregatorInfiniteTracing.IsServiceAvailable;
            var useTraditionalTracing = !useInfiniteTracing && immutableTransaction.Sampled && _spanEventAggregator.IsServiceEnabled && _spanEventAggregator.IsServiceAvailable;

            if (!useInfiniteTracing && !useTraditionalTracing)
            {
                return;
            }

            var countProposedSpans = immutableTransaction.Segments.Count + 1;

            if (useInfiniteTracing && !_spanEventAggregatorInfiniteTracing.HasCapacity(countProposedSpans))
            {
                _spanEventAggregatorInfiniteTracing.RecordSeenSpans(countProposedSpans);
                _spanEventAggregatorInfiniteTracing.RecordDroppedSpans(countProposedSpans);
                return;
            }

            var spanEvents = _spanEventMaker.GetSpanEvents(immutableTransaction, transactionName, attributes.Invoke());

            using (_agentTimerService.StartNew("CollectSpanEvents"))
            {
                if (useInfiniteTracing)
                {
                    _spanEventAggregatorInfiniteTracing.Collect(spanEvents);
                }
                else
                {
                    _spanEventAggregator.Collect(spanEvents);
                }
            }
        }
        private void GenerateAndCollectSqlTrace(ImmutableTransaction immutableTransaction, TransactionMetricName transactionMetricName, TransactionMetricStatsCollection txStats)
        {
            if (!_configurationService.Configuration.SlowSqlEnabled)
            {
                return;
            }

            var txSqlTrStats = new SqlTraceStatsCollection();

            foreach (var segment in immutableTransaction.Segments.Where(s => s.Data is DatastoreSegmentData))
            {
                var datastoreSegmentData = (DatastoreSegmentData)segment.Data;
                if (datastoreSegmentData.CommandText != null &&
                    segment.Duration >= _configurationService.Configuration.SqlExplainPlanThreshold)
                {
                    AddSqlTraceStats(txSqlTrStats, _sqlTraceMaker.TryGetSqlTrace(immutableTransaction, transactionMetricName, segment));
                }
            }

            if (txSqlTrStats.Collection.Count > 0)
            {
                using (_agentTimerService.StartNew("CollectSqlTrace"))
                {
                    _sqlTraceAggregator.Collect(txSqlTrStats);
                }

                MetricBuilder.TryBuildSqlTracesCollectedMetric(txSqlTrStats.TracesCollected, txStats);
            }
        }
        public TransactionTraceWireModel GetTransactionTrace(ImmutableTransaction immutableTransaction, IEnumerable <ImmutableSegmentTreeNode> segmentTrees, TransactionMetricName transactionMetricName, IAttributeValueCollection attribValues)
        {
            segmentTrees = segmentTrees.ToList();

            if (!segmentTrees.Any())
            {
                throw new ArgumentException("There must be at least one segment to create a trace");
            }

            var filteredAttributes = new AttributeValueCollection(attribValues, AttributeDestinations.TransactionTrace);

            // See spec for details on these fields: https://source.datanerd.us/agents/agent-specs/blob/master/Transaction-Trace-LEGACY.md
            var    startTime = immutableTransaction.StartTime;
            var    duration  = immutableTransaction.ResponseTimeOrDuration;
            string uri       = null;

            if (_attribDefs.RequestUri.IsAvailableForAny(AttributeDestinations.TransactionTrace))
            {
                uri = immutableTransaction.TransactionMetadata.Uri?.TrimAfterAChar(StringSeparators.QuestionMarkChar) ?? "/Unknown";
            }

            var guid          = immutableTransaction.Guid;
            var xraySessionId = null as ulong?; // The .NET agent does not support xray sessions

            var isSynthetics         = immutableTransaction.TransactionMetadata.IsSynthetics;
            var syntheticsResourceId = immutableTransaction.TransactionMetadata.SyntheticsResourceId;
            var rootSegment          = GetRootSegment(segmentTrees, immutableTransaction);


            var traceData = new TransactionTraceData(startTime, rootSegment, attribValues);

            var trace = new TransactionTraceWireModel(startTime, duration, transactionMetricName.PrefixedName, uri, traceData, guid, xraySessionId, syntheticsResourceId, isSynthetics);

            return(trace);
        }
        private static ImmutableSegmentTreeNode BuildNode(ImmutableTransaction transaction = null, DateTime?startTime = null, TimeSpan?duration = null, string name = "", MethodCallData methodCallData = null, IEnumerable <KeyValuePair <string, object> > parameters = null)
        {
            startTime = startTime ?? DateTime.Now;
            var relativeStart = startTime.Value - (transaction?.StartTime ?? startTime.Value);

            methodCallData = methodCallData ?? new MethodCallData("typeName", "methodName", 1);
            return(new SegmentTreeNodeBuilder(SimpleSegmentDataTests.createSimpleSegmentBuilder(relativeStart, duration ?? TimeSpan.Zero, 2, 1, methodCallData, parameters ?? new Dictionary <string, object>(), name, false))
                   .Build());
        }
        private ErrorTraceWireModel GenerateErrorTrace(ImmutableTransaction immutableTransaction, IAttributeValueCollection attributes, TransactionMetricName transactionMetricName)
        {
            if (!ErrorCollectionEnabled())
            {
                return(null);
            }

            return(_errorTraceMaker.GetErrorTrace(immutableTransaction, attributes, transactionMetricName));
        }
Example #6
0
        public ErrorEventWireModel GetErrorEvent(ImmutableTransaction immutableTransaction, IAttributeValueCollection attribValues)
        {
            var transactionMetadata = immutableTransaction.TransactionMetadata;
            var isSynthetics        = transactionMetadata.IsSynthetics;
            var priority            = immutableTransaction.Priority;

            _attribDefs.GetTypeAttribute(TypeAttributeValue.TransactionError).TrySetDefault(attribValues);
            return(new ErrorEventWireModel(attribValues, isSynthetics, priority));
        }
        private TimeSpan?GetApdexT(ImmutableTransaction immutableTransaction, string transactionApdexMetricName)
        {
            var apdexT = _metricNameService.TryGetApdex_t(transactionApdexMetricName);

            if (immutableTransaction.IsWebTransaction())
            {
                apdexT = apdexT ?? _configurationService.Configuration.TransactionTraceApdexT;
            }

            return(apdexT);
        }
        public static IInternalTransaction CreateDefaultTransaction(bool isWebTransaction          = true, string uri     = null,
                                                                    string guid                    = null, int?statusCode = null, int?subStatusCode = null, string referrerCrossProcessId = null,
                                                                    string transactionCategory     = "defaultTxCategory", string transactionName = "defaultTxName", bool addSegment = true,
                                                                    IEnumerable <Segment> segments = null, bool sampled = false, IConfigurationService configurationService         = null, Exception exception = null)
        {
            var name = isWebTransaction
                ? TransactionName.ForWebTransaction(transactionCategory, transactionName)
                : TransactionName.ForOtherTransaction(transactionCategory, transactionName);

            segments = segments ?? Enumerable.Empty <Segment>();

            var placeholderMetadataBuilder = new TransactionMetadata();
            var placeholderMetadata        = placeholderMetadataBuilder.ConvertToImmutableMetadata();

            var immutableTransaction = new ImmutableTransaction(name, segments, placeholderMetadata, DateTime.Now, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), guid, false, false, false, 0.5f, false, string.Empty, null, _attribDefSvc.AttributeDefs);
            var priority             = 0.5f;

            var configuration = configurationService?.Configuration ?? GetDefaultConfiguration();
            var errorService  = configurationService != null ? new ErrorService(configurationService) : new ErrorService(Mock.Create <IConfigurationService>());

            var internalTransaction = new Transaction(configuration, immutableTransaction.TransactionName, Mock.Create <ITimer>(), DateTime.UtcNow, Mock.Create <ICallStackManager>(),
                                                      _databaseService, priority, Mock.Create <IDatabaseStatementParser>(), Mock.Create <IDistributedTracePayloadHandler>(),
                                                      errorService, _attribDefSvc.AttributeDefs);

            if (exception != null)
            {
                internalTransaction.NoticeError(exception);
            }

            if (segments.Any())
            {
                foreach (var segment in segments)
                {
                    internalTransaction.Add(segment);
                }
            }
            else if (addSegment)
            {
                internalTransaction.Add(SimpleSegmentDataTests.createSimpleSegmentBuilder(TimeSpan.Zero, TimeSpan.Zero, 0, null, new MethodCallData("typeName", "methodName", 1), Enumerable.Empty <KeyValuePair <string, object> >(), "MyMockedRootNode", false));
            }

            var adaptiveSampler = Mock.Create <IAdaptiveSampler>();

            Mock.Arrange(() => adaptiveSampler.ComputeSampled(ref priority)).Returns(sampled);
            internalTransaction.SetSampled(adaptiveSampler);
            var transactionMetadata = internalTransaction.TransactionMetadata;

            PopulateTransactionMetadataBuilder(transactionMetadata, errorService, uri, statusCode, subStatusCode, referrerCrossProcessId);

            return(internalTransaction);
        }
        private void GetApdexMetrics(ImmutableTransaction immutableTransaction, TimeSpan apdexT, string transactionApdexMetricName, TransactionMetricStatsCollection txStats)
        {
            var isWebTransaction = immutableTransaction.IsWebTransaction();

            if (immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError &&
                !immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData.IsExpected)
            {
                MetricBuilder.TryBuildFrustratedApdexMetrics(isWebTransaction, transactionApdexMetricName, txStats);
            }
            else
            {
                MetricBuilder.TryBuildApdexMetrics(transactionApdexMetricName, isWebTransaction, immutableTransaction.ResponseTimeOrDuration, apdexT, txStats);
            }
        }
Example #10
0
        public IEnumerable <ISpanEventWireModel> GetSpanEvents(ImmutableTransaction immutableTransaction, string transactionName, IAttributeValueCollection transactionAttribValues)
        {
            var rootSpanId = GuidGenerator.GenerateNewRelicGuid();

            yield return(GenerateRootSpan(rootSpanId, immutableTransaction, transactionName, transactionAttribValues));

            foreach (var segment in immutableTransaction.Segments)
            {
                var segmentAttribValues = GetAttributeValues(segment, immutableTransaction, rootSpanId);

                segmentAttribValues.MakeImmutable();

                yield return(segmentAttribValues);
            }
        }
Example #11
0
        /// <summary>
        /// Gets an <see cref="NewRelic.Agent.Core.WireModels.ErrorTraceWireModel"/> given
        /// a transaction, transaction attributes and an error referenced by an <see cref="NewRelic.Agent.Core.Errors.ErrorData"/>
        /// occurring inside of a transaction.
        /// </summary>
        /// <remarks>
        /// The <param name="errorData"></param> passed to this method is assumed to contain valid error information.
        /// The method won't throw if it is not but will send meaningless data in some of the attributes.
        /// </remarks>
        /// <param name="immutableTransaction"></param>
        /// <param name="transactionAttributes"></param>
        /// <param name="transactionMetricName"></param>
        /// <param name="errorData"></param>
        /// <returns></returns>
        public ErrorTraceWireModel GetErrorTrace(ImmutableTransaction immutableTransaction, IAttributeValueCollection transactionAttributes, TransactionMetricName transactionMetricName)
        {
            var errorData = immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData;

            var stackTrace = GetFormattedStackTrace(errorData);

            var timestamp                = errorData.NoticedAt;
            var path                     = transactionMetricName.PrefixedName;
            var message                  = errorData.ErrorMessage;
            var exceptionClassName       = errorData.ErrorTypeName;
            var errorAttributesWireModel = GetErrorTraceAttributes(transactionAttributes, stackTrace);
            var guid                     = immutableTransaction.Guid;

            return(new ErrorTraceWireModel(timestamp, path, message, exceptionClassName, errorAttributesWireModel, guid));
        }
Example #12
0
        public SqlTraceWireModel TryGetSqlTrace(ImmutableTransaction immutableTransaction, TransactionMetricName transactionMetricName, Segment segment)
        {
            var segmentData = segment.Data as DatastoreSegmentData;

            if (segment.Duration == null || segmentData == null)
            {
                return(null);
            }

            var transactionName = transactionMetricName.PrefixedName;

            var uri = _attribDefs.RequestUri.IsAvailableForAny(AttributeDestinations.SqlTrace)
                ? immutableTransaction.TransactionMetadata.Uri ?? "<unknown>"
                : "<unknown>";

            var sql   = _databaseService.GetObfuscatedSql(segmentData.CommandText, segmentData.DatastoreVendorName);
            var sqlId = _databaseService.GetSqlId(segmentData.CommandText, segmentData.DatastoreVendorName);

            var       metricName    = segmentData.GetTransactionTraceName();
            const int count         = 1;
            var       totalCallTime = segment.Duration.Value;
            var       parameterData = new Dictionary <string, object>(); // Explain plans will go here

            if (segmentData.ExplainPlan != null)
            {
                parameterData.Add("explain_plan", new ExplainPlanWireModel(segmentData.ExplainPlan));
            }

            if (_configurationService.Configuration.InstanceReportingEnabled)
            {
                parameterData.Add("host", segmentData.Host);
                parameterData.Add("port_path_or_id", segmentData.PortPathOrId);
            }

            if (_configurationService.Configuration.DatabaseNameReportingEnabled)
            {
                parameterData.Add("database_name", segmentData.DatabaseName);
            }

            if (segmentData.QueryParameters != null)
            {
                parameterData["query_parameters"] = segmentData.QueryParameters;
            }

            var sqlTraceData = new SqlTraceWireModel(transactionName, uri, sqlId, sql, metricName, count, totalCallTime, totalCallTime, totalCallTime, parameterData);

            return(sqlTraceData);
        }
        public static ImmutableTransaction CreateTestTransactionWithSegments(IEnumerable <Segment> segments)
        {
            var uri = "sqlTrace/Uri";

            var transactionMetadata = new TransactionMetadata();

            transactionMetadata.SetUri(uri);

            var name     = TransactionName.ForWebTransaction("TxsWithSegments", "TxWithSegmentX");
            var metadata = transactionMetadata.ConvertToImmutableMetadata();
            var guid     = Guid.NewGuid().ToString();

            var transaction = new ImmutableTransaction(name, segments, metadata, DateTime.UtcNow, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), guid, false, false, false, 0.5f, false, string.Empty, null, _attribDefSvc.AttributeDefs);

            return(transaction);
        }
Example #14
0
        /// <summary>
        /// Creates a single root span, much like we do for Transaction Traces, since DT requires that there be only one parent-less span per txn (or at least the UI/Backend is expecting that).
        /// </summary>
        private SpanAttributeValueCollection GenerateRootSpan(string rootSpanId, ImmutableTransaction immutableTransaction, string transactionName, IAttributeValueCollection transactionAttribValues)
        {
            var spanAttributes = new SpanAttributeValueCollection();

            spanAttributes.AddRange(transactionAttribValues.GetAttributeValues(AttributeClassification.AgentAttributes));

            _attribDefs.TransactionNameForSpan.TrySetValue(spanAttributes, transactionName);


            spanAttributes.Priority = immutableTransaction.Priority;

            spanAttributes.AddRange(immutableTransaction.CommonSpanAttributes);

            if (immutableTransaction.TracingState != null)
            {
                _attribDefs.ParentId.TrySetValue(spanAttributes, immutableTransaction.TracingState.ParentId ?? immutableTransaction.TracingState.Guid);
                _attribDefs.TrustedParentId.TrySetValue(spanAttributes, immutableTransaction.TracingState.Guid);
                _attribDefs.TracingVendors.TrySetValue(spanAttributes, immutableTransaction.TracingState.VendorStateEntries ?? null);
            }

            if (_configurationService.Configuration.ErrorCollectorEnabled && immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
            {
                _attribDefs.SpanErrorClass.TrySetValue(spanAttributes, immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData.ErrorTypeName);
                _attribDefs.SpanErrorMessage.TrySetValue(spanAttributes, immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData.ErrorMessage);
                if (immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData.IsExpected)
                {
                    _attribDefs.SpanIsErrorExpected.TrySetValue(spanAttributes, true);
                }
            }

            _attribDefs.Guid.TrySetValue(spanAttributes, rootSpanId);
            _attribDefs.Timestamp.TrySetValue(spanAttributes, immutableTransaction.StartTime);
            _attribDefs.Duration.TrySetValue(spanAttributes, immutableTransaction.Duration);

            _attribDefs.NameForSpan.TrySetValue(spanAttributes, transactionName);

            _attribDefs.SpanCategory.TrySetValue(spanAttributes, SpanCategory.Generic);
            _attribDefs.NrEntryPoint.TrySetValue(spanAttributes, true);

            spanAttributes.AddRange(transactionAttribValues.GetAttributeValues(AttributeClassification.UserAttributes));

            spanAttributes.MakeImmutable();

            return(spanAttributes);
        }
        private void GenerateAndCollectTransactionTrace(ImmutableTransaction immutableTransaction, TransactionMetricName transactionMetricName, Func <IAttributeValueCollection> attributes)
        {
            if (!_configurationService.Configuration.TransactionTracerEnabled)
            {
                return;
            }

            var traceComponents = new TransactionTraceWireModelComponents(
                transactionMetricName,
                immutableTransaction.Duration,
                immutableTransaction.TransactionMetadata.IsSynthetics,
                () => _transactionTraceMaker.GetTransactionTrace(immutableTransaction, _segmentTreeMaker.BuildSegmentTrees(immutableTransaction.Segments), transactionMetricName, attributes.Invoke()));

            using (_agentTimerService.StartNew("CollectTransactionTrace"))
            {
                _transactionTraceAggregator.Collect(traceComponents);
            }
        }
Example #16
0
        /// <summary>
        /// Determines the parentId (SpanId) for the span being created.
        /// </summary>
        /// <param name="segment">Current segment being processed into a Span Event.</param>
        /// <param name="immutableTransaction">Current transaction whose segments are being processed into Span Events.</param>
        /// <param name="rootSpanId">SpanId of the faux root segment.</param>
        /// <returns>SpanId of the parent segment.</returns>
        private static string GetParentSpanId(Segment segment, ImmutableTransaction immutableTransaction, string rootSpanId)
        {
            if (segment.ParentUniqueId == null)
            {
                return(rootSpanId);
            }

            foreach (var otherSegment in immutableTransaction.Segments)
            {
                if (otherSegment.UniqueId != segment.ParentUniqueId)
                {
                    continue;
                }

                return(otherSegment.SpanId);
            }

            return(rootSpanId);
        }
        private void GenerateAndCollectTransactionEvent(ImmutableTransaction immutableTransaction, Func <IAttributeValueCollection> attributes)
        {
            if (!_configurationService.Configuration.TransactionEventsEnabled)
            {
                return;
            }

            if (!_configurationService.Configuration.TransactionEventsTransactionsEnabled)
            {
                return;
            }

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

            using (_agentTimerService.StartNew("CollectTransactionEvent"))
            {
                _transactionEventAggregator.Collect(transactionEvent);
            }
        }
Example #18
0
        public void multiple_sqlId_does_not_has_9_digits_number()
        {
            var transactionMetadata = new TransactionMetadata();
            var name     = TransactionName.ForWebTransaction("foo", "bar");
            var metadata = transactionMetadata.ConvertToImmutableMetadata();
            var duration = TimeSpan.FromSeconds(1);
            var guid     = Guid.NewGuid().ToString();
            var transactionMetricName = new TransactionMetricName("WebTransaction", "Name");
            var databaseService       = new DatabaseService(Mock.Create <ICacheStatsReporter>());
            var configurationService  = Mock.Create <IConfigurationService>();
            var attribDefSvc          = new AttributeDefinitionService((f) => new AttributeDefinitions(f));

            string[] queries = { Sql,                                                                                               "Select * from someTable", "Insert x into anotherTable",             "another random string",
                                 "1234567890!@#$%^&*()",                                                                            "fjdksalfjdkla;fjdla;",    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
                                 "NNNNNNNNNNNUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIIIINNNNNNNNNNNNNNNNNNNN",
                                 double.MaxValue.ToString() };
            var      sqlTraceMaker = new SqlTraceMaker(configurationService, attribDefSvc, databaseService);
            var      traceDatas    = new List <SqlTraceWireModel>();

            foreach (string query in queries)
            {
                var data    = new DatastoreSegmentData(databaseService, new ParsedSqlStatement(DatastoreVendor.MSSQL, null, null), query);
                var segment = new Segment(TransactionSegmentStateHelpers.GetItransactionSegmentState(), new MethodCallData("typeName", "methodName", 1));
                segment.SetSegmentData(data);

                var segments = new List <Segment>()
                {
                    new Segment(new TimeSpan(), TotalCallTime, segment, null)
                };
                var immutableTransaction = new ImmutableTransaction(name, segments, metadata, DateTime.Now, duration, duration, guid, false, false, false, 1.2f, false, string.Empty, null, _attribDefs);

                var sqlTraceData = sqlTraceMaker.TryGetSqlTrace(immutableTransaction, transactionMetricName, immutableTransaction.Segments.FirstOrDefault());
                traceDatas.Add(sqlTraceData);
            }

            foreach (SqlTraceWireModel traceData in traceDatas)
            {
                var numberOfDigits = Math.Floor(Math.Log10(traceData.SqlId) + 1);
                Assert.IsTrue(numberOfDigits != 9);
            }
        }
        private void GenerateAndCollectErrorEventTracesAndEvents(ImmutableTransaction immutableTransaction, IAttributeValueCollection attributes, TransactionMetricName transactionMetricName)
        {
            var errorTrace = GenerateErrorTrace(immutableTransaction, attributes, transactionMetricName);

            if (errorTrace == null)
            {
                return;
            }

            using (_agentTimerService.StartNew("CollectErrorTrace"))
            {
                _errorTraceAggregator.Collect(errorTrace);
            }

            if (_configurationService.Configuration.ErrorCollectorCaptureEvents)
            {
                var errorEvent = _errorEventMaker.GetErrorEvent(immutableTransaction, attributes);
                using (_agentTimerService.StartNew("CollectErrorEvent"))
                {
                    _errorEventAggregator.Collect(errorEvent);
                }
            }
        }
        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);
        }
Example #21
0
 internal virtual void AddTransactionTraceParameters(IConfigurationService configurationService, Segment segment, IDictionary <string, object> segmentParameters, ImmutableTransaction immutableTransaction)
 {
 }
        private void GenerateAndCollectMetrics(ImmutableTransaction immutableTransaction, TimeSpan?apdexT, string transactionApdexMetricName, TimeSpan totalTime, TransactionMetricStatsCollection txStats)
        {
            foreach (var segment in immutableTransaction.Segments)
            {
                GenerateSegmentMetrics(segment, txStats);
            }

            var isWebTransaction = immutableTransaction.IsWebTransaction();

            if (_configurationService.Configuration.DistributedTracingEnabled)
            {
                TimeSpan duration  = default;
                string   type      = default;
                string   account   = default;
                string   app       = default;
                string   transport = default;

                if (immutableTransaction.TracingState != null)
                {
                    duration = immutableTransaction.TracingState.TransportDuration;
                    type     = EnumNameCache <DistributedTracingParentType> .GetName(immutableTransaction.TracingState.Type);

                    account   = immutableTransaction.TracingState.AccountId;
                    app       = immutableTransaction.TracingState.AppId;
                    transport = EnumNameCache <TransportType> .GetName(immutableTransaction.TracingState.TransportType);
                }

                MetricBuilder.TryBuildDistributedTraceDurationByCaller(type, account, app, transport, isWebTransaction,
                                                                       immutableTransaction.Duration, txStats);

                if (immutableTransaction.TracingState != null)
                {
                    MetricBuilder.TryBuildDistributedTraceTransportDuration(type, account, app, transport, isWebTransaction, duration, txStats);
                }

                if (ErrorCollectionEnabled() && immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
                {
                    MetricBuilder.TryBuildDistributedTraceErrorsByCaller(type, account, app, transport, isWebTransaction, txStats);
                }
            }

            MetricBuilder.TryBuildTransactionMetrics(isWebTransaction, immutableTransaction.ResponseTimeOrDuration, txStats);

            // 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
            MetricBuilder.TryBuildTotalTimeMetrics(isWebTransaction, totalTime, txStats);

            // 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
            //_metricBuilder.TryBuildCpuTimeRollupMetric(isWebTransaction, immutableTransaction.Duration, txStats),
            //_metricBuilder.TryBuildCpuTimeMetric(transactionMetricName, immutableTransaction.Duration, txStats)

            if (immutableTransaction.TransactionMetadata.QueueTime != null)
            {
                MetricBuilder.TryBuildQueueTimeMetric(immutableTransaction.TransactionMetadata.QueueTime.Value, txStats);
            }

            if (apdexT != null && !immutableTransaction.IgnoreApdex)
            {
                GetApdexMetrics(immutableTransaction, apdexT.Value, transactionApdexMetricName, txStats);
            }

            if (ErrorCollectionEnabled() && immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.HasError)
            {
                var isErrorExpected = immutableTransaction.TransactionMetadata.ReadOnlyTransactionErrorState.ErrorData.IsExpected;
                MetricBuilder.TryBuildErrorsMetrics(isWebTransaction, txStats, isErrorExpected);
            }

            var referrerCrossProcessId = immutableTransaction.TransactionMetadata.CrossApplicationReferrerProcessId;

            if (referrerCrossProcessId != null)
            {
                var catResponseTime = TimeSpan.FromSeconds(immutableTransaction.TransactionMetadata.CrossApplicationResponseTimeInSeconds);
                MetricBuilder.TryBuildClientApplicationMetric(referrerCrossProcessId, catResponseTime, catResponseTime, txStats);
            }

            using (_agentTimerService.StartNew("CollectMetrics"))
            {
                _metricAggregator.Collect(txStats);
            }
        }