private void OnMessageStart(KeyValuePair <string, object> kv, string action)
        {
            var currentSegment = ApmAgent.GetCurrentExecutionSegment();

            if (currentSegment is null)
            {
                return;
            }

            if (!(kv.Value is Activity activity))
            {
                Logger.Trace()?.Log("Value is not an activity - exiting");
                return;
            }

            string queueName = null;

            foreach (var tag in activity.Tags)
            {
                switch (tag.Key)
                {
                case "message_bus.destination":
                    queueName = tag.Value;
                    break;

                default:
                    continue;
                }
            }

            if (MatchesIgnoreMessageQueues(queueName))
            {
                return;
            }

            var name = $"{ServiceBus.SegmentName} {action} message";

            _onMessageCurrent = currentSegment switch
            {
                Span span => span.StartSpanInternal(name, ApiConstants.TypeMessaging, ServiceBus.SubType, action.ToLowerInvariant(),
                                                    id: activity.SpanId.ToString()),
                Transaction transaction => transaction.StartSpanInternal(name, ApiConstants.TypeMessaging, ServiceBus.SubType,
                                                                         action.ToLowerInvariant(), id: activity.SpanId.ToString()),
                _ => _onMessageCurrent
            };
        }
Example #2
0
		public void ErrorShouldContainTransactionData(bool isSampled, bool captureOnSpan, bool captureAsError)
		{
			var payloadSender = new MockPayloadSender();
			var expectedErrorContext = new Context();
			expectedErrorContext.Labels["one"] = "1";
			expectedErrorContext.Labels["twenty two"] = "22";

			ITransaction capturedTransaction = null;
			IExecutionSegment errorCapturingExecutionSegment = null;
			var mockConfig = new MockConfigSnapshot(transactionSampleRate: isSampled ? "1" : "0");
			using (var agent = new ApmAgent(new TestAgentComponents(config: mockConfig, payloadSender: payloadSender)))
			{
				agent.Tracer.CaptureTransaction(TestTransaction, CustomTransactionTypeForTests, transaction =>
				{
					capturedTransaction = transaction;
					foreach (var keyValue in expectedErrorContext.Labels)
						transaction.Context.Labels[keyValue.Key] = keyValue.Value;
					ISpan span = null;
					if (captureOnSpan)
					{
						span = transaction.StartSpan(TestSpan1, ApiConstants.TypeExternal);
						errorCapturingExecutionSegment = span;
					}
					else
						errorCapturingExecutionSegment = transaction;

					if (captureAsError)
						errorCapturingExecutionSegment.CaptureError("Test error message", "Test error culprit", new StackTrace(true).GetFrames());
					else
						errorCapturingExecutionSegment.CaptureException(new TestException("test exception"));

					// Immutable snapshot of the context should be captured instead of reference to a mutable object
					// transaction.Context.Labels["three hundred thirty three"] = "333";

					span?.End();
				});
			}

			payloadSender.Errors.Count.Should().Be(1);
			payloadSender.FirstError.Transaction.IsSampled.Should().Be(isSampled);
			payloadSender.FirstError.Transaction.Type.Should().Be(CustomTransactionTypeForTests);
			payloadSender.FirstError.TransactionId.Should().Be(capturedTransaction.Id);
			payloadSender.FirstError.TraceId.Should().Be(capturedTransaction.TraceId);
			payloadSender.FirstError.ParentId.Should().Be(errorCapturingExecutionSegment.Id);
			payloadSender.FirstError.Context.Should().BeEquivalentTo(expectedErrorContext);
		}
        private static ElasticDocument DeserializeAndMapData(IExecutionSegment transaction, EventData message)
        {
            var span =
                transaction.StartSpan("Deserialize and Map Data in Message", "Data Transformation");

            try
            {
                var readData = JsonConvert.DeserializeObject <ElasticDocument>(Encoding.UTF8.GetString(message.Body));
                return(readData);
            }
            catch (Exception e)
            {
                span.CaptureException(e, "DeserializeAndMapData");
                return(null);
            }
            finally
            {
                span.End();
            }
        }
        private void PublishMessage(IMessage message, string destination, bool forceDestination, Action <IMessage, string, bool> publish,
                                    IExecutionSegment transaction, string name)
        {
            var span = transaction.StartSpan(name, SpanType);

            try
            {
                var traceParent           = $"00-{transaction.TraceId}-{span.Id}-01";
                var traceAsyncTransaction = _config.GetValue <bool>(EnvironmentConstants.ApmTraceAsyncTransaction);
                message.Headers[ApmConstants.TraceParent] = traceParent;
                message.Headers[ApmConstants.ApmTraceAsyncTransaction] = traceAsyncTransaction;
                publish(message, destination, forceDestination);
            }
            catch (Exception ex)
            {
                span.CaptureException(ex);
                throw;
            }
            finally
            {
                span.End();
            }
        }
        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;
            }
        }
