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)); }
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); } }
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); } }
/// <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)); }
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); }
/// <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); } }
/// <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); } }
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); }
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); } }