From a8d00c1fdf52ab3b4ca61e3588537a7a07f2c07c Mon Sep 17 00:00:00 2001 From: satvu Date: Thu, 22 Jan 2026 14:12:47 -0800 Subject: [PATCH 1/5] works e2e --- .../src/proto/FunctionRpc.proto | 2 + .../Diagnostics/TraceConstants.cs | 16 ++++++++ src/DotNetWorker.Core/FunctionsApplication.cs | 5 +++ .../Handlers/InvocationHandler.cs | 37 ++++++++++++++++++- 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/protos/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto b/protos/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto index 64162e12d..616451f11 100644 --- a/protos/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto +++ b/protos/azure-functions-language-worker-protobuf/src/proto/FunctionRpc.proto @@ -442,6 +442,8 @@ message InvocationResponse { // Status of the invocation (success/failure/canceled) StatusResult result = 3; + + RpcTraceContext trace_context = 5; } message WorkerWarmupRequest { diff --git a/src/DotNetWorker.Core/Diagnostics/TraceConstants.cs b/src/DotNetWorker.Core/Diagnostics/TraceConstants.cs index d6120c997..7b83cd5a9 100644 --- a/src/DotNetWorker.Core/Diagnostics/TraceConstants.cs +++ b/src/DotNetWorker.Core/Diagnostics/TraceConstants.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System.Collections.Generic; + namespace Microsoft.Azure.Functions.Worker.Diagnostics; internal static class TraceConstants @@ -40,8 +42,22 @@ public static class OTelAttributes_1_37_0 public const string SchemaVersion = "https://opentelemetry.io/schemas/1.37.0"; } + public static class KnownAttributes + { + public static IReadOnlyList All { get; } = new List + { + OTelAttributes_1_17_0.InvocationId, + OTelAttributes_1_17_0.SchemaUrl, + OTelAttributes_1_37_0.InvocationId, + OTelAttributes_1_37_0.FunctionName, + OTelAttributes_1_37_0.Instance, + OTelAttributes_1_37_0.SchemaUrl, + }; + } + public static class InternalKeys { + public const string FunctionContextItemsKey = "TagsForFunctionActivity"; public const string FunctionInvocationId = "AzureFunctions_InvocationId"; public const string FunctionName = "AzureFunctions_FunctionName"; public const string HostInstanceId = "HostInstanceId"; diff --git a/src/DotNetWorker.Core/FunctionsApplication.cs b/src/DotNetWorker.Core/FunctionsApplication.cs index 40157f9c0..53ea2fb61 100644 --- a/src/DotNetWorker.Core/FunctionsApplication.cs +++ b/src/DotNetWorker.Core/FunctionsApplication.cs @@ -74,6 +74,11 @@ public async Task InvokeFunctionAsync(FunctionContext context) try { await _functionExecutionDelegate(context); + var tags = invokeActivity?.Tags.ToDictionary(kv => kv.Key, kv => kv.Value); + if (tags is not null) + { + context.Items.Add(TraceConstants.InternalKeys.FunctionContextItemsKey, tags); + } } catch (Exception ex) { diff --git a/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs b/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs index 07a5300ce..c9cc65c68 100644 --- a/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs +++ b/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs @@ -1,12 +1,17 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System; using System.Collections.Concurrent; +using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Azure.Core; +using Google.Protobuf.Collections; using Microsoft.Azure.Functions.Worker.Context.Features; using Microsoft.Azure.Functions.Worker.Core; +using Microsoft.Azure.Functions.Worker.Diagnostics; using Microsoft.Azure.Functions.Worker.Grpc; using Microsoft.Azure.Functions.Worker.Grpc.Features; using Microsoft.Azure.Functions.Worker.Grpc.Messages; @@ -112,6 +117,9 @@ public async Task InvokeAsync(InvocationRequest request) response.ReturnValue = returnVal; } + RpcTraceContext traceContext = AddTraceContextTags(request, context); + response.TraceContext = traceContext; + response.Result.Status = StatusResult.Types.Status.Success; } catch (Exception ex) when (!ex.IsFatal()) @@ -163,5 +171,32 @@ public bool TryCancel(string invocationId) return false; } + + private RpcTraceContext AddTraceContextTags(InvocationRequest request, FunctionContext context) + { + RpcTraceContext traceContext = new RpcTraceContext + { + TraceParent = request.TraceContext.TraceParent, + TraceState = request.TraceContext.TraceState, + Attributes = { } + }; + + var invocationTags = context.Items.TryGetValue(TraceConstants.InternalKeys.FunctionContextItemsKey, out var tagsObj) + ? tagsObj as System.Collections.Generic.IDictionary + : null; + + if (invocationTags is not null) + { + foreach (var tag in invocationTags) + { + if (!TraceConstants.KnownAttributes.All.Contains(tag.Key)) + { + traceContext.Attributes[tag.Key] = tag.Value; + } + } + } + + return traceContext; + } } } From d7fc58e065437cc312f28d5962b560cc9b090955 Mon Sep 17 00:00:00 2001 From: sarah <35204912+satvu@users.noreply.github.com> Date: Fri, 23 Jan 2026 16:00:36 -0800 Subject: [PATCH 2/5] Update src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs b/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs index c9cc65c68..ee74be929 100644 --- a/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs +++ b/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Azure.Core; using Google.Protobuf.Collections; using Microsoft.Azure.Functions.Worker.Context.Features; using Microsoft.Azure.Functions.Worker.Core; From 6b92dbdf2604641215b86c03b5abda9a56592103 Mon Sep 17 00:00:00 2001 From: sarah <35204912+satvu@users.noreply.github.com> Date: Fri, 23 Jan 2026 16:01:16 -0800 Subject: [PATCH 3/5] Update src/DotNetWorker.Core/FunctionsApplication.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/DotNetWorker.Core/FunctionsApplication.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotNetWorker.Core/FunctionsApplication.cs b/src/DotNetWorker.Core/FunctionsApplication.cs index 53ea2fb61..b46e71a33 100644 --- a/src/DotNetWorker.Core/FunctionsApplication.cs +++ b/src/DotNetWorker.Core/FunctionsApplication.cs @@ -77,7 +77,7 @@ public async Task InvokeFunctionAsync(FunctionContext context) var tags = invokeActivity?.Tags.ToDictionary(kv => kv.Key, kv => kv.Value); if (tags is not null) { - context.Items.Add(TraceConstants.InternalKeys.FunctionContextItemsKey, tags); + context.Items[TraceConstants.InternalKeys.FunctionContextItemsKey] = tags; } } catch (Exception ex) From 26704559317429c7080ccdf5783e2ab0cd28f32b Mon Sep 17 00:00:00 2001 From: sarah <35204912+satvu@users.noreply.github.com> Date: Fri, 23 Jan 2026 16:01:53 -0800 Subject: [PATCH 4/5] Update src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs b/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs index ee74be929..04f950512 100644 --- a/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs +++ b/src/DotNetWorker.Grpc/Handlers/InvocationHandler.cs @@ -186,12 +186,9 @@ private RpcTraceContext AddTraceContextTags(InvocationRequest request, FunctionC if (invocationTags is not null) { - foreach (var tag in invocationTags) + foreach (var tag in invocationTags.Where(tag => !TraceConstants.KnownAttributes.All.Contains(tag.Key))) { - if (!TraceConstants.KnownAttributes.All.Contains(tag.Key)) - { - traceContext.Attributes[tag.Key] = tag.Value; - } + traceContext.Attributes[tag.Key] = tag.Value; } } From 3c5197c35edf0148db6718ab8c6bb1407c058ad4 Mon Sep 17 00:00:00 2001 From: satvu Date: Fri, 23 Jan 2026 16:05:07 -0800 Subject: [PATCH 5/5] fix dictionary conversion --- src/DotNetWorker.Core/FunctionsApplication.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/DotNetWorker.Core/FunctionsApplication.cs b/src/DotNetWorker.Core/FunctionsApplication.cs index 53ea2fb61..b189c35ee 100644 --- a/src/DotNetWorker.Core/FunctionsApplication.cs +++ b/src/DotNetWorker.Core/FunctionsApplication.cs @@ -74,7 +74,9 @@ public async Task InvokeFunctionAsync(FunctionContext context) try { await _functionExecutionDelegate(context); - var tags = invokeActivity?.Tags.ToDictionary(kv => kv.Key, kv => kv.Value); + var tags = invokeActivity?.Tags + .GroupBy(kv => kv.Key) + .ToDictionary(g => g.Key, g => g.Last().Value); if (tags is not null) { context.Items.Add(TraceConstants.InternalKeys.FunctionContextItemsKey, tags);