private bool MatchesIgnoreMessageQueues(string name)
        {
            if (name != null && _realAgent != null)
            {
                var matcher = WildcardMatcher.AnyMatch(_realAgent.ConfigStore.CurrentSnapshot.IgnoreMessageQueues, name);
                if (matcher != null)
                {
                    Logger.Debug()?.Log(
                        "Not tracing message from {QueueName} because it matched IgnoreMessageQueues pattern {Matcher}",
                        name,
                        matcher.GetMatcher());
                    return(true);
                }
            }

            return(false);
        }
Пример #2
0
        public void TestMatchAnyStartsWith()
        {
            var matcher1 = WildcardMatcher.ValueOf("foo*");
            var matcher2 = WildcardMatcher.ValueOf("bar*");

            WildcardMatcher.AnyMatch(new List <WildcardMatcher> {
                matcher1, matcher2
            }, "foo").Should().Be(matcher1);
            WildcardMatcher.AnyMatch(new List <WildcardMatcher> {
                matcher1, matcher2
            }, "bar").Should().Be(matcher2);
            WildcardMatcher.AnyMatch(new List <WildcardMatcher> {
                matcher1, matcher2
            }, "baz").Should().BeNull();
            WildcardMatcher.AnyMatch(new List <WildcardMatcher> {
                matcher1, matcher2
            }, "fo", "o").Should().Be(matcher1);
            WildcardMatcher.AnyMatch(new List <WildcardMatcher> {
                matcher1, matcher2
            }, "ba", "r").Should().Be(matcher2);
            WildcardMatcher.AnyMatch(new List <WildcardMatcher> {
                matcher1, matcher2
            }, "ba", "z").Should().BeNull();
        }
Пример #3
0
        internal static ISpan CreateProducerSpan(IApmAgent agent, ITopicPartition topicPartition, bool isTombstone, bool finishOnClose)
        {
            ISpan span = null;

            try
            {
                // no current transaction, don't create a span
                var currentTransaction = agent.Tracer.CurrentTransaction;
                if (currentTransaction is null)
                {
                    return(span);
                }

                var topic   = topicPartition?.Topic;
                var matcher = WildcardMatcher.AnyMatch(currentTransaction.Configuration.IgnoreMessageQueues, topic);
                if (matcher != null)
                {
                    agent.Logger.Trace()
                    ?.Log(
                        "Not tracing message from {Queue} because it matched IgnoreMessageQueues pattern {Matcher}",
                        topic,
                        matcher.GetMatcher());

                    return(span);
                }

                var spanName = string.IsNullOrEmpty(topic)
                                        ? "Kafka SEND"
                                        : $"Kafka SEND to {topic}";

                span = agent.GetCurrentExecutionSegment().StartSpan(
                    spanName,
                    ApiConstants.TypeMessaging,
                    Subtype,
                    isExitSpan: true);

                if (!string.IsNullOrEmpty(topic))
                {
                    span.Context.Message = new Message {
                        Queue = new Queue {
                            Name = topic
                        }
                    }
                }
                ;

                if (topicPartition?.Partition is not null && !topicPartition.Partition.IsSpecial)
                {
                    span.SetLabel("partition", topicPartition.Partition.ToString());
                }

                if (isTombstone)
                {
                    span.SetLabel("tombstone", "true");
                }
            }
            catch (Exception ex)
            {
                agent.Logger.Error()?.LogException(ex, "Error creating or populating kafka span.");
            }

            return(span);
        }