Example #6
0
        private void StartSpan <TState>(IExecutionSegment currentExecutionSegment, TState state)
        {
            if (state is string)
            {
                currentExecutionSegment.StartSpan(state.ToString(), ApmOptions.DefaultSpanType);
            }
            else if (state is IEnumerable <KeyValuePair <string, object> > Properties)
            {
                var propDic = new Dictionary <string, object>();
                foreach (var item in Properties)
                {
                    if (!propDic.ContainsKey(item.Key))
                    {
                        propDic.Add(item.Key, item.Value);
                    }
                }

                string apmSpanType = propDic.ContainsKey(nameof(apmSpanType)) ? propDic[nameof(apmSpanType)].ToString() : ApmOptions.DefaultSpanType;
                string apmSpanName = propDic.ContainsKey(nameof(apmSpanName)) ? propDic[nameof(apmSpanName)].ToString() : ApmOptions.DefaultSpanName;
                var    span        = currentExecutionSegment.StartSpan(apmSpanName, apmSpanType);

                AddMetadata(span, propDic);
            }
        }
        private static async Task <T> PublishMessageAndWait <T>(IMessage message, string destination, bool forceDestination,
                                                                int milliSecondsTimeout, Func <IMessage, string, bool, int, Task <T> > publishAndWait, IExecutionSegment transaction, string name) where T : IMessage
        {
            var span = transaction.StartSpan(name, SpanType);

            try
            {
                var traceParent = $"00-{transaction.TraceId}-{span.Id}-01";
                message.Headers[ApmConstants.TraceParent] = traceParent;
                message.Headers[ApmConstants.ApmTraceAsyncTransaction] = true;
                return(await publishAndWait(message, destination, forceDestination, milliSecondsTimeout));
            }
            catch (Exception ex)
            {
                span.CaptureException(ex);
                throw;
            }
            finally
            {
                span.End();
            }
        }
 public ElasticSpan(IExecutionSegment segment)
 {
     this._segment = segment;
 }
Example #9
0
        /// <summary>
        /// Try to inject the trace context into the Kafka message headers
        /// </summary>
        /// <param name="agent">The agent</param>
        /// <param name="segment">The outgoing distributed tracing data to propagate</param>
        /// <param name="message">The duck-typed Kafka Message object</param>
        /// <typeparam name="TTopicPartitionMarker">The TopicPartition type (used  optimisation purposes)</typeparam>
        /// <typeparam name="TMessage">The type of the duck-type proxy</typeparam>
        internal static void TryInjectHeaders <TTopicPartitionMarker, TMessage>(IApmAgent agent, IExecutionSegment segment, TMessage message)
            where TMessage : IMessage
        {
            if (!HeadersInjectionEnabled)
            {
                return;
            }

            try
            {
                message.Headers ??= CachedMessageHeadersHelper <TTopicPartitionMarker> .CreateHeaders();

                var adapter = new KafkaHeadersCollection(message.Headers, agent.Logger);
                var distributedTracingData = segment.OutgoingDistributedTracingData;
                adapter.Set(TraceContext.TraceParentBinaryHeaderName, distributedTracingData.SerializeToString());
                adapter.Set(TraceContext.TraceStateHeaderName, distributedTracingData.TraceState.ToTextHeader());
            }
            catch (Exception ex)
            {
                // don't keep trying if we run into problems
                HeadersInjectionEnabled = false;
                agent.Logger.Warning()?.LogException(ex, "There was a problem injecting headers into the Kafka record. Disabling headers injection");
            }
        }