private void OnSendStart(KeyValuePair <string, object> kv, string action, PropertyFetcherCollection cachedProperties) { var currentSegment = ApmAgent.GetCurrentExecutionSegment(); if (currentSegment is null) { Logger.Trace()?.Log("No current transaction or span - exiting"); return; } if (kv.Value is null) { Logger.Trace()?.Log("Value is null - exiting"); return; } var activity = Activity.Current; var queueName = cachedProperties.Fetch(kv.Value, "Entity") as string; var destinationAddress = cachedProperties.Fetch(kv.Value, "Endpoint") as Uri; if (MatchesIgnoreMessageQueues(queueName)) { return; } var spanName = queueName is null ? $"{ServiceBus.SegmentName} {action}" : $"{ServiceBus.SegmentName} {action} to {queueName}"; var span = currentSegment.StartSpan(spanName, ApiConstants.TypeMessaging, ServiceBus.SubType, action.ToLowerInvariant()); span.Context.Destination = new Destination { Address = destinationAddress?.AbsoluteUri, Service = new Destination.DestinationService { Resource = queueName is null ? ServiceBus.SubType : $"{ServiceBus.SubType}/{queueName}" } }; if (queueName != null) { span.Context.Message = new Message { Queue = new Queue { Name = queueName } } } ; if (!_processingSegments.TryAdd(activity.Id, span)) { Logger.Trace() ?.Log( "Could not add {Action} span {SpanId} for activity {ActivityId} to tracked segments", action, span.Id, activity.Id); } }
private void OnException(KeyValuePair <string, object> kv) { var activity = Activity.Current; if (activity is null) { Logger.Trace()?.Log("Current activity is null - exiting"); return; } if (!_processingSegments.TryRemove(activity.Id, out var segment)) { Logger.Trace() ?.Log( "Could not find segment for activity {ActivityId} in tracked segments", activity.Id); return; } if (_exceptionProperty.Fetch(kv.Value, "Exception") is Exception exception) { segment.CaptureException(exception); } FillSpanLinks(_exceptionProperty, segment, kv); segment.Outcome = Outcome.Failure; segment.End(); }
private void OnStop(KeyValuePair <string, object> kv, PropertyFetcherCollection cachedProperties) { var activity = Activity.Current; if (activity is null) { Logger.Trace()?.Log("Current activity is null - exiting"); return; } if (!_processingSegments.TryRemove(activity.Id, out var segment)) { Logger.Trace() ?.Log( "Could not find segment for activity {ActivityId} in tracked segments", activity.Id); return; } FillSpanLinks(cachedProperties, segment, kv); var status = cachedProperties.Fetch(kv.Value, "Status") as TaskStatus?; var outcome = status switch { TaskStatus.RanToCompletion => Outcome.Success, TaskStatus.Canceled => Outcome.Failure, TaskStatus.Faulted => Outcome.Failure, _ => Outcome.Unknown }; segment.Outcome = outcome; segment.End(); }
private void OnProcessStart(KeyValuePair <string, object> kv, string action, PropertyFetcherCollection cachedProperties) { if (kv.Value is null) { Logger.Trace()?.Log("Value is null - exiting"); return; } var queueName = cachedProperties.Fetch(kv.Value, "Entity") as string; if (MatchesIgnoreMessageQueues(queueName)) { return; } var transactionName = queueName is null ? $"{ServiceBus.SegmentName} {action}" : $"{ServiceBus.SegmentName} {action} from {queueName}"; var transaction = ApmAgent.Tracer.StartTransaction(transactionName, ApiConstants.TypeMessaging); transaction.Context.Service = new Service(null, null) { Framework = _framework }; if (queueName != null) { transaction.Context.Message = new Message { Queue = new Queue { Name = queueName } } } ; // transaction creation will create an activity, so use this as the key. var activityId = Activity.Current.Id; if (!_processingSegments.TryAdd(activityId, transaction)) { Logger.Trace() ?.Log( "Could not add {Action} transaction {TransactionId} for activity {ActivityId} to tracked segments", action, transaction.Id, activityId); } }
private void OnReceiveStart(KeyValuePair <string, object> kv, string action, PropertyFetcherCollection cachedProperties) { if (kv.Value is null) { Logger.Trace()?.Log("Value is null - exiting"); return; } var queueName = cachedProperties.Fetch(kv.Value, "Entity") as string; if (MatchesIgnoreMessageQueues(queueName)) { return; } var transactionName = queueName is null ? $"{ServiceBus.SegmentName} {action}" : $"{ServiceBus.SegmentName} {action} from {queueName}"; IExecutionSegment segment; if (ApmAgent.Tracer.CurrentTransaction is null) { var transaction = ApmAgent.Tracer.StartTransaction(transactionName, ApiConstants.TypeMessaging); transaction.Context.Service = new Service(null, null) { Framework = _framework }; segment = transaction; } else { var span = ApmAgent.GetCurrentExecutionSegment().StartSpan(transactionName, ApiConstants.TypeMessaging, ServiceBus.SubType, action); segment = span; } // transaction creation will create an activity, so use this as the key. var activityId = Activity.Current.Id; if (!_processingSegments.TryAdd(activityId, segment)) { Logger.Trace()?.Log( "Could not add {Action} {SegmentName} {TransactionId} for activity {ActivityId} to tracked segments", action, segment is ITransaction ? "transaction" : "span", segment.Id, activityId); } }
private void FillSpanLinks(PropertyFetcherCollection cachedProperties, IExecutionSegment segment, KeyValuePair <string, object> kv) { var messages = cachedProperties.Fetch(kv.Value, "Messages") as IEnumerable <object>; var spanLinks = new List <SpanLink>(); if (messages != null) { foreach (var message in messages) { if (message.GetType().GetProperty("UserProperties")?.GetValue(message) is Dictionary <string, object> properties) { foreach (var property in properties) { if (property.Key.Equals("Diagnostic-Id", StringComparison.InvariantCultureIgnoreCase)) { var parsedTraceParent = DistributedTracingData.TryDeserializeFromString(property.Value.ToString()); if (parsedTraceParent != null) { spanLinks.Add(new SpanLink(parsedTraceParent.ParentId, parsedTraceParent.TraceId)); } } } } } } switch (segment) { case Model.Transaction t: t.InsertSpanLinkInternal(spanLinks); break; case Model.Span s: s.InsertSpanLinkInternal(spanLinks); break; } }