Пример #4
0
        internal static ITransaction CreateConsumerTransaction(
            IApmAgent agent,
            string topic,
            Partition?partition,
            Offset?offset,
            IMessage message)
        {
            ITransaction transaction = null;

            try
            {
                if (agent.Tracer.CurrentTransaction is not null)
                {
                    return(null);
                }

                if (agent is ApmAgent apmAgent)
                {
                    var matcher = WildcardMatcher.AnyMatch(apmAgent.ConfigurationStore.CurrentSnapshot.IgnoreMessageQueues, topic);
                    if (matcher != null)
                    {
                        agent.Logger.Trace()
                        ?.Log(
                            "Not tracing message from {Queue} because it matched IgnoreMessageQueues pattern {Matcher}",
                            topic,
                            matcher.GetMatcher());

                        return(null);
                    }
                }

                DistributedTracingData distributedTracingData = null;
                if (message?.Headers != null)
                {
                    var headers = new KafkaHeadersCollection(message.Headers, agent.Logger);
                    try
                    {
                        var traceParent = string.Join(",", headers.GetValues(TraceContext.TraceParentBinaryHeaderName));
                        var traceState  = headers.GetValues(TraceContext.TraceStateHeaderName).FirstOrDefault();
                        distributedTracingData = TraceContext.TryExtractTracingData(traceParent, traceState);
                    }
                    catch (Exception ex)
                    {
                        agent.Logger.Error()?.LogException(ex, "Error extracting propagated headers from Kafka message");
                    }
                }

                var name = string.IsNullOrEmpty(topic)
                                        ? "Kafka RECEIVE"
                                        : $"Kafka RECEIVE from {topic}";

                transaction = agent.Tracer.StartTransaction(name, ApiConstants.TypeMessaging, distributedTracingData);

                if (partition is not null)
                {
                    transaction.SetLabel("partition", partition.ToString());
                }

                if (offset is not null)
                {
                    transaction.SetLabel("offset", offset.ToString());
                }

                // record only queue topic name and age on context for now. capture body and headers potentially in future
                transaction.Context.Message = new Message {
                    Queue = new Queue {
                        Name = topic
                    }
                };
                if (transaction is Transaction realTransaction && message is not null && message.Timestamp.Type != 0)
                {
                    var consumeTime = TimeUtils.ToDateTime(realTransaction.Timestamp);
                    var produceTime = message.Timestamp.UtcDateTime;

                    var age = Math.Max(0, (consumeTime - produceTime).TotalMilliseconds);
                    if (age > 0 && age < MaxAge)
                    {
                        transaction.Context.Message.Age = new Age {
                            Ms = (long)age
                        }
                    }
                    ;
                }

                if (message is not null && message.Value is null)
                {
                    transaction.SetLabel("tombstone", "true");
                }
            }
            catch (Exception ex)
            {
                agent.Logger.Error()?.LogException(ex, "Error creating or populating transaction.");
            }

            return(transaction);
        }
        /// <summary>
        /// OnMethodEnd callback
        /// </summary>
        /// <typeparam name="TTarget">Type of the target</typeparam>
        /// <typeparam name="TResult">Type of the BasicGetResult</typeparam>
        /// <param name="instance">Instance value, aka `this` of the instrumented method.</param>
        /// <param name="basicGetResult">BasicGetResult instance</param>
        /// <param name="exception">Exception instance in case the original code threw an exception.</param>
        /// <param name="state">Calltarget state value</param>
        /// <returns>A default CallTargetReturn to satisfy the CallTarget contract</returns>
        public static CallTargetReturn <TResult> OnMethodEnd <TTarget, TResult>(TTarget instance, TResult basicGetResult, Exception exception, CallTargetState state)
            where TResult : IBasicGetResult, IDuckType
        {
            var queue       = (string)state.State;
            var startTime   = state.StartTime;
            var agent       = Agent.Instance;
            var transaction = agent.Tracer.CurrentTransaction;

            if (transaction is null)
            {
                return(new CallTargetReturn <TResult>(basicGetResult));
            }

            var matcher = WildcardMatcher.AnyMatch(transaction.Configuration.IgnoreMessageQueues, queue);

            if (matcher != null)
            {
                agent.Logger.Trace()
                ?.Log(
                    "Not tracing message from {Queue} because it matched IgnoreMessageQueues pattern {Matcher}",
                    queue,
                    matcher.GetMatcher());

                return(new CallTargetReturn <TResult>(basicGetResult));
            }

            // check if there is an actual instance of the duck-typed type. RabbitMQ client can return null when the server
            // answers that there are no messages available
            var instanceNotNull = basicGetResult.Instance != null;

            if (instanceNotNull)
            {
                var normalizedExchange = RabbitMqIntegration.NormalizeExchangeName(basicGetResult.Exchange);
                matcher = WildcardMatcher.AnyMatch(transaction.Configuration.IgnoreMessageQueues, normalizedExchange);
                if (matcher != null)
                {
                    agent.Logger.Trace()
                    ?.Log(
                        "Not tracing message from {Queue} because it matched IgnoreMessageQueues pattern {Matcher}",
                        normalizedExchange,
                        matcher.GetMatcher());

                    return(new CallTargetReturn <TResult>(basicGetResult));
                }
            }

            var normalizedQueue = RabbitMqIntegration.NormalizeQueueName(queue);
            var span            = agent.Tracer.CurrentExecutionSegment().StartSpan(
                $"{RabbitMqIntegration.Name} POLL from {normalizedQueue}",
                ApiConstants.TypeMessaging,
                RabbitMqIntegration.Subtype);

            if (startTime.HasValue && span is Span realSpan)
            {
                realSpan.Timestamp = TimeUtils.ToTimestamp(startTime.Value);
            }

            span.Context.Message = new Message {
                Queue = new Queue {
                    Name = queue
                }
            };

            if (instanceNotNull)
            {
                span.SetLabel("message_size", basicGetResult.Body?.Length ?? 0);

                if (!string.IsNullOrEmpty(basicGetResult.RoutingKey))
                {
                    span.Context.Message.RoutingKey = basicGetResult.RoutingKey;
                }
            }

            span.EndCapturingException(exception);
            return(new CallTargetReturn <TResult>(basicGetResult));
        }