private void HandleStart(RabbitMqEvent <RabbitMqHandleParams> evt) { try { var prms = evt.Params; DistributedTracingData tracingData = null; if (prms.Properties != null && prms.Properties.Headers.TryGetValue(Constants.HeaderKey, out object tracingDataBlob) && tracingDataBlob is byte[]) { tracingData = DistributedTracingData.TryDeserializeFromString(Encoding.UTF8.GetString((byte[])tracingDataBlob)); } if (MatchesIgnoreMessageQueues(prms.RoutingKey)) { return; } var transaction = _ApmAgent.Tracer.StartTransaction(prms.RoutingKey, Constants.Type, tracingData); if (!_processingQueries.TryAdd(prms.Id, transaction)) { return; } transaction.SetLabel(nameof(prms.RoutingKey), prms.RoutingKey); transaction.SetLabel(nameof(prms.ConsumerTag), prms.ConsumerTag); transaction.SetLabel(nameof(prms.DeliveryTag), $"{prms.DeliveryTag}"); transaction.SetLabel(nameof(prms.Exchange), prms.Exchange); transaction.SetLabel(nameof(prms.Redelivered), $"{prms.ConsumerTag}"); transaction.SetLabel(nameof(prms.Body), prms.Body != null ? System.Text.Encoding.UTF8.GetString(prms.Body) : string.Empty); } catch { } }
/// <inheritdoc /> public IApmSpan Start(string spanKind, string operationName, string type, IDictionary <string, string> existingContext = null, string resourceName = null) { if (!global::Elastic.Apm.Agent.IsConfigured) { return(NullApmSpan.Instance); } var tracer = global::Elastic.Apm.Agent.Tracer; DistributedTracingData?distributedTracingData = null; if (existingContext != null && existingContext.TryGetValue("ElasticDTD", out var d)) { distributedTracingData = DistributedTracingData.TryDeserializeFromString(d); } if (tracer.CurrentTransaction == null) { return(new ElasticSpan(tracer.StartTransaction( operationName, type, distributedTracingData))); } return(new ElasticSpan( tracer.CurrentTransaction.StartSpan(operationName, type, resourceName))); }
private static void Main(string[] args) { if (args.Length == 1) //in case it's started with an argument we try to parse the argument as a DistributedTracingData { WriteLineToConsole($"Callee process started - continuing trace with distributed tracing data: {args[0]}"); var transaction2 = Agent.Tracer.StartTransaction("Transaction2", "TestTransaction", DistributedTracingData.TryDeserializeFromString(args[0])); try { transaction2.CaptureSpan("TestSpan", "TestSpanType", () => Thread.Sleep(200)); } finally { transaction2.End(); } Thread.Sleep(1000); WriteLineToConsole("About to exit"); } else { WriteLineToConsole("Started"); PassDistributedTracingData(); //WIP: if the process terminates the agent //potentially does not have time to send the transaction to the server. Thread.Sleep(1000); WriteLineToConsole("About to exit - press any key..."); Console.ReadKey(); } }
public override IDisposable Consume(IQueue queue, Func <byte[], MessageProperties, MessageReceivedInfo, Task> onMessage, Action <IConsumerConfiguration> configure) { async Task NewOnMessage(byte[] body, MessageProperties properties, MessageReceivedInfo receivedInfo) { if (!Agent.IsConfigured) { await onMessage(body, properties, receivedInfo).ConfigureAwait(false); return; } DistributedTracingData tracingData = null; if (properties.Headers.ContainsKey("traceparent") && properties.Headers["traceparent"] is string traceparent) { tracingData = DistributedTracingData.TryDeserializeFromString(traceparent); } var transaction = Agent.Tracer.StartTransaction(receivedInfo.Queue, "event", tracingData); try { await onMessage(body, properties, receivedInfo).ConfigureAwait(false); } finally { transaction.End(); } } return(base.Consume(queue, NewOnMessage, configure)); }
public static DistributedTracingData GetTracingData(string traceId, string parentId, bool flagRecorded) { //NOTE: Not ideal - this really should just be using the constructor but it is marked private var serialized = TraceParent.BuildTraceparent(traceId, parentId, flagRecorded); return(DistributedTracingData.TryDeserializeFromString(serialized)); }
/// <inheritdoc /> public IApmSpan StartOperation(ApiOperationDescriptor operation, string spanKind, IDictionary <string, string> existingContext = null) { if (!global::Elastic.Apm.Agent.IsConfigured) { return(NullApmSpan.Instance); } var tracer = global::Elastic.Apm.Agent.Tracer; if (tracer.CurrentTransaction != null) { // If a transaction is already underway we want to set it's name for a more accurate picture (i.e. this is // a HTTP call but we want to use the operation name not the HTTP route name). tracer.CurrentTransaction.Name = operation.Name; // We will also start a new span as there may be work before and after in the framework that should // be tracked separately from the Blueprint processing work. return(new ElasticSpan( tracer.CurrentTransaction.StartSpan(operation.Name, ApiConstants.TypeRequest, "operation", ApiConstants.ActionExec))); } DistributedTracingData?distributedTracingData = null; if (existingContext != null && existingContext.TryGetValue("ElasticDTD", out var d)) { distributedTracingData = DistributedTracingData.TryDeserializeFromString(d); } return(new ElasticSpan(tracer.StartTransaction( operation.Name, spanKind, distributedTracingData))); }
public void HandleProcessError_should_call_CaptureTransaction_as_expected(Message message, bool withTransactionName, bool withTrace) { var transactionName = withTransactionName ? TransactionName : HandleProcessErrorTransaction; var traceParent = withTrace ? DistributedTracingData.TryDeserializeFromString(TraceParent) : null; _elasticApmMessageProcessor.HandleProcessError(message, _publisherMock.Object, new Exception(), _processorMock.Object.HandleProcessError); _elasticApmTracerMock.Verify(e => e.CaptureTransaction(transactionName, It.IsAny <string>(), It.IsAny <Func <bool> >(), traceParent)); }
public void ProcessMessage_should_call_CaptureTransaction_as_expected(Message message, bool withTransactionName, bool withTrace) { var transactionName = withTransactionName ? TransactionName : ProcessMessageTransacion; var traceParent = withTrace ? DistributedTracingData.TryDeserializeFromString(TraceParent) : null; _elasticApmMessageProcessor.ProcessMessage(message, _publisherMock.Object, _processorMock.Object.ProcessMessage); _elasticApmTracerMock.Verify(e => e.CaptureTransaction(transactionName, It.IsAny <string>(), It.IsAny <Action>(), traceParent)); }
private DistributedTracingData getDistributedTracingData(ServerCallContext context) { Metadata.Entry metadataEntry = context.RequestHeaders.FirstOrDefault(m => String.Equals(m.Key.ToLower(), "elastic-apm-traceparent", StringComparison.Ordinal)); DistributedTracingData distributedTracingData = null; if (metadataEntry != null && !metadataEntry.Equals(default(Metadata.Entry)) && metadataEntry.Value != null) { distributedTracingData = DistributedTracingData.TryDeserializeFromString(metadataEntry.Value); } return(distributedTracingData); }
static void Main(string[] args) { if (args.Length == 1) //in case it's started with an argument we try to parse the argument as a DistributedTracingData { Console.WriteLine($"Process started - continuing trace with distributed tracing data: {args[0]}"); var distributedTracingData = DistributedTracingData.TryDeserializeFromString(args[0]); var transaction2 = Agent.Tracer.StartTransaction("Transaction2", "TestTransaction", distributedTracingData); try { transaction2.CaptureSpan("TestSpan", "TestSpanType", () => Thread.Sleep(200)); } finally { transaction2.End(); } Thread.Sleep(2000); Console.WriteLine("About to exit - press any key..."); Console.ReadKey(); } else { Console.WriteLine("Started"); Console.WriteLine("Capturing a transaction"); var transaction = Agent.Tracer.StartTransaction("Transaction1", "TestTransaction"); try { var outgoingDistributedTracingData = Agent.Tracer.CurrentTransaction?.OutgoingDistributedTracingData?.SerializeToString(); Console.WriteLine($"The value of the distributed tracing data: {outgoingDistributedTracingData}"); Console.WriteLine($"Waiting 20 sec to continue the trace"); Thread.Sleep(20000); } finally { transaction.End(); } //WIP: if the process terminates the agent //potentially does not have time to send the transaction to the server. Console.WriteLine("About to exit - press any key..."); Console.ReadKey(); } }
public async Task <CommandResult> Handle(TCommand command, RequestContext context) { var commandName = command.GetType().FullName; bool shouldCreateSpan = traceSettings?.ShouldCreateSpan(commandName) ?? false; CommandResult commandResult = null; if (!shouldCreateSpan) { commandResult = await decoratedRequestHandler.Handle(command, context); } if (!context.Headers.ContainsKey(DistributedTracingHeader.DistributedTracingDataKey)) { string outgoingDistributedTracingData = (tracer.CurrentSpan?.OutgoingDistributedTracingData ?? tracer.CurrentTransaction?.OutgoingDistributedTracingData)?.SerializeToString(); context.Headers.Add(DistributedTracingHeader.DistributedTracingDataKey, outgoingDistributedTracingData); } if (tracer.CurrentTransaction == null) { await tracer.CaptureTransaction(commandName.ToTransactionName(), commandName.ToTransactionType(), async(transaction) => { // transaction.Labels["TK"] = "kadirzade"; await tracer.CurrentTransaction.CaptureSpan(commandName.ToSpanName(), commandName.ToSpanType(), async(span) => { commandResult = await decoratedRequestHandler.Handle(command, context); }); }, DistributedTracingData.TryDeserializeFromString(context.Headers[DistributedTracingHeader.DistributedTracingDataKey])); } else { await tracer.CurrentTransaction.CaptureSpan(commandName.ToSpanName(), commandName.ToSpanType(), async (span) => { commandResult = await decoratedRequestHandler.Handle(command, context); span.Labels["result"] = commandResult.FormatResult(); }); } return(commandResult); }
public async Task <QueryResult <TResponse> > Handle(TQuery query, RequestContext context) { var queryName = query.GetType().FullName; bool shouldCreateSpan = traceSettings?.ShouldCreateSpan(queryName) ?? false; QueryResult <TResponse> queryResult = null; if (!shouldCreateSpan) { queryResult = await decoratedRequestHandler.Handle(query, context); } if (!context.Headers.ContainsKey(DistributedTracingHeader.DistributedTracingDataKey)) { string outgoingDistributedTracingData = (tracer.CurrentSpan?.OutgoingDistributedTracingData ?? tracer.CurrentTransaction?.OutgoingDistributedTracingData)?.SerializeToString(); context.Headers.Add(DistributedTracingHeader.DistributedTracingDataKey, outgoingDistributedTracingData); } if (tracer.CurrentTransaction == null) { await tracer.CaptureTransaction(queryName.ToTransactionName(), queryName.ToTransactionType(), async() => { await tracer.CurrentTransaction.CaptureSpan(queryName.ToSpanName(), queryName.ToSpanType(), async(span) => { queryResult = await decoratedRequestHandler.Handle(query, context); }); }, DistributedTracingData.TryDeserializeFromString(context.Headers[DistributedTracingHeader.DistributedTracingDataKey])); } else { await tracer.CurrentTransaction.CaptureSpan(queryName.ToSpanName(), queryName.ToSpanType(), async (span) => { queryResult = await decoratedRequestHandler.Handle(query, context); span.Labels["result"] = queryResult.FormatResult(); span.Type = ""; }); } return(queryResult); }
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; } }
public override Task <bool> ReceiveAsync <T>(T message, QueueMessageContext messageContext, ReceiveAsyncDelegate <T>?callback = null) { var tracer = GetTracer(); if (tracer != null) { var transaction = tracer.CurrentTransaction; if (transaction == null) { return(tracer.CaptureTransaction($"Process {message.GetType().FullName}", ApiConstants.TypeRequest, () => base.ReceiveAsync(message, messageContext, callback), DistributedTracingData.TryDeserializeFromString(messageContext.RequestId))); } return(transaction.CaptureSpan($"Process {message.GetType().FullName}", ApiConstants.TypeExternal, () => base.ReceiveAsync(message, messageContext, callback), "Queue")); } return(base.ReceiveAsync(message, messageContext, callback)); }
public bool HandleProcessError(IMessage message, IPublisher publisher, Exception error, Func <IMessage, IPublisher, Exception, bool> handleProcessError) { var method = new StackFrame().GetMethod(); var name = GetName(message, method, handleProcessError.GetMethodInfo().Name); if (!message.Headers.ContainsKey(ApmConstants.TraceParent)) { return(_elasticApmtracer.CaptureTransaction(name, TransactionType, () => handleProcessError(message, publisher, error))); } var traceParent = message.Headers[ApmConstants.TraceParent].ToString(); return(_elasticApmtracer.CaptureTransaction(name, TransactionType, () => handleProcessError(message, publisher, error), DistributedTracingData.TryDeserializeFromString(traceParent))); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAllElasticApm(_configuration); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { var output = new StringBuilder(); output.Append("<ul>"); output.Append("<li><a href=\"/trans1/1\">Distributed Transaction 1</a></li>"); output.Append("<li><a href=\"/trans2\">Distributed Transaction 2</a></li>"); output.Append("</ul>"); context.Response.ContentType = "text/html"; await context.Response.WriteAsync(output.ToString()); }); endpoints.MapGet("/trans1/1", async context => { var trans = Agent.Tracer.StartTransaction("Dist Trans 1", ApiConstants.TypeRequest); await trans.CaptureSpan("step 1 processing", ApiConstants.ActionExec, async() => await Task.Delay(30)); trans.End(); var trace = trans.OutgoingDistributedTracingData.SerializeToString(); await context.Response.WriteAsync($"<a href=\"/trans1/2?s={trace}\">Continue</a>"); }); endpoints.MapGet("/trans1/2", async context => { var deser = DistributedTracingData.TryDeserializeFromString(context.Request.Query["s"]); var trans = Agent.Tracer.StartTransaction("Dist Trans 1", ApiConstants.TypeRequest, deser); await trans.CaptureSpan("step 2 processing", ApiConstants.ActionExec, async() => await Task.Delay(15)); trans.End(); var trace = trans.OutgoingDistributedTracingData.SerializeToString(); await context.Response.WriteAsync($"<a href=\"/trans1/3?s={trace}\">Continue</a>"); }); endpoints.MapGet("/trans1/3", async context => { var deser = DistributedTracingData.TryDeserializeFromString(context.Request.Query["s"]); var trans = Agent.Tracer.StartTransaction("Dist Trans 1", ApiConstants.TypeRequest, deser); await trans.CaptureSpan("step 3 processing", ApiConstants.ActionExec, async() => await Task.Delay(40)); trans.End(); await context.Response.WriteAsync($"<a href=\"/trans1/1\">Restart</a> / <a href=\"/\">Exit</a>"); }); endpoints.MapGet("/trans2", async context => { // transaction 1 var trans1 = Agent.Tracer.StartTransaction("Dist Trans 2", ApiConstants.TypeRequest); await trans1.CaptureSpan("step 1 processing", ApiConstants.ActionExec, async() => await Task.Delay(30)); trans1.End(); // transaction 2 var trans2 = Agent.Tracer.StartTransaction("Dist Trans 2", ApiConstants.TypeRequest, DistributedTracingData.TryDeserializeFromString(trans1.OutgoingDistributedTracingData.SerializeToString())); await trans2.CaptureSpan("step 2 processing", ApiConstants.ActionExec, async() => await Task.Delay(30)); trans2.End(); // transaction 3 var trans3 = Agent.Tracer.StartTransaction("Dist Trans 2", ApiConstants.TypeRequest, DistributedTracingData.TryDeserializeFromString(trans2.OutgoingDistributedTracingData.SerializeToString())); await trans3.CaptureSpan("step 3 processing", ApiConstants.ActionExec, async() => await Task.Delay(30)); trans3.End(); await context.Response.WriteAsync($"<a href=\"/trans2\">Restart</a> / <a href=\"/\">Exit</a>"); }); }); }
private static DistributedTracingData BuildDistributedTracingData(string traceId, string parentId, string traceFlags) => DistributedTracingData.TryDeserializeFromString( "00-" + // version (traceId == null ? "" : $"{traceId}") + (parentId == null ? "" : $"-{parentId}") + (traceFlags == null ? "" : $"-{traceFlags}"));
public void ProcessMessage(IMessage message, IPublisher publisher, Action <IMessage, IPublisher> processMessage) { var method = new StackFrame().GetMethod(); var name = GetName(message, method, processMessage.GetMethodInfo().Name); var traceAsyncTransaction = GetTraceAsyncTransaction(message); if (message.Headers.ContainsKey(ApmConstants.TraceParent) && traceAsyncTransaction) { var traceParent = message.Headers[ApmConstants.TraceParent].ToString(); _elasticApmtracer.CaptureTransaction(name, TransactionType, () => processMessage(message, publisher), DistributedTracingData.TryDeserializeFromString(traceParent)); } else { _elasticApmtracer.CaptureTransaction(name, TransactionType, () => processMessage(message, publisher)); } }