public TransactionTraceWireModelComponents(TransactionMetricName transactionMetricName, TimeSpan duration, bool isSynthetics, GenerateWireModel generateWireModel) { _generateWireModel = generateWireModel; Duration = duration; IsSynthetics = isSynthetics; TransactionMetricName = transactionMetricName; }
public TransactionMetricName GetTransactionMetricName(ITransactionName transactionName) { var proposedTransactionMetricName = new TransactionMetricName(transactionName.IsWeb ? MetricNames.WebTransactionPrefix : MetricNames.OtherTransactionPrefix, transactionName.UnprefixedName); var vettedTransactionMetricName = _metricNameService.RenameTransaction(proposedTransactionMetricName); return(vettedTransactionMetricName); }
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); }
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); } }
public IAttributeValueCollection GetAttributes(ImmutableTransaction immutableTransaction, TransactionMetricName transactionMetricName, TimeSpan?apdexT, TimeSpan totalTime, TransactionMetricStatsCollection txStats) { var attribVals = new AttributeValueCollection(AttributeValueCollection.AllTargetModelTypes); SetUserAndAgentAttributes(attribVals, immutableTransaction.TransactionMetadata); SetIntrinsicAttributes(attribVals, immutableTransaction, transactionMetricName, apdexT, totalTime, txStats); return(attribVals); }
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); } }
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); } }
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 ErrorTraceWireModel GenerateErrorTrace(ImmutableTransaction immutableTransaction, IAttributeValueCollection attributes, TransactionMetricName transactionMetricName) { if (!ErrorCollectionEnabled()) { return(null); } return(_errorTraceMaker.GetErrorTrace(immutableTransaction, attributes, transactionMetricName)); }
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); }
/// <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 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); }