internal bool TryStartElasticsearchSpan(string name, out Span span, Uri instanceUri = null) { span = null; var transaction = ApmAgent.Tracer.CurrentTransaction; if (transaction == null) { return(false); } span = (Span)ExecutionSegmentCommon.GetCurrentExecutionSegment(ApmAgent) .StartSpan( name, ApiConstants.TypeDb, ApiConstants.SubtypeElasticsearch); span.Action = name; SetDbContext(span, instanceUri); SetDestination(span, instanceUri); var id = Activity.Current.Id; if (Spans.TryAdd(id, span)) { return(true); } Logger.Error()?.Log("Failed to register start of span in ConcurrentDictionary {SpanDetails}", span.ToString()); span = null; return(false); }
public ISpan StartSpan(IApmAgent agent, string method, Uri requestUrl, Func <string, string> headerGetter) { var resourcePath = ParseResourcePath(requestUrl.PathAndQuery); var operation = BuildOperationMoniker(method, resourcePath); var operationName = GetOperationName(operation); var spanName = operationName.Length > 4 ? $"Cosmos DB {operationName}" : "Cosmos DB"; var span = ExecutionSegmentCommon.StartSpanOnCurrentExecutionSegment(agent, spanName, ApiConstants.TypeDb, ApiConstants.SubTypeCosmosDb); if (span != null) { span.Context.Db = new Database(); foreach (var resource in resourcePath) { if (resource.Value != null) { if (resource.Key == "dbs") { span.Context.Db.Instance = resource.Value; } var propertyName = GetPropertyNameForResource(resource.Key); if (!string.IsNullOrEmpty(propertyName)) { span.Name += $" {resource.Value}"; } } } } return(span); }
private void ProcessStartEvent(TRequest request, Uri requestUrl) { Logger.Trace()?.Log("Processing start event... Request URL: {RequestUrl}", Http.Sanitize(requestUrl)); var transaction = ApmAgent.Tracer.CurrentTransaction; if (transaction == null) { Logger.Debug()?.Log("No current transaction, skip creating span for outgoing HTTP request"); return; } var span = ExecutionSegmentCommon.StartSpanOnCurrentExecutionSegment(ApmAgent, $"{RequestGetMethod(request)} {requestUrl.Host}", ApiConstants.TypeExternal, ApiConstants.SubtypeHttp, InstrumentationFlag.HttpClient, true); if (!ProcessingRequests.TryAdd(request, span)) { // Consider improving error reporting - see https://github.com/elastic/apm-agent-dotnet/issues/280 Logger.Error()?.Log("Failed to add to ProcessingRequests - ???"); return; } if (!RequestHeadersContain(request, TraceContext.TraceParentHeaderName)) { // We call TraceParent.BuildTraceparent explicitly instead of DistributedTracingData.SerializeToString because // in the future we might change DistributedTracingData.SerializeToString to use some other internal format // but here we want the string to be in W3C 'traceparent' header format. RequestHeadersAdd(request, TraceContext.TraceParentHeaderName, TraceContext.BuildTraceparent(span.OutgoingDistributedTracingData)); } if (transaction is Transaction t) { if (t.ConfigSnapshot.UseElasticTraceparentHeader) { if (!RequestHeadersContain(request, TraceContext.TraceParentHeaderNamePrefixed)) { RequestHeadersAdd(request, TraceContext.TraceParentHeaderNamePrefixed, TraceContext.BuildTraceparent(span.OutgoingDistributedTracingData)); } } } if (!RequestHeadersContain(request, TraceContext.TraceStateHeaderName) && span.OutgoingDistributedTracingData != null && span.OutgoingDistributedTracingData.HasTraceState) { RequestHeadersAdd(request, TraceContext.TraceStateHeaderName, span.OutgoingDistributedTracingData.TraceState.ToTextHeader()); } if (span is Span spanInstance) { if (!spanInstance.ShouldBeSentToApmServer) { return; } } span.Context.Http = new Http { Method = RequestGetMethod(request) }; span.Context.Http.SetUrl(requestUrl); }
/// <summary> /// Gets a profiling session for StackExchange.Redis to add redis commands to. /// Creates a profiling session per span or transaction /// </summary> /// <remarks> /// See https://stackexchange.github.io/StackExchange.Redis/Profiling_v2.html /// </remarks> /// <returns>A profiling session for the current span or transaction, or null if the agent is not enabled or not recording</returns> public ProfilingSession GetProfilingSession() { if (!Agent.Config.Enabled || !Agent.Config.Recording) { return(null); } var executionSegment = ExecutionSegmentCommon.GetCurrentExecutionSegment(_agent); var realSpan = executionSegment as Span; Transaction realTransaction = null; // don't profile when there's no real span or transaction if (realSpan is null) { realTransaction = executionSegment as Transaction; if (realTransaction is null) { return(null); } } var isSpan = realSpan != null; if (!_executionSegmentSessions.TryGetValue(executionSegment.Id, out var session)) { _logger.Trace()?.Log("Creating profiling session for {ExecutionSegment} {Id}", isSpan ? "span" : "transaction", executionSegment.Id); session = new ProfilingSession(); if (!_executionSegmentSessions.TryAdd(executionSegment.Id, session)) { _logger.Debug()?.Log("could not add profiling session to tracked sessions for {ExecutionSegment} {Id}", isSpan ? "span" : "transaction", executionSegment.Id); } if (isSpan) { realSpan.Ended += (sender, _) => EndProfilingSession(sender, session); } else { realTransaction.Ended += (sender, _) => EndProfilingSession(sender, session); } } return(session); }
private void ProcessStartEvent(TRequest request, Uri requestUrl) { Logger.Trace()?.Log("Processing start event... Request URL: {RequestUrl}", requestUrl); var transaction = _agent.Tracer.CurrentTransaction; if (transaction == null) { Logger.Debug()?.Log("No current transaction, skip creating span for outgoing HTTP request"); return; } var span = (Span)ExecutionSegmentCommon.GetCurrentExecutionSegment(_agent).StartSpan( $"{RequestGetMethod(request)} {requestUrl.Host}", ApiConstants.TypeExternal, ApiConstants.SubtypeHttp); if (!ProcessingRequests.TryAdd(request, span)) { // Consider improving error reporting - see https://github.com/elastic/apm-agent-dotnet/issues/280 Logger.Error()?.Log("Failed to add to ProcessingRequests - ???"); return; } if (!RequestHeadersContain(request, TraceParent.TraceParentHeaderName)) { // We call TraceParent.BuildTraceparent explicitly instead of DistributedTracingData.SerializeToString because // in the future we might change DistributedTracingData.SerializeToString to use some other internal format // but here we want the string to be in W3C 'traceparent' header format. RequestHeadersAdd(request, TraceParent.TraceParentHeaderName, TraceParent.BuildTraceparent(span.OutgoingDistributedTracingData)); } if (span.ShouldBeSentToApmServer) { span.Context.Http = new Http { Url = requestUrl.ToString(), Method = RequestGetMethod(request) } } ; }
private void ProcessStartEvent(TRequest request, Uri requestUrl) { if (_realAgent?.TracerInternal.CurrentSpan is Span currentSpan) { // if the current span is an exit span, don't create a span for the current request if (currentSpan.InstrumentationFlag == InstrumentationFlag.Azure || currentSpan.InstrumentationFlag == InstrumentationFlag.Elasticsearch) { return; } } Logger.Trace()?.Log("Processing start event... Request URL: {RequestUrl}", Http.Sanitize(requestUrl)); var transaction = ApmAgent.Tracer.CurrentTransaction; if (transaction == null) { Logger.Debug()?.Log("No current transaction, skip creating span for outgoing HTTP request"); return; } var method = RequestGetMethod(request); string HeaderGetter(string header) => RequestTryGetHeader(request, header, out var value) ? value : null; ISpan span = null; if (_configuration?.HasTracers ?? false) { using (var httpTracers = _configuration.GetTracers()) { foreach (var httpSpanTracer in httpTracers) { if (httpSpanTracer.IsMatch(method, requestUrl, HeaderGetter)) { span = httpSpanTracer.StartSpan(ApmAgent, method, requestUrl, HeaderGetter); if (span != null) { break; } } } } } if (span is null) { if (_configuration?.CaptureSpan ?? false) { span = ExecutionSegmentCommon.StartSpanOnCurrentExecutionSegment(ApmAgent, $"{method} {requestUrl.Host}", ApiConstants.TypeExternal, ApiConstants.SubtypeHttp, InstrumentationFlag.HttpClient, true); if (span is null) { Logger.Trace()?.Log("Could not create span for outgoing HTTP request to {RequestUrl}", Http.Sanitize(requestUrl)); return; } } else { Logger.Trace()?.Log("Skip creating span for outgoing HTTP request to {RequestUrl} as not to known service", Http.Sanitize(requestUrl)); return; } } if (!ProcessingRequests.TryAdd(request, span)) { // Consider improving error reporting - see https://github.com/elastic/apm-agent-dotnet/issues/280 Logger.Error()?.Log("Failed to add to ProcessingRequests - ???"); return; } if (!RequestHeadersContain(request, TraceContext.TraceParentHeaderName)) { // We call TraceParent.BuildTraceparent explicitly instead of DistributedTracingData.SerializeToString because // in the future we might change DistributedTracingData.SerializeToString to use some other internal format // but here we want the string to be in W3C 'traceparent' header format. RequestHeadersAdd(request, TraceContext.TraceParentHeaderName, TraceContext.BuildTraceparent(span.OutgoingDistributedTracingData)); } if (transaction is Transaction t) { if (t.ConfigSnapshot.UseElasticTraceparentHeader) { if (!RequestHeadersContain(request, TraceContext.TraceParentHeaderNamePrefixed)) { RequestHeadersAdd(request, TraceContext.TraceParentHeaderNamePrefixed, TraceContext.BuildTraceparent(span.OutgoingDistributedTracingData)); } } } if (!RequestHeadersContain(request, TraceContext.TraceStateHeaderName) && span.OutgoingDistributedTracingData != null && span.OutgoingDistributedTracingData.HasTraceState) { RequestHeadersAdd(request, TraceContext.TraceStateHeaderName, span.OutgoingDistributedTracingData.TraceState.ToTextHeader()); } if (span is Span realSpan) { if (!realSpan.ShouldBeSentToApmServer) { return; } } span.Context.Http = new Http { Method = method }; span.Context.Http.SetUrl(requestUrl); }
public ISpan StartSpan(IApmAgent agent, string method, Uri requestUrl, Func <string, string> headerGetter) { var blobUrl = new BlobUrl(requestUrl); string action = null; switch (method) { case "DELETE": action = "Delete"; break; case "GET": if (requestUrl.Query.Contains("restype=container")) { if (requestUrl.Query.Contains("comp=list")) { action = "ListBlobs"; } else if (requestUrl.Query.Contains("comp=acl")) { action = "GetAcl"; } else { action = "GetProperties"; } } else { if (requestUrl.Query.Contains("comp=metadata")) { action = "GetMetadata"; } else if (requestUrl.Query.Contains("comp=list")) { action = "ListContainers"; } else if (requestUrl.Query.Contains("comp=tags")) { action = requestUrl.Query.Contains("where=") ? "FindTags" : "GetTags"; } else { action = "Download"; } } break; case "HEAD": if (requestUrl.Query.Contains("comp=metadata")) { action = "GetMetadata"; } else if (requestUrl.Query.Contains("comp=acl")) { action = "GetAcl"; } else { action = "GetProperties"; } break; case "POST": if (requestUrl.Query.Contains("comp=batch")) { action = "Batch"; } else if (requestUrl.Query.Contains("comp=query")) { action = "Query"; } break; case "PUT": if (!string.IsNullOrEmpty(headerGetter("x-ms-copy-source"))) { action = "Copy"; } else if (requestUrl.Query.Contains("comp=copy")) { action = "Abort"; } else if (!string.IsNullOrEmpty(headerGetter("x-ms-blob-type")) || requestUrl.Query.Contains("comp=block") || requestUrl.Query.Contains("comp=blocklist") || requestUrl.Query.Contains("comp=page") || requestUrl.Query.Contains("comp=appendblock")) { action = "Upload"; } else if (requestUrl.Query.Contains("comp=metadata")) { action = "SetMetadata"; } else if (requestUrl.Query.Contains("comp=acl")) { action = "SetAcl"; } else if (requestUrl.Query.Contains("comp=properties")) { action = "SetProperties"; } else if (requestUrl.Query.Contains("comp=lease")) { action = "Lease"; } else if (requestUrl.Query.Contains("comp=snapshot")) { action = "Snapshot"; } else if (requestUrl.Query.Contains("comp=undelete")) { action = "Undelete"; } else if (requestUrl.Query.Contains("comp=tags")) { action = "SetTags"; } else if (requestUrl.Query.Contains("comp=tier")) { action = "SetTier"; } else if (requestUrl.Query.Contains("comp=expiry")) { action = "SetExpiry"; } else if (requestUrl.Query.Contains("comp=seal")) { action = "Seal"; } else { action = "Create"; } break; } if (action is null) { return(null); } var name = $"{AzureBlobStorage.SpanName} {action} {blobUrl.ResourceName}"; var span = ExecutionSegmentCommon.StartSpanOnCurrentExecutionSegment(agent, name, ApiConstants.TypeStorage, AzureBlobStorage.SubType, InstrumentationFlag.Azure, true); span.Action = action; span.Context.Destination = new Destination { Address = blobUrl.FullyQualifiedNamespace, Service = new Destination.DestinationService { Name = AzureBlobStorage.SubType, Resource = $"{AzureBlobStorage.SubType}/{blobUrl.ResourceName}", Type = ApiConstants.TypeStorage } }; if (span is Span realSpan) { realSpan.InstrumentationFlag = InstrumentationFlag.Azure; } return(span); }