diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommon.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommon.cs index 2718e159b641..7b6ea4280fe0 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommon.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommon.cs @@ -15,13 +15,15 @@ using Datadog.Trace.ClrProfiler.CallTarget; using Datadog.Trace.Configuration; using Datadog.Trace.DuckTyping; -using Datadog.Trace.Headers; +using Datadog.Trace.ExtensionMethods; using Datadog.Trace.Logging; +using Datadog.Trace.PlatformHelpers; using Datadog.Trace.Propagators; using Datadog.Trace.Tagging; using Datadog.Trace.Util; using Datadog.Trace.Util.Json; using Datadog.Trace.Vendors.Newtonsoft.Json; +using Datadog.Trace.Vendors.Serilog.Events; #nullable enable @@ -29,10 +31,16 @@ namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Azure.Functions { internal static class AzureFunctionsCommon { - public const string IntegrationName = nameof(Configuration.IntegrationId.AzureFunctions); + // Key used by the Azure Functions .NET Worker to store the ASP.NET Core HttpContext in FunctionContext.Items. + // Defined in Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore: + // https://github.com/Azure/azure-functions-dotnet-worker/blob/596a94ef97f458d68381678fec6d92585e80d83d/extensions/Worker.Extensions.Http.AspNetCore/src/Constants.cs#L14 + // Set by FunctionsHttpProxyingMiddleware: + // https://github.com/Azure/azure-functions-dotnet-worker/blob/596a94ef97f458d68381678fec6d92585e80d83d/extensions/Worker.Extensions.Http.AspNetCore/src/FunctionsMiddleware/FunctionsHttpProxyingMiddleware.cs#L124 + private const string HttpRequestContextKey = "HttpRequestContext"; + private const string SpanType = SpanTypes.Serverless; + public const string IntegrationName = nameof(Configuration.IntegrationId.AzureFunctions); public const string OperationName = AzureFunctionsConstants.AzureFunctionName; - public const string SpanType = SpanTypes.Serverless; public const string AzureApim = AzureFunctionsConstants.AzureApimName; public const IntegrationId IntegrationId = Configuration.IntegrationId.AzureFunctions; @@ -60,7 +68,7 @@ public static CallTargetState OnFunctionExecutionBegin(TTarg return new CallTargetState(scope); } - internal static Scope? CreateScope(Tracer tracer, TFunction instanceParam) + private static Scope? CreateScope(Tracer tracer, TFunction instanceParam) where TFunction : IFunctionInstance { Scope? scope = null; @@ -129,7 +137,7 @@ public static CallTargetState OnFunctionExecutionBegin(TTarg { // We don't want to create a new scope here when running isolated functions, // otherwise it is essentially a duplicate of the span created inside the - // isolated app, but we _do_ want to populate the "root" span here with the appropriate names + // isolated app. We _do_ want to populate the "root" span here with the appropriate names // and update it to be a "serverless" span. if (!isProxySpan) { @@ -139,7 +147,7 @@ public static CallTargetState OnFunctionExecutionBegin(TTarg ? functionName.Substring(10) : functionName; AzureFunctionsTags.SetRootSpanTags( - rootSpan, + rootSpan.Tags, shortName: remoteFunctionName, fullName: rootSpan.Tags is AzureFunctionsTags t ? t.FullName : null, // can't get anything meaningful here, so leave it as-is bindingSource: bindingSourceType.FullName, @@ -171,7 +179,7 @@ public static CallTargetState OnFunctionExecutionBegin(TTarg if (!isProxySpan) { AzureFunctionsTags.SetRootSpanTags( - scope.Root.Span, + scope.Root.Span.Tags, shortName: functionName, fullName: instanceParam.FunctionDescriptor.FullName, bindingSource: bindingSourceType.FullName, @@ -203,20 +211,27 @@ public static CallTargetState OnIsolatedFunctionBegin(T functionContext) { var tracer = Tracer.Instance; - if (tracer.CurrentTraceSettings.Settings.IsIntegrationEnabled(IntegrationId)) + if (!tracer.CurrentTraceSettings.Settings.IsIntegrationEnabled(IntegrationId)) { - var scope = CreateIsolatedFunctionScope(tracer, functionContext); + return CallTargetState.GetDefault(); + } - if (scope != null) - { - return new CallTargetState(scope); - } + // Look up the aspnet_core.request scope once so we can both use it as parent + // (in CreateIsolatedFunctionScope) and propagate exceptions onto it later + // (in OnAsyncMethodEnd of the calling integration). + var aspNetCoreScope = GetAspNetCoreScope(functionContext); + + var scope = CreateIsolatedFunctionScope(tracer, functionContext, aspNetCoreScope); + + if (scope == null && aspNetCoreScope == null) + { + return CallTargetState.GetDefault(); } - return CallTargetState.GetDefault(); + return new CallTargetState(scope, state: aspNetCoreScope); } - private static Scope? CreateIsolatedFunctionScope(Tracer tracer, T functionContext) + private static Scope? CreateIsolatedFunctionScope(Tracer tracer, T functionContext, Scope? aspNetCoreScope) where T : IFunctionContext { Scope? scope = null; @@ -254,8 +269,43 @@ _ when type.StartsWith("eventGrid", StringComparison.OrdinalIgnoreCase) => "Even switch (triggerType) { case "Http": - extractedContext = ExtractPropagatedContextFromHttp(functionContext, entry.Key as string).MergeBaggageInto(Baggage.Current); + { + // Detect ASP.NET Core integration by checking for HttpContext in FunctionContext.Items. + // In ASP.NET Core mode, HTTP requests are proxied directly (not via gRPC). + // The headers in the gRPC message are STALE (contain host's root span context). + // The key "HttpRequestContext" is set by FunctionsHttpProxyingMiddleware in the worker. + // Only skip gRPC extraction when we successfully retrieved the ASP.NET Core scope bridge, + // otherwise fall back to the (stale) gRPC headers to at least keep the spans in the same trace. + var isAspNetCoreIntegration = functionContext.Items?.ContainsKey(HttpRequestContextKey) == true; + + if (isAspNetCoreIntegration && aspNetCoreScope is not null) + { + // Skip gRPC header extraction in HTTP proxying mode. We already have the + // ASP.NET Core scope from the HttpContext.Items bridge and will use it as + // the parent below. + Log.Debug("Skipping header extraction - HTTP trigger with ASP.NET Core integration detected (HTTP proxying mode)"); + } + else + { + // Fall back to gRPC message extraction when not using ASP.NET Core integration, + // or when proxying is detected but the ASP.NET Core scope bridge is unavailable. + extractedContext = ExtractPropagatedContextFromHttp(functionContext, entry.Key as string).MergeBaggageInto(Baggage.Current); + + if (isAspNetCoreIntegration) + { + // ASP.NET Core integration detected but the scope bridge was not available + // (GetAspNetCoreScope returned null). Fall back to gRPC headers: the parent + // will be the host's root span (wrong, but keeps the spans in the same trace). + Log.Debug("HTTP trigger detected ASP.NET Core integration, but no active scope was found. Falling back to gRPC header extraction for trace correlation."); + } + else + { + Log.Debug("Extracted trace context from gRPC message (non-ASP.NET Core mode)"); + } + } + break; + } case "ServiceBus" when tracer.CurrentTraceSettings.Settings.IsIntegrationEnabled(IntegrationId.AzureServiceBus): extractedContext = ExtractPropagatedContextFromMessaging(functionContext, "UserProperties", "UserPropertiesArray").MergeBaggageInto(Baggage.Current); @@ -269,36 +319,72 @@ _ when type.StartsWith("eventGrid", StringComparison.OrdinalIgnoreCase) => "Even break; } - var functionName = functionContext.FunctionDefinition.Name; - if (tracer.InternalActiveScope == null) + var tags = new AzureFunctionsTags { - // This is the root scope - var tags = new AzureFunctionsTags - { - TriggerType = triggerType, - ShortName = functionName, - FullName = functionContext.FunctionDefinition.EntryPoint, - }; - tags.SetAnalyticsSampleRate(IntegrationId, tracer.CurrentTraceSettings.Settings, enabledWithGlobalSetting: false); - scope = tracer.StartActiveInternal(OperationName, tags: tags, parent: extractedContext.SpanContext); - } - else + TriggerType = triggerType, + ShortName = functionContext.FunctionDefinition.Name, + FullName = functionContext.FunctionDefinition.EntryPoint, + }; + + // Use the supplied aspnet_core.request scope (from HttpContext.Items bridge) + // if available, otherwise fall back to the existing local active scope. + var activeScope = tracer.InternalActiveScope; + + // Check if the ASP.NET Core scope is already active + if (aspNetCoreScope != null && activeScope == aspNetCoreScope) { - // shouldn't be hit, but better safe than sorry - scope = tracer.StartActiveInternal(OperationName); + // The ASP.NET Core span is already active - don't create a new span, + // just update the existing root span's tags to make it a "serverless" span. + // Don't assign to `scope`: the ASP.NET Core middleware owns this scope's + // lifetime, and returning it here would cause OnAsyncMethodEnd to dispose it. + var rootSpan = activeScope.Root.Span; - var rootSpan = scope.Root.Span; AzureFunctionsTags.SetRootSpanTags( - rootSpan, - shortName: functionName, - fullName: functionContext.FunctionDefinition.EntryPoint, + rootSpan.Tags, + shortName: tags.ShortName, + fullName: tags.FullName, bindingSource: rootSpan.Tags is AzureFunctionsTags t ? t.BindingSource : null, - triggerType: triggerType); + triggerType: tags.TriggerType); + + rootSpan.Type = SpanType; // "serverless" + rootSpan.ResourceName = $"{tags.TriggerType} {tags.ShortName}"; + } + else + { + // Create a new span with the appropriate parent context from: + // 1. Extracted from propagation headers (gRPC message from the host process). + // 2. ASP.NET Core scope (if available but not active - shouldn't happen). + // 3. Existing local span (fallback). + var parentSpanContext = extractedContext.SpanContext ?? + aspNetCoreScope?.Span.Context ?? + activeScope?.Span.Context; + + scope = tracer.StartActiveInternal(OperationName, parent: parentSpanContext, tags: tags); + var span = scope.Span; + var rootSpan = scope.Root.Span; + + if (span == rootSpan) + { + // this is the local root span + tags.SetAnalyticsSampleRate(IntegrationId, tracer.CurrentTraceSettings.Settings, enabledWithGlobalSetting: false); + } + else + { + // this is NOT the local root span, copy some tags to the root span + AzureFunctionsTags.SetRootSpanTags( + rootSpan.Tags, + shortName: tags.ShortName, + fullName: tags.FullName, + bindingSource: rootSpan.Tags is AzureFunctionsTags t ? t.BindingSource : null, + triggerType: tags.TriggerType); + + rootSpan.Type = SpanType; // "serverless" + } + + span.ResourceName = $"{tags.TriggerType} {tags.ShortName}"; + span.Type = SpanType; } - scope.Root.Span.Type = SpanType; - scope.Span.ResourceName = $"{triggerType} {functionName}"; - scope.Span.Type = SpanType; tracer.TracerManager.Telemetry.IntegrationGeneratedSpan(IntegrationId); } catch (Exception ex) @@ -311,7 +397,78 @@ _ when type.StartsWith("eventGrid", StringComparison.OrdinalIgnoreCase) => "Even return scope; } - private static PropagationContext ExtractPropagatedContextFromHttp(T context, string? bindingName) + private static Scope? GetAspNetCoreScope(T functionContext) + where T : IFunctionContext + { + // Try to retrieve the aspnet_core.request scope via the HttpContext.Items bridge. + // This is needed because AsyncLocal context doesn't reliably flow between the worker's + // ASP.NET Core pipeline and the Azure Functions worker middleware pipeline. + Scope? parentScope = null; + + try + { + if (functionContext.Items is not null && + functionContext.Items.TryGetValue(HttpRequestContextKey, out var httpContextObj) && + httpContextObj is not null && + httpContextObj.TryDuckCast(out var httpContext) && + httpContext is not null && + httpContext.Items.TryGetValue(AspNetCoreHttpRequestHandler.HttpContextActiveScopeKey, out var scopeObj) && + scopeObj is Scope aspNetCoreScope) + { + parentScope = aspNetCoreScope; + + if (Log.IsEnabled(LogEventLevel.Debug)) + { + var spanContext = parentScope.Span.Context; + + Log.Debug( + "Azure Functions: retrieved AspNetCore scope from HttpContext.Items {TraceId}-{SpanId}", + spanContext.RawTraceId, + spanContext.RawSpanId); + } + } + else + { + Log.Debug("Azure Functions: could not retrieve AspNetCore scope from HttpContext.Items"); + } + } + catch (Exception ex) + { + Log.Error(ex, "Azure Functions: error retrieving AspNetCore scope from HttpContext.Items"); + } + + return parentScope; + } + + /// + /// Propagates an exception thrown by an isolated worker user function onto the + /// aspnet_core.request span. The exception is caught internally by the worker's + /// FunctionExecutionMiddleware, so the ASP.NET Core diagnostic observer never sees it + /// and the worker's HttpContext.Response.StatusCode remains at the default 200. Mirror + /// what AspNetCoreHttpRequestHandler.HandleAspNetCoreException does, without the AppSec + /// side effects (which already ran when the request entered ASP.NET Core). + /// + public static void SetExceptionOnAspNetCoreScope(Scope aspNetCoreScope, Exception exception, Tracer tracer) + { + try + { + var span = aspNetCoreScope.Span; + var settings = tracer.CurrentTraceSettings.Settings; + + if (!span.HasHttpStatusCode()) + { + span.SetHttpStatusCode(statusCode: 500, isServer: true, settings); + } + + span.SetException(exception); + } + catch (Exception ex) + { + Log.Error(ex, "Azure Functions: error propagating user function exception to AspNetCore scope"); + } + } + + private static PropagationContext ExtractPropagatedContextFromHttp(T functionContext, string? bindingName) where T : IFunctionContext { // Need to try and grab the headers from the context @@ -319,7 +476,7 @@ private static PropagationContext ExtractPropagatedContextFromHttp(T context, // directly from the grpc call instead. This is... interesting. It // is effectively doing the equivalent of context.GetHttpRequestDataAsync() which is // the suggested approach in the docs. - if (context.Features is null || string.IsNullOrEmpty(bindingName)) + if (functionContext.Features is null || string.IsNullOrEmpty(bindingName)) { return default; } @@ -327,7 +484,7 @@ private static PropagationContext ExtractPropagatedContextFromHttp(T context, try { object? feature = null; - foreach (var keyValuePair in context.Features) + foreach (var keyValuePair in functionContext.Features) { if (keyValuePair.Key.FullName?.Equals("Microsoft.Azure.Functions.Worker.Context.Features.IFunctionBindingsFeature") == true) { diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/FunctionExecutionMiddlewareInvokeIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/FunctionExecutionMiddlewareInvokeIntegration.cs index 9aaf899bc4c5..d2ad6030355b 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/FunctionExecutionMiddlewareInvokeIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/FunctionExecutionMiddlewareInvokeIntegration.cs @@ -45,6 +45,13 @@ internal static CallTargetState OnMethodBegin(TTarget [PreserveContext] internal static TReturn OnAsyncMethodEnd(TTarget instance, TReturn returnValue, Exception exception, in CallTargetState state) { + // The worker's FunctionExecutionMiddleware catches this exception internally, + // so the aspnet_core.request span otherwise records status 200. Annotate it here. + if (exception is not null && state.State is Scope aspNetCoreScope) + { + AzureFunctionsCommon.SetExceptionOnAspNetCoreScope(aspNetCoreScope, exception, Tracer.Instance); + } + state.Scope?.DisposeWithException(exception); return returnValue; } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IFunctionContext.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IFunctionContext.cs index 6df59c1ebbc8..24d23b8369e2 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IFunctionContext.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IFunctionContext.cs @@ -18,6 +18,8 @@ internal interface IFunctionContext FunctionDefinitionStruct FunctionDefinition { get; } IEnumerable>? Features { get; } + + IDictionary? Items { get; } } #endif diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IHttpContextItems.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IHttpContextItems.cs new file mode 100644 index 000000000000..61e76253c2e0 --- /dev/null +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/IHttpContextItems.cs @@ -0,0 +1,23 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. +// + +#if !NETFRAMEWORK +#nullable enable + +using System.Collections.Generic; + +namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Azure.Functions; + +/// +/// Duck type for Microsoft.AspNetCore.Http.HttpContext, +/// used to avoid a hard assembly reference to Microsoft.AspNetCore.Http.Abstractions +/// which may not be available in non-ASP.NET Core Azure Functions workers. +/// +internal interface IHttpContextItems +{ + IDictionary Items { get; } +} + +#endif diff --git a/tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs b/tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs index 3f32a82f6567..b91abeae913d 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs @@ -85,7 +85,7 @@ private static void PropagateStableConfiguration() var tracerSettings = tracer.Settings; var mutableSettings = tracerSettings.Manager.InitialMutableSettings; - NativeInterop.SharedConfig config = new NativeInterop.SharedConfig + var config = new NativeInterop.SharedConfig { ProfilingEnabled = profilerSettings.ProfilerState switch { @@ -525,10 +525,53 @@ private static AspNetCoreDiagnosticObserver GetAspNetCoreDiagnosticObserver() [Pure] private static bool SkipAspNetCoreDiagnosticObserver() { - // this is extremely simple now, but will get more complex soon... - return AzureInfo.Instance.IsAzureFunction; + // Enable AspNetCoreDiagnosticObserver in: + // - outside Azure Functions + // - Isolated functions worker processes with extension v4 + // (to create aspnet_core.request spans that azure_functions.invoke can parent to) + + // Skip AspNetCoreDiagnosticObserver in Azure Functions: + // - In-process functions (due to AssemblyLoadContext issues) + // - Isolated functions host process (to avoid duplicate spans) + // - Isolated functions worker process with extension v1 (FUNCTIONS_EXTENSION_VERSION="~1") + + if (!AzureInfo.Instance.IsAzureFunction) + { + // We only skip AspNetCoreDiagnosticObserver in Azure Functions. + // Don't skip it outside Azure Functions. + return false; + } + + // FUNCTIONS_WORKER_RUNTIME == "dotnet-isolated" + if (!AzureInfo.Instance.IsIsolatedFunction) + { + // Skip AspNetCoreDiagnosticObserver in in-process Azure Functions + Log.Debug("Skipping AspNetCoreDiagnosticObserver: running in an in-process Azure Function."); + return true; + } + + if (AzureInfo.Instance.IsIsolatedFunctionHostProcess) + { + // Skip AspNetCoreDiagnosticObserver in Azure Functions _host_ processes + Log.Debug("Skipping AspNetCoreDiagnosticObserver: running in an isolated Azure Function host process."); + return true; + } + + // FUNCTIONS_EXTENSION_VERSION + var azureFunctionsExtensionVersion = AzureInfo.Instance.AzureFunctionsExtensionVersion; + + if (azureFunctionsExtensionVersion != "~4") + { + // Skip AspNetCoreDiagnosticObserver in v1 isolated functions (v2 and v3 are not supported at all) + // to keep the previous behavior + Log.Debug("Skipping AspNetCoreDiagnosticObserver: running in Azure Function with extension version {AzureFunctionsExtensionVersion}.", azureFunctionsExtensionVersion); + return true; + } + + // do not skip when running in an isolated Azure Functions worker process with extension v4 + return false; } -#endif +#endif // #if !NETFRAMEWORK private static void InitializeDebugger(TracerSettings tracerSettings) { diff --git a/tracer/src/Datadog.Trace/PlatformHelpers/AspNetCoreHttpRequestHandler.cs b/tracer/src/Datadog.Trace/PlatformHelpers/AspNetCoreHttpRequestHandler.cs index 5d5a56580988..4cd518cc3c90 100644 --- a/tracer/src/Datadog.Trace/PlatformHelpers/AspNetCoreHttpRequestHandler.cs +++ b/tracer/src/Datadog.Trace/PlatformHelpers/AspNetCoreHttpRequestHandler.cs @@ -5,10 +5,8 @@ #if !NETFRAMEWORK using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; -using System.Linq; using Datadog.Trace.Activity; using Datadog.Trace.Activity.DuckTypes; using Datadog.Trace.Activity.Helpers; @@ -20,14 +18,14 @@ using Datadog.Trace.DataStreamsMonitoring.TransactionTracking; using Datadog.Trace.DiagnosticListeners; using Datadog.Trace.DuckTyping; -using Datadog.Trace.ExtensionMethods; using Datadog.Trace.Headers; -using Datadog.Trace.Iast; using Datadog.Trace.Logging; using Datadog.Trace.Propagators; +using Datadog.Trace.Serverless; using Datadog.Trace.Tagging; using Datadog.Trace.Util; using Datadog.Trace.Util.Http; +using Datadog.Trace.Vendors.Serilog.Events; using Microsoft.AspNetCore.Http; namespace Datadog.Trace.PlatformHelpers @@ -35,6 +33,7 @@ namespace Datadog.Trace.PlatformHelpers internal sealed class AspNetCoreHttpRequestHandler { internal const string HttpContextTrackingKey = "__Datadog.AspNetCoreHttpRequestHandler.Tracking"; + internal const string HttpContextActiveScopeKey = "__Datadog.AspNetCoreHttpRequestHandler.ActiveScope"; private readonly IDatadogLogger _log; private readonly IntegrationId _integrationId; @@ -174,6 +173,21 @@ private Scope StartAspNetCorePipelineScope(Tracer tracer, Security security, Ias httpContext.Items[HttpContextTrackingKey] = new RequestTrackingFeature(originalPath, scope, proxyContext?.Scope); #endif + if (AzureInfo.Instance.IsAzureFunction) + { + // Store scope in HttpContext.Items for Azure Functions middleware to retrieve + httpContext.Items[HttpContextActiveScopeKey] = scope; + + if (_log.IsEnabled(LogEventLevel.Debug) && scope.Span.Context is { } spanContext) + { + _log.Debug( + "AspNetCore: Stored scope in HttpContext.Items, {TraceId}-{SpanId}, path: {Path}", + spanContext.RawTraceId, + spanContext.RawSpanId, + request.Path); + } + } + if (tracer.Settings.IpHeaderEnabled || security.AppsecEnabled) { var peerIp = new Headers.Ip.IpInfo(httpContext.Connection.RemoteIpAddress?.ToString(), httpContext.Connection.RemotePort); diff --git a/tracer/src/Datadog.Trace/Tagging/AzureFunctionsTags.cs b/tracer/src/Datadog.Trace/Tagging/AzureFunctionsTags.cs index ca01f44f2a1e..ddfe1efda70b 100644 --- a/tracer/src/Datadog.Trace/Tagging/AzureFunctionsTags.cs +++ b/tracer/src/Datadog.Trace/Tagging/AzureFunctionsTags.cs @@ -34,14 +34,13 @@ internal sealed partial class AzureFunctionsTags : InstrumentationTags public string TriggerType { get; set; } = "Unknown"; internal static void SetRootSpanTags( - Span span, + ITags tags, string shortName, string fullName, string bindingSource, string triggerType) { - var tags = span.Tags; - if (span.Tags is AspNetCoreTags aspNetTags) + if (tags is AspNetCoreTags aspNetTags) { aspNetTags.InstrumentationName = ComponentName; } @@ -51,10 +50,20 @@ internal static void SetRootSpanTags( tags.SetTag(Tags.InstrumentationName, ComponentName); } - tags.SetTag(ShortNameTagName, shortName); - tags.SetTag(FullNameTagName, fullName); - tags.SetTag(BindingSourceTagName, bindingSource); - tags.SetTag(TriggerTypeTagName, triggerType); + if (tags is AzureFunctionsTags azureFunctionsTags) + { + azureFunctionsTags.ShortName = shortName; + azureFunctionsTags.FullName = fullName; + azureFunctionsTags.BindingSource = bindingSource; + azureFunctionsTags.TriggerType = triggerType; + } + else + { + tags.SetTag(ShortNameTagName, shortName); + tags.SetTag(FullNameTagName, fullName); + tags.SetTag(BindingSourceTagName, bindingSource); + tags.SetTag(TriggerTypeTagName, triggerType); + } } } } diff --git a/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AzureFunctionsTests.cs b/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AzureFunctionsTests.cs index ed50c2b78d43..989c95ecfed1 100644 --- a/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AzureFunctionsTests.cs +++ b/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AzureFunctionsTests.cs @@ -145,6 +145,7 @@ public InProcessRuntimeV3(ITestOutputHelper output) public async Task SubmitsTraces() { using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true); + using (await RunAzureFunctionAndWaitForExit(agent)) { const int expectedSpanCount = 21; @@ -152,8 +153,7 @@ public async Task SubmitsTraces() var filteredSpans = spans.Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)).ToImmutableList(); using var s = new AssertionScope(); - filteredSpans.Count.Should().Be(expectedSpanCount); - + filteredSpans.Should().HaveCount(expectedSpanCount); await AssertInProcessSpans(filteredSpans); } } @@ -179,6 +179,7 @@ public InProcessRuntimeV4(ITestOutputHelper output) public async Task SubmitsTraces() { using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true, useStatsD: true); + using (await RunAzureFunctionAndWaitForExit(agent, framework: "net6.0")) { const int expectedSpanCount = 21; @@ -186,7 +187,7 @@ public async Task SubmitsTraces() var filteredSpans = spans.Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)).ToImmutableList(); using var s = new AssertionScope(); - + filteredSpans.Should().HaveCount(expectedSpanCount); await AssertInProcessSpans(filteredSpans); } } @@ -213,13 +214,15 @@ public IsolatedRuntimeV4SdkV1(ITestOutputHelper output) public async Task SubmitsTraces() { using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true); + using (await RunAzureFunctionAndWaitForExit(agent, expectedExitCode: -1)) { const int expectedSpanCount = 21; var spans = await agent.WaitForSpansAsync(expectedSpanCount); var filteredSpans = spans.Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)).ToImmutableList(); - using var s = new AssertionScope(); + using var s = new AssertionScope(); + filteredSpans.Should().HaveCount(expectedSpanCount); await AssertIsolatedSpans(filteredSpans, $"{nameof(AzureFunctionsTests)}.Isolated.V4.Sdk1"); } } @@ -245,16 +248,14 @@ public async Task SubmitsTraces() using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true); using (await RunAzureFunctionAndWaitForExit(agent, expectedExitCode: -1)) { - const int expectedSpanCount = 26; + const int expectedSpanCount = 31; var spans = await agent.WaitForSpansAsync(expectedSpanCount); var filteredSpans = FilterOutSocketsHttpHandler(spans); using var s = new AssertionScope(); - + spans.Should().HaveCount(expectedSpanCount); await AssertIsolatedSpans(filteredSpans.ToImmutableList(), $"{nameof(AzureFunctionsTests)}.Isolated.V4.AspNetCore1"); - - spans.Count.Should().Be(expectedSpanCount); } } } @@ -283,10 +284,13 @@ public async Task SubmitsTraces() // so we will enable them with a lot of logging SetEnvironmentVariable("DD_LOGS_DIRECT_SUBMISSION_AZURE_FUNCTIONS_HOST_ENABLED", "true"); SetEnvironmentVariable("DD_LOGS_DIRECT_SUBMISSION_MINIMUM_LEVEL", "VERBOSE"); - var hostName = "integration_ilogger_az_tests"; + const string hostName = "integration_ilogger_az_tests"; + using var logsIntake = new MockLogsIntake(); EnableDirectLogSubmission(logsIntake.Port, nameof(IntegrationId.ILogger), hostName); + using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true); + using (await RunAzureFunctionAndWaitForExit(agent, expectedExitCode: -1)) { const int expectedSpanCount = 21; @@ -294,16 +298,13 @@ public async Task SubmitsTraces() var filteredSpans = spans.Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)).ToImmutableList(); using var s = new AssertionScope(); + filteredSpans.Should().HaveCount(expectedSpanCount); await AssertIsolatedSpans(filteredSpans); - filteredSpans.Count.Should().Be(expectedSpanCount); - - var logs = logsIntake.Logs; - // ~327 (ish) logs but we kill func.exe so some logs are lost // and since sometimes the batch of logs can be 100+ it can be a LOT of logs that we lose // so just check that we have much more than when we have host logs disabled - logs.Should().HaveCountGreaterThanOrEqualTo(200); + logsIntake.Logs.Should().HaveCountGreaterThanOrEqualTo(200); } } } @@ -331,25 +332,27 @@ public async Task SubmitsTraces() { SetEnvironmentVariable("DD_LOGS_DIRECT_SUBMISSION_AZURE_FUNCTIONS_HOST_ENABLED", "false"); SetEnvironmentVariable("DD_LOGS_DIRECT_SUBMISSION_MINIMUM_LEVEL", "VERBOSE"); - var hostName = "integration_ilogger_az_tests"; + const string hostName = "integration_ilogger_az_tests"; + using var logsIntake = new MockLogsIntake(); EnableDirectLogSubmission(logsIntake.Port, nameof(IntegrationId.ILogger), hostName); using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true); + using (await RunAzureFunctionAndWaitForExit(agent, expectedExitCode: -1)) { const int expectedSpanCount = 21; var spans = await agent.WaitForSpansAsync(expectedSpanCount); - var filteredSpans = spans.Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)).ToImmutableList(); + using var s = new AssertionScope(); + filteredSpans.Should().HaveCount(expectedSpanCount); await AssertIsolatedSpans(filteredSpans, filename: $"{nameof(AzureFunctionsTests)}.Isolated.V4.HostLogsDisabled"); - filteredSpans.Count.Should().Be(expectedSpanCount); - var logs = logsIntake.Logs; // we expect some logs still from the worker process // this just seems flaky I THINK because of killing the func.exe process (even though we aren't using the host logs) // commonly see 13, 14, 15, 16 logs, but IF we were logging the host logs we'd see 300+ + var logs = logsIntake.Logs; logs.Should().HaveCountGreaterThan(10); logs.Should().HaveCountLessThanOrEqualTo(20); } @@ -374,9 +377,10 @@ public IsolatedRuntimeV4AspNetCore(ITestOutputHelper output) public async Task SubmitsTraces() { using var agent = EnvironmentHelper.GetMockAgent(useTelemetry: true); + using (await RunAzureFunctionAndWaitForExit(agent, expectedExitCode: -1)) { - const int expectedSpanCount = 26; + const int expectedSpanCount = 31; var spans = await agent.WaitForSpansAsync(expectedSpanCount); // There are _additional_ spans created for these compared to the non-AspNetCore version @@ -385,15 +389,13 @@ public async Task SubmitsTraces() // because of this they cause a lot of flake in the snapshots where they shift places // opting to just scrub them from the snapshots - we also don't think that the spans provide much // value so they may be removed from being traced. - var filteredSpans = FilterOutSocketsHttpHandler(spans); - - filteredSpans = filteredSpans.Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)).ToImmutableList(); + var filteredSpans = FilterOutSocketsHttpHandler(spans) + .Where(s => !s.Resource.Equals("Timer ExitApp", StringComparison.OrdinalIgnoreCase)) + .ToImmutableList(); using var s = new AssertionScope(); - - await AssertIsolatedSpans(filteredSpans.ToImmutableList(), $"{nameof(AzureFunctionsTests)}.Isolated.V4.AspNetCore"); - - spans.Count.Should().Be(expectedSpanCount); + spans.Should().HaveCount(expectedSpanCount); + await AssertIsolatedSpans(filteredSpans, $"{nameof(AzureFunctionsTests)}.Isolated.V4.AspNetCore"); } } } diff --git a/tracer/test/Datadog.Trace.Tests/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommonTests.cs b/tracer/test/Datadog.Trace.Tests/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommonTests.cs index 0c39c2f92a1a..452a76443567 100644 --- a/tracer/test/Datadog.Trace.Tests/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommonTests.cs +++ b/tracer/test/Datadog.Trace.Tests/ClrProfiler/AutoInstrumentation/Azure/Functions/AzureFunctionsCommonTests.cs @@ -122,6 +122,8 @@ private class MockFunctionContext : IFunctionContext public FunctionDefinitionStruct FunctionDefinition { get; set; } public IEnumerable>? Features { get; set; } + + public IDictionary? Items { get; } } // This duck types with tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Azure/Functions/Isolated/GrpcBindingsFeatureStruct.cs diff --git a/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore.verified.txt b/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore.verified.txt index 2a6e19c64b29..ec3f14a1c8fb 100644 --- a/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore.verified.txt +++ b/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore.verified.txt @@ -2,24 +2,29 @@ { TraceId: Id_1, SpanId: Id_2, - Name: azure_functions.invoke, - Resource: Timer TriggerAllTimer, + Name: aspnet_core.request, + Resource: GET /api/badrequest, Service: AzureFunctionsAllTriggers, - Type: serverless, + Type: web, + ParentId: Id_3, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.TriggerAllTimer, - aas.function.name: TriggerAllTimer, - aas.function.trigger: Timer, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: AzureFunctions, + aspnet_core.endpoint: BadRequest, + aspnet_core.route: api/badrequest, + component: aspnet_core, env: integration_tests, + http.method: GET, + http.request.headers.host: localhost:00000, + http.route: api/badrequest, + http.status_code: 400, + http.url: http://localhost:00000/api/badrequest, language: dotnet, runtime-id: Guid_1, span.kind: server @@ -33,60 +38,222 @@ }, { TraceId: Id_1, - SpanId: Id_3, - Name: http.request, - Resource: GET localhost:00000/api/trigger, - Service: AzureFunctionsAllTriggers-http-client, - Type: http, + SpanId: Id_4, + Name: azure_functions.invoke, + Resource: Http BadRequest, + Service: AzureFunctionsAllTriggers, + Type: serverless, ParentId: Id_2, Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.BadRequest, + aas.function.name: BadRequest, + aas.function.trigger: Http, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: HttpMessageHandler, + component: AzureFunctions, env: integration_tests, - http-client-handler-type: System.Net.Http.HttpClientHandler, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_5, + Name: Manual inside BadRequest, + Resource: Manual inside BadRequest, + Service: AzureFunctionsAllTriggers, + ParentId: Id_4, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_6, + Name: aspnet_core.request, + Resource: GET /api/error, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_7, + Error: 1, + Tags: { + aas.environment.extension_version: unknown, + aas.environment.instance_id: unknown, + aas.environment.instance_name: IntegrationTestHost, + aas.environment.os: unknown, + aas.environment.runtime: .NET, + aas.site.kind: functionapp, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + aspnet_core.endpoint: ServerError, + aspnet_core.route: api/error, + component: aspnet_core, + env: integration_tests, + error.msg: The HTTP response has status code 500., http.method: GET, - http.status_code: 200, - http.url: http://localhost:00000/api/trigger, + http.request.headers.host: localhost:00000, + http.route: api/error, + http.status_code: 500, + http.url: http://localhost:00000/api/error, language: dotnet, - out.host: localhost, runtime-id: Guid_1, - span.kind: client, - _dd.base_service: AzureFunctionsAllTriggers, - _dd.svc_src: http-client + span.kind: server }, Metrics: { - _dd.top_level: 1.0 + process_id: 0, + _dd.top_level: 1.0, + _dd.tracer_kr: 1.0, + _sampling_priority_v1: 1.0 } }, { TraceId: Id_1, - SpanId: Id_4, + SpanId: Id_8, Name: azure_functions.invoke, - Resource: GET /api/trigger, + Resource: Http ServerError, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_3, + ParentId: Id_6, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.ServerError, + aas.function.name: ServerError, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + component: AzureFunctions, + env: integration_tests, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_9, + Name: Manual inside ServerError, + Resource: Manual inside ServerError, + Service: AzureFunctionsAllTriggers, + ParentId: Id_8, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_10, + Name: aspnet_core.request, + Resource: GET /api/exception, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_11, + Error: 1, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.binding: Microsoft.Azure.WebJobs.Host.Executors.BindingSource, - aas.function.name: TriggerCaller, - aas.function.trigger: Http, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, + aspnet_core.endpoint: Exception, + aspnet_core.route: api/exception, + component: aspnet_core, + env: integration_tests, + error.msg: Task failed successfully., + error.stack: +System.InvalidOperationException: Task failed successfully. +at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req), + error.type: System.InvalidOperationException, + http.method: GET, + http.request.headers.host: localhost:00000, + http.route: api/exception, + http.status_code: 500, + http.url: http://localhost:00000/api/exception, + language: dotnet, + runtime-id: Guid_1, + span.kind: server + }, + Metrics: { + process_id: 0, + _dd.top_level: 1.0, + _dd.tracer_kr: 1.0, + _sampling_priority_v1: 1.0 + } + }, + { + TraceId: Id_1, + SpanId: Id_12, + Name: azure_functions.invoke, + Resource: Http Exception, + Service: AzureFunctionsAllTriggers, + Type: serverless, + ParentId: Id_10, + Error: 1, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Exception, + aas.function.name: Exception, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, component: AzureFunctions, env: integration_tests, + error.msg: Task failed successfully., + error.stack: +System.InvalidOperationException: Task failed successfully. +at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req), + error.type: System.InvalidOperationException, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_13, + Name: Manual inside Exception, + Resource: Manual inside Exception, + Service: AzureFunctionsAllTriggers, + ParentId: Id_12, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_14, + Name: aspnet_core.request, + Resource: GET /api/simple, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_15, + Tags: { + aas.environment.extension_version: unknown, + aas.environment.instance_id: unknown, + aas.environment.instance_name: IntegrationTestHost, + aas.environment.os: unknown, + aas.environment.runtime: .NET, + aas.site.kind: functionapp, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + aspnet_core.endpoint: SimpleHttpTrigger, + aspnet_core.route: api/simple, + component: aspnet_core, + env: integration_tests, http.method: GET, http.request.headers.host: localhost:00000, + http.route: api/simple, http.status_code: 200, - http.url: http://localhost:00000/api/trigger, + http.url: http://localhost:00000/api/simple, language: dotnet, - runtime-id: Guid_2, + runtime-id: Guid_1, span.kind: server }, Metrics: { @@ -98,26 +265,64 @@ }, { TraceId: Id_1, - SpanId: Id_5, + SpanId: Id_16, Name: azure_functions.invoke, - Resource: Http TriggerCaller, + Resource: Http SimpleHttpTrigger, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_4, + ParentId: Id_14, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.SimpleHttpTrigger, + aas.function.name: SimpleHttpTrigger, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + component: AzureFunctions, + env: integration_tests, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_17, + Name: Manual inside Simple, + Resource: Manual inside Simple, + Service: AzureFunctionsAllTriggers, + ParentId: Id_16, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_18, + Name: aspnet_core.request, + Resource: GET /api/trigger, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_19, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Trigger, - aas.function.name: TriggerCaller, - aas.function.trigger: Http, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: AzureFunctions, + aspnet_core.endpoint: TriggerCaller, + aspnet_core.route: api/trigger, + component: aspnet_core, env: integration_tests, + http.method: GET, + http.request.headers.host: localhost:00000, + http.route: api/trigger, + http.status_code: 200, + http.url: http://localhost:00000/api/trigger, language: dotnet, runtime-id: Guid_1, span.kind: server @@ -131,11 +336,31 @@ }, { TraceId: Id_1, - SpanId: Id_6, + SpanId: Id_20, + Name: azure_functions.invoke, + Resource: Http TriggerCaller, + Service: AzureFunctionsAllTriggers, + Type: serverless, + ParentId: Id_18, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Trigger, + aas.function.name: TriggerCaller, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + component: AzureFunctions, + env: integration_tests, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_21, Name: Manual inside Trigger, Resource: Manual inside Trigger, Service: AzureFunctionsAllTriggers, - ParentId: Id_5, + ParentId: Id_20, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -145,12 +370,12 @@ }, { TraceId: Id_1, - SpanId: Id_7, + SpanId: Id_22, Name: http.request, Resource: GET localhost:00000/api/simple, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -173,12 +398,12 @@ }, { TraceId: Id_1, - SpanId: Id_8, + SpanId: Id_23, Name: http.request, Resource: GET localhost:00000/api/exception, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -201,12 +426,12 @@ }, { TraceId: Id_1, - SpanId: Id_9, + SpanId: Id_24, Name: http.request, Resource: GET localhost:00000/api/error, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -229,12 +454,12 @@ }, { TraceId: Id_1, - SpanId: Id_10, + SpanId: Id_25, Name: http.request, Resource: GET localhost:00000/api/badrequest, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Error: 1, Tags: { aas.site.name: AzureFunctionsAllTriggers, @@ -259,12 +484,12 @@ }, { TraceId: Id_1, - SpanId: Id_11, + SpanId: Id_26, Name: azure_functions.invoke, Resource: GET /api/simple, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_7, + ParentId: Id_22, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, @@ -296,12 +521,12 @@ }, { TraceId: Id_1, - SpanId: Id_12, + SpanId: Id_27, Name: azure_functions.invoke, Resource: GET /api/exception, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_8, + ParentId: Id_23, Error: 1, Tags: { aas.environment.extension_version: unknown, @@ -342,12 +567,12 @@ at Samples.AzureFunctions.V4Isolated.AspNetCore.DirectFunctionExecutor.ExecuteAs }, { TraceId: Id_1, - SpanId: Id_13, + SpanId: Id_28, Name: azure_functions.invoke, Resource: GET /api/error, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_9, + ParentId: Id_24, Error: 1, Tags: { aas.environment.extension_version: unknown, @@ -381,12 +606,12 @@ at Samples.AzureFunctions.V4Isolated.AspNetCore.DirectFunctionExecutor.ExecuteAs }, { TraceId: Id_1, - SpanId: Id_14, + SpanId: Id_29, Name: azure_functions.invoke, Resource: GET /api/badrequest, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_10, + ParentId: Id_25, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, @@ -418,21 +643,20 @@ at Samples.AzureFunctions.V4Isolated.AspNetCore.DirectFunctionExecutor.ExecuteAs }, { TraceId: Id_1, - SpanId: Id_15, + SpanId: Id_30, Name: azure_functions.invoke, - Resource: Http SimpleHttpTrigger, + Resource: Timer TriggerAllTimer, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_11, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.SimpleHttpTrigger, - aas.function.name: SimpleHttpTrigger, - aas.function.trigger: Http, + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.TriggerAllTimer, + aas.function.name: TriggerAllTimer, + aas.function.trigger: Timer, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -451,100 +675,60 @@ at Samples.AzureFunctions.V4Isolated.AspNetCore.DirectFunctionExecutor.ExecuteAs }, { TraceId: Id_1, - SpanId: Id_16, - Name: azure_functions.invoke, - Resource: Http Exception, - Service: AzureFunctionsAllTriggers, - Type: serverless, - ParentId: Id_12, - Error: 1, - Tags: { - aas.environment.extension_version: unknown, - aas.environment.instance_id: unknown, - aas.environment.instance_name: IntegrationTestHost, - aas.environment.os: unknown, - aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Exception, - aas.function.name: Exception, - aas.function.trigger: Http, - aas.site.kind: functionapp, - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - component: AzureFunctions, - env: integration_tests, - error.msg: Task failed successfully., - error.stack: -System.InvalidOperationException: Task failed successfully. -at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req), - error.type: System.InvalidOperationException, - language: dotnet, - runtime-id: Guid_1, - span.kind: server - }, - Metrics: { - process_id: 0, - _dd.top_level: 1.0, - _dd.tracer_kr: 1.0, - _sampling_priority_v1: 1.0 - } - }, - { - TraceId: Id_1, - SpanId: Id_17, - Name: azure_functions.invoke, - Resource: Http ServerError, - Service: AzureFunctionsAllTriggers, - Type: serverless, - ParentId: Id_13, + SpanId: Id_31, + Name: http.request, + Resource: GET localhost:00000/api/trigger, + Service: AzureFunctionsAllTriggers-http-client, + Type: http, + ParentId: Id_30, Tags: { - aas.environment.extension_version: unknown, - aas.environment.instance_id: unknown, - aas.environment.instance_name: IntegrationTestHost, - aas.environment.os: unknown, - aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.ServerError, - aas.function.name: ServerError, - aas.function.trigger: Http, - aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: AzureFunctions, + component: HttpMessageHandler, env: integration_tests, + http-client-handler-type: System.Net.Http.HttpClientHandler, + http.method: GET, + http.status_code: 200, + http.url: http://localhost:00000/api/trigger, language: dotnet, + out.host: localhost, runtime-id: Guid_1, - span.kind: server + span.kind: client, + _dd.base_service: AzureFunctionsAllTriggers, + _dd.svc_src: http-client }, Metrics: { - process_id: 0, - _dd.top_level: 1.0, - _dd.tracer_kr: 1.0, - _sampling_priority_v1: 1.0 + _dd.top_level: 1.0 } }, { TraceId: Id_1, - SpanId: Id_18, + SpanId: Id_32, Name: azure_functions.invoke, - Resource: Http BadRequest, + Resource: GET /api/trigger, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_14, + ParentId: Id_31, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.BadRequest, - aas.function.name: BadRequest, + aas.function.binding: Microsoft.Azure.WebJobs.Host.Executors.BindingSource, + aas.function.name: TriggerCaller, aas.function.trigger: Http, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, component: AzureFunctions, env: integration_tests, + http.method: GET, + http.request.headers.host: localhost:00000, + http.status_code: 200, + http.url: http://localhost:00000/api/trigger, language: dotnet, - runtime-id: Guid_1, + runtime-id: Guid_2, span.kind: server }, Metrics: { @@ -553,61 +737,5 @@ at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req) _dd.tracer_kr: 1.0, _sampling_priority_v1: 1.0 } - }, - { - TraceId: Id_1, - SpanId: Id_19, - Name: Manual inside Simple, - Resource: Manual inside Simple, - Service: AzureFunctionsAllTriggers, - ParentId: Id_15, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } - }, - { - TraceId: Id_1, - SpanId: Id_20, - Name: Manual inside Exception, - Resource: Manual inside Exception, - Service: AzureFunctionsAllTriggers, - ParentId: Id_16, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } - }, - { - TraceId: Id_1, - SpanId: Id_21, - Name: Manual inside ServerError, - Resource: Manual inside ServerError, - Service: AzureFunctionsAllTriggers, - ParentId: Id_17, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } - }, - { - TraceId: Id_1, - SpanId: Id_22, - Name: Manual inside BadRequest, - Resource: Manual inside BadRequest, - Service: AzureFunctionsAllTriggers, - ParentId: Id_18, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } } ] \ No newline at end of file diff --git a/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore1.verified.txt b/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore1.verified.txt index 5ef6fca4b60e..4180c5900ea3 100644 --- a/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore1.verified.txt +++ b/tracer/test/snapshots/AzureFunctionsTests.Isolated.V4.AspNetCore1.verified.txt @@ -2,24 +2,29 @@ { TraceId: Id_1, SpanId: Id_2, - Name: azure_functions.invoke, - Resource: Timer TriggerAllTimer, + Name: aspnet_core.request, + Resource: GET /api/badrequest, Service: AzureFunctionsAllTriggers, - Type: serverless, + Type: web, + ParentId: Id_3, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.TriggerAllTimer, - aas.function.name: TriggerAllTimer, - aas.function.trigger: Timer, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: AzureFunctions, + aspnet_core.endpoint: BadRequest, + aspnet_core.route: api/badrequest, + component: aspnet_core, env: integration_tests, + http.method: GET, + http.request.headers.host: localhost:00000, + http.route: api/badrequest, + http.status_code: 400, + http.url: http://localhost:00000/api/badrequest, language: dotnet, runtime-id: Guid_1, span.kind: server @@ -33,60 +38,222 @@ }, { TraceId: Id_1, - SpanId: Id_3, - Name: http.request, - Resource: GET localhost:00000/api/trigger, - Service: AzureFunctionsAllTriggers-http-client, - Type: http, + SpanId: Id_4, + Name: azure_functions.invoke, + Resource: Http BadRequest, + Service: AzureFunctionsAllTriggers, + Type: serverless, ParentId: Id_2, Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.BadRequest, + aas.function.name: BadRequest, + aas.function.trigger: Http, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: HttpMessageHandler, + component: AzureFunctions, env: integration_tests, - http-client-handler-type: System.Net.Http.HttpClientHandler, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_5, + Name: Manual inside BadRequest, + Resource: Manual inside BadRequest, + Service: AzureFunctionsAllTriggers, + ParentId: Id_4, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_6, + Name: aspnet_core.request, + Resource: GET /api/error, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_7, + Error: 1, + Tags: { + aas.environment.extension_version: unknown, + aas.environment.instance_id: unknown, + aas.environment.instance_name: IntegrationTestHost, + aas.environment.os: unknown, + aas.environment.runtime: .NET, + aas.site.kind: functionapp, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + aspnet_core.endpoint: ServerError, + aspnet_core.route: api/error, + component: aspnet_core, + env: integration_tests, + error.msg: The HTTP response has status code 500., http.method: GET, - http.status_code: 200, - http.url: http://localhost:00000/api/trigger, + http.request.headers.host: localhost:00000, + http.route: api/error, + http.status_code: 500, + http.url: http://localhost:00000/api/error, language: dotnet, - out.host: localhost, runtime-id: Guid_1, - span.kind: client, - _dd.base_service: AzureFunctionsAllTriggers, - _dd.svc_src: http-client + span.kind: server }, Metrics: { - _dd.top_level: 1.0 + process_id: 0, + _dd.top_level: 1.0, + _dd.tracer_kr: 1.0, + _sampling_priority_v1: 1.0 } }, { TraceId: Id_1, - SpanId: Id_4, + SpanId: Id_8, Name: azure_functions.invoke, - Resource: GET /api/trigger, + Resource: Http ServerError, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_3, + ParentId: Id_6, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.ServerError, + aas.function.name: ServerError, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + component: AzureFunctions, + env: integration_tests, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_9, + Name: Manual inside ServerError, + Resource: Manual inside ServerError, + Service: AzureFunctionsAllTriggers, + ParentId: Id_8, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_10, + Name: aspnet_core.request, + Resource: GET /api/exception, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_11, + Error: 1, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.binding: Microsoft.Azure.WebJobs.Host.Executors.BindingSource, - aas.function.name: TriggerCaller, - aas.function.trigger: Http, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, + aspnet_core.endpoint: Exception, + aspnet_core.route: api/exception, + component: aspnet_core, + env: integration_tests, + error.msg: Task failed successfully., + error.stack: +System.InvalidOperationException: Task failed successfully. +at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req), + error.type: System.InvalidOperationException, + http.method: GET, + http.request.headers.host: localhost:00000, + http.route: api/exception, + http.status_code: 500, + http.url: http://localhost:00000/api/exception, + language: dotnet, + runtime-id: Guid_1, + span.kind: server + }, + Metrics: { + process_id: 0, + _dd.top_level: 1.0, + _dd.tracer_kr: 1.0, + _sampling_priority_v1: 1.0 + } + }, + { + TraceId: Id_1, + SpanId: Id_12, + Name: azure_functions.invoke, + Resource: Http Exception, + Service: AzureFunctionsAllTriggers, + Type: serverless, + ParentId: Id_10, + Error: 1, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Exception, + aas.function.name: Exception, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, component: AzureFunctions, env: integration_tests, + error.msg: Task failed successfully., + error.stack: +System.InvalidOperationException: Task failed successfully. +at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req), + error.type: System.InvalidOperationException, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_13, + Name: Manual inside Exception, + Resource: Manual inside Exception, + Service: AzureFunctionsAllTriggers, + ParentId: Id_12, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_14, + Name: aspnet_core.request, + Resource: GET /api/simple, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_15, + Tags: { + aas.environment.extension_version: unknown, + aas.environment.instance_id: unknown, + aas.environment.instance_name: IntegrationTestHost, + aas.environment.os: unknown, + aas.environment.runtime: .NET, + aas.site.kind: functionapp, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + aspnet_core.endpoint: SimpleHttpTrigger, + aspnet_core.route: api/simple, + component: aspnet_core, + env: integration_tests, http.method: GET, http.request.headers.host: localhost:00000, + http.route: api/simple, http.status_code: 200, - http.url: http://localhost:00000/api/trigger, + http.url: http://localhost:00000/api/simple, language: dotnet, - runtime-id: Guid_2, + runtime-id: Guid_1, span.kind: server }, Metrics: { @@ -98,26 +265,64 @@ }, { TraceId: Id_1, - SpanId: Id_5, + SpanId: Id_16, Name: azure_functions.invoke, - Resource: Http TriggerCaller, + Resource: Http SimpleHttpTrigger, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_4, + ParentId: Id_14, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.SimpleHttpTrigger, + aas.function.name: SimpleHttpTrigger, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + component: AzureFunctions, + env: integration_tests, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_17, + Name: Manual inside Simple, + Resource: Manual inside Simple, + Service: AzureFunctionsAllTriggers, + ParentId: Id_16, + Tags: { + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + env: integration_tests, + language: dotnet + } + }, + { + TraceId: Id_1, + SpanId: Id_18, + Name: aspnet_core.request, + Resource: GET /api/trigger, + Service: AzureFunctionsAllTriggers, + Type: web, + ParentId: Id_19, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Trigger, - aas.function.name: TriggerCaller, - aas.function.trigger: Http, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: AzureFunctions, + aspnet_core.endpoint: TriggerCaller, + aspnet_core.route: api/trigger, + component: aspnet_core, env: integration_tests, + http.method: GET, + http.request.headers.host: localhost:00000, + http.route: api/trigger, + http.status_code: 200, + http.url: http://localhost:00000/api/trigger, language: dotnet, runtime-id: Guid_1, span.kind: server @@ -131,11 +336,31 @@ }, { TraceId: Id_1, - SpanId: Id_6, + SpanId: Id_20, + Name: azure_functions.invoke, + Resource: Http TriggerCaller, + Service: AzureFunctionsAllTriggers, + Type: serverless, + ParentId: Id_18, + Tags: { + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Trigger, + aas.function.name: TriggerCaller, + aas.function.trigger: Http, + aas.site.name: AzureFunctionsAllTriggers, + aas.site.type: function, + component: AzureFunctions, + env: integration_tests, + language: dotnet, + span.kind: server + } + }, + { + TraceId: Id_1, + SpanId: Id_21, Name: Manual inside Trigger, Resource: Manual inside Trigger, Service: AzureFunctionsAllTriggers, - ParentId: Id_5, + ParentId: Id_20, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -145,12 +370,12 @@ }, { TraceId: Id_1, - SpanId: Id_7, + SpanId: Id_22, Name: http.request, Resource: GET localhost:00000/api/simple, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -173,12 +398,12 @@ }, { TraceId: Id_1, - SpanId: Id_8, + SpanId: Id_23, Name: http.request, Resource: GET localhost:00000/api/exception, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -201,12 +426,12 @@ }, { TraceId: Id_1, - SpanId: Id_9, + SpanId: Id_24, Name: http.request, Resource: GET localhost:00000/api/error, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Tags: { aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -229,12 +454,12 @@ }, { TraceId: Id_1, - SpanId: Id_10, + SpanId: Id_25, Name: http.request, Resource: GET localhost:00000/api/badrequest, Service: AzureFunctionsAllTriggers-http-client, Type: http, - ParentId: Id_6, + ParentId: Id_21, Error: 1, Tags: { aas.site.name: AzureFunctionsAllTriggers, @@ -259,12 +484,12 @@ }, { TraceId: Id_1, - SpanId: Id_11, + SpanId: Id_26, Name: azure_functions.invoke, Resource: GET /api/simple, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_7, + ParentId: Id_22, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, @@ -296,12 +521,12 @@ }, { TraceId: Id_1, - SpanId: Id_12, + SpanId: Id_27, Name: azure_functions.invoke, Resource: GET /api/exception, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_8, + ParentId: Id_23, Error: 1, Tags: { aas.environment.extension_version: unknown, @@ -341,12 +566,12 @@ at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req) }, { TraceId: Id_1, - SpanId: Id_13, + SpanId: Id_28, Name: azure_functions.invoke, Resource: GET /api/error, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_9, + ParentId: Id_24, Error: 1, Tags: { aas.environment.extension_version: unknown, @@ -380,12 +605,12 @@ at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req) }, { TraceId: Id_1, - SpanId: Id_14, + SpanId: Id_29, Name: azure_functions.invoke, Resource: GET /api/badrequest, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_10, + ParentId: Id_25, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, @@ -417,21 +642,20 @@ at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req) }, { TraceId: Id_1, - SpanId: Id_15, + SpanId: Id_30, Name: azure_functions.invoke, - Resource: Http SimpleHttpTrigger, + Resource: Timer TriggerAllTimer, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_11, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.SimpleHttpTrigger, - aas.function.name: SimpleHttpTrigger, - aas.function.trigger: Http, + aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.TriggerAllTimer, + aas.function.name: TriggerAllTimer, + aas.function.trigger: Timer, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, @@ -450,100 +674,60 @@ at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req) }, { TraceId: Id_1, - SpanId: Id_16, - Name: azure_functions.invoke, - Resource: Http Exception, - Service: AzureFunctionsAllTriggers, - Type: serverless, - ParentId: Id_12, - Error: 1, - Tags: { - aas.environment.extension_version: unknown, - aas.environment.instance_id: unknown, - aas.environment.instance_name: IntegrationTestHost, - aas.environment.os: unknown, - aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.Exception, - aas.function.name: Exception, - aas.function.trigger: Http, - aas.site.kind: functionapp, - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - component: AzureFunctions, - env: integration_tests, - error.msg: Task failed successfully., - error.stack: -System.InvalidOperationException: Task failed successfully. -at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req), - error.type: System.InvalidOperationException, - language: dotnet, - runtime-id: Guid_1, - span.kind: server - }, - Metrics: { - process_id: 0, - _dd.top_level: 1.0, - _dd.tracer_kr: 1.0, - _sampling_priority_v1: 1.0 - } - }, - { - TraceId: Id_1, - SpanId: Id_17, - Name: azure_functions.invoke, - Resource: Http ServerError, - Service: AzureFunctionsAllTriggers, - Type: serverless, - ParentId: Id_13, + SpanId: Id_31, + Name: http.request, + Resource: GET localhost:00000/api/trigger, + Service: AzureFunctionsAllTriggers-http-client, + Type: http, + ParentId: Id_30, Tags: { - aas.environment.extension_version: unknown, - aas.environment.instance_id: unknown, - aas.environment.instance_name: IntegrationTestHost, - aas.environment.os: unknown, - aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.ServerError, - aas.function.name: ServerError, - aas.function.trigger: Http, - aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, - component: AzureFunctions, + component: HttpMessageHandler, env: integration_tests, + http-client-handler-type: System.Net.Http.HttpClientHandler, + http.method: GET, + http.status_code: 200, + http.url: http://localhost:00000/api/trigger, language: dotnet, + out.host: localhost, runtime-id: Guid_1, - span.kind: server + span.kind: client, + _dd.base_service: AzureFunctionsAllTriggers, + _dd.svc_src: http-client }, Metrics: { - process_id: 0, - _dd.top_level: 1.0, - _dd.tracer_kr: 1.0, - _sampling_priority_v1: 1.0 + _dd.top_level: 1.0 } }, { TraceId: Id_1, - SpanId: Id_18, + SpanId: Id_32, Name: azure_functions.invoke, - Resource: Http BadRequest, + Resource: GET /api/trigger, Service: AzureFunctionsAllTriggers, Type: serverless, - ParentId: Id_14, + ParentId: Id_31, Tags: { aas.environment.extension_version: unknown, aas.environment.instance_id: unknown, aas.environment.instance_name: IntegrationTestHost, aas.environment.os: unknown, aas.environment.runtime: .NET, - aas.function.method: Samples.AzureFunctions.AllTriggers.AllTriggers.BadRequest, - aas.function.name: BadRequest, + aas.function.binding: Microsoft.Azure.WebJobs.Host.Executors.BindingSource, + aas.function.name: TriggerCaller, aas.function.trigger: Http, aas.site.kind: functionapp, aas.site.name: AzureFunctionsAllTriggers, aas.site.type: function, component: AzureFunctions, env: integration_tests, + http.method: GET, + http.request.headers.host: localhost:00000, + http.status_code: 200, + http.url: http://localhost:00000/api/trigger, language: dotnet, - runtime-id: Guid_1, + runtime-id: Guid_2, span.kind: server }, Metrics: { @@ -552,61 +736,5 @@ at Samples.AzureFunctions.AllTriggers.AllTriggers.Exception(HttpRequestData req) _dd.tracer_kr: 1.0, _sampling_priority_v1: 1.0 } - }, - { - TraceId: Id_1, - SpanId: Id_19, - Name: Manual inside Simple, - Resource: Manual inside Simple, - Service: AzureFunctionsAllTriggers, - ParentId: Id_15, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } - }, - { - TraceId: Id_1, - SpanId: Id_20, - Name: Manual inside Exception, - Resource: Manual inside Exception, - Service: AzureFunctionsAllTriggers, - ParentId: Id_16, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } - }, - { - TraceId: Id_1, - SpanId: Id_21, - Name: Manual inside ServerError, - Resource: Manual inside ServerError, - Service: AzureFunctionsAllTriggers, - ParentId: Id_17, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } - }, - { - TraceId: Id_1, - SpanId: Id_22, - Name: Manual inside BadRequest, - Resource: Manual inside BadRequest, - Service: AzureFunctionsAllTriggers, - ParentId: Id_18, - Tags: { - aas.site.name: AzureFunctionsAllTriggers, - aas.site.type: function, - env: integration_tests, - language: dotnet - } } ] \ No newline at end of file