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);
            }
        }
Beispiel #5
0
        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;
            }
        }