Skip to content

Commit fe56653

Browse files
Adding TraceContext attributes for OTel. (#11429)
Adding TraceContext attributes for OTel.
1 parent 2a1684b commit fe56653

File tree

10 files changed

+101
-83
lines changed

10 files changed

+101
-83
lines changed

release_notes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@
1717
- Updated to version 1.5.8 of Microsoft.Azure.AppService.Middleware.Functions (#11416)
1818
- Enabling worker indexing for Logic Apps app kind behind an enviornment setting
1919
- Adding HttpWorkerFunctionProvider functions to synctrigger payload (#11430)
20-
- Remove the Flex-only AzureMonitorDiagnosticLoggerProvider filter (#11431)
20+
- Remove the Flex-only AzureMonitorDiagnosticLoggerProvider filter (#11431)
21+
- Add TraceContext attributes for OTel (#11429)

src/WebJobs.Script.Grpc/Channel/GrpcWorkerChannel.cs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,39 +1685,30 @@ private void AddAdditionalTraceContext(InvocationRequest invocationRequest, Scri
16851685
{
16861686
MapField<string, string> attributes = invocationRequest.TraceContext.Attributes;
16871687
bool isOtelEnabled = _scriptHostOptions?.Value.TelemetryMode == TelemetryMode.OpenTelemetry;
1688-
bool isAIEnabled = _environment.IsApplicationInsightsAgentEnabled();
16891688

1690-
if (isOtelEnabled || isAIEnabled)
1689+
if (context.FunctionMetadata.Properties.TryGetValue(ScriptConstants.LogPropertyHostInstanceIdKey, out var hostInstanceIdValue))
16911690
{
1692-
if (context.FunctionMetadata.Properties.TryGetValue(ScriptConstants.LogPropertyHostInstanceIdKey, out var hostInstanceIdValue))
1693-
{
1694-
string id = Convert.ToString(hostInstanceIdValue);
1691+
string id = Convert.ToString(hostInstanceIdValue);
16951692

1696-
if (isOtelEnabled)
1697-
{
1698-
Activity.Current?.AddTag(ResourceSemanticConventions.FaaSInstance, id);
1699-
}
1700-
if (isAIEnabled)
1701-
{
1702-
attributes[ScriptConstants.LogPropertyHostInstanceIdKey] = id;
1703-
}
1693+
if (isOtelEnabled)
1694+
{
1695+
Activity.Current?.AddTag(ResourceSemanticConventions.FaaSInstance, id);
17041696
}
1697+
1698+
attributes[ScriptConstants.LogPropertyHostInstanceIdKey] = id;
17051699
}
17061700

1707-
if (isAIEnabled)
1701+
attributes[ScriptConstants.LogPropertyProcessIdKey] = Convert.ToString(_rpcWorkerProcess.Id);
1702+
attributes[ScriptConstants.OperationNameKey] = context.FunctionMetadata.Name;
1703+
string sessionId = Activity.Current?.GetBaggageItem(ScriptConstants.LiveLogsSessionAIKey);
1704+
if (!string.IsNullOrEmpty(sessionId))
17081705
{
1709-
attributes[ScriptConstants.LogPropertyProcessIdKey] = Convert.ToString(_rpcWorkerProcess.Id);
1710-
attributes[ScriptConstants.OperationNameKey] = context.FunctionMetadata.Name;
1711-
string sessionId = Activity.Current?.GetBaggageItem(ScriptConstants.LiveLogsSessionAIKey);
1712-
if (!string.IsNullOrEmpty(sessionId))
1713-
{
1714-
attributes[ScriptConstants.LiveLogsSessionAIKey] = sessionId;
1715-
}
1706+
attributes[ScriptConstants.LiveLogsSessionAIKey] = sessionId;
1707+
}
17161708

1717-
if (context.FunctionMetadata.Properties.TryGetValue(LogConstants.CategoryNameKey, out var categoryNameValue))
1718-
{
1719-
attributes[LogConstants.CategoryNameKey] = Convert.ToString(categoryNameValue);
1720-
}
1709+
if (context.FunctionMetadata.Properties.TryGetValue(LogConstants.CategoryNameKey, out var categoryNameValue))
1710+
{
1711+
attributes[LogConstants.CategoryNameKey] = Convert.ToString(categoryNameValue);
17211712
}
17221713

17231714
if (isOtelEnabled)

src/WebJobs.Script/Diagnostics/OpenTelemetry/FunctionsResourceDetector.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
@@ -15,7 +15,7 @@ public Resource Detect()
1515
List<KeyValuePair<string, object>> attributeList = new(9);
1616
try
1717
{
18-
string serviceName = Environment.GetEnvironmentVariable(OpenTelemetryConstants.SiteNameEnvVar);
18+
string serviceName = Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName);
1919
string version = typeof(ScriptHost).Assembly.GetName().Version.ToString();
2020

2121
attributeList.Add(new KeyValuePair<string, object>(ResourceSemanticConventions.ServiceVersion, version));
@@ -29,7 +29,7 @@ public Resource Detect()
2929
attributeList.Add(new KeyValuePair<string, object>(ResourceSemanticConventions.CloudProvider, OpenTelemetryConstants.AzureCloudProviderValue));
3030
attributeList.Add(new KeyValuePair<string, object>(ResourceSemanticConventions.CloudPlatform, OpenTelemetryConstants.AzurePlatformValue));
3131

32-
string region = Environment.GetEnvironmentVariable(OpenTelemetryConstants.RegionNameEnvVar);
32+
string region = Environment.GetEnvironmentVariable(EnvironmentSettingNames.RegionName);
3333
if (!string.IsNullOrEmpty(region))
3434
{
3535
attributeList.Add(new KeyValuePair<string, object>(ResourceSemanticConventions.CloudRegion, region));
@@ -40,6 +40,12 @@ public Resource Detect()
4040
{
4141
attributeList.Add(new KeyValuePair<string, object>(ResourceSemanticConventions.CloudResourceId, azureResourceUri));
4242
}
43+
44+
string slotName = Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteSlotName);
45+
if (!string.IsNullOrEmpty(slotName))
46+
{
47+
attributeList.Add(new KeyValuePair<string, object>(ResourceSemanticConventions.DeploymentEnvironmentName, slotName));
48+
}
4349
}
4450
}
4551
catch
@@ -53,8 +59,8 @@ public Resource Detect()
5359

5460
private static string GetAzureResourceURI(string websiteSiteName)
5561
{
56-
string websiteResourceGroup = Environment.GetEnvironmentVariable(OpenTelemetryConstants.ResourceGroupEnvVar);
57-
string websiteOwnerName = Environment.GetEnvironmentVariable(OpenTelemetryConstants.OwnerNameEnvVar) ?? string.Empty;
62+
string websiteResourceGroup = Environment.GetEnvironmentVariable(EnvironmentSettingNames.ResourceGroup);
63+
string websiteOwnerName = Environment.GetEnvironmentVariable(EnvironmentSettingNames.WebsiteOwnerName) ?? string.Empty;
5864
int idx = websiteOwnerName.IndexOf('+', StringComparison.Ordinal);
5965
string subscriptionId = idx > 0 ? websiteOwnerName.Substring(0, idx) : websiteOwnerName;
6066

src/WebJobs.Script/Diagnostics/OpenTelemetry/OpenTelemetryConfigurationExtensions.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Azure.Core;
99
using Azure.Identity;
1010
using Azure.Monitor.OpenTelemetry.Exporter;
11+
using Microsoft.AspNetCore.Http;
1112
using Microsoft.AspNetCore.Routing;
1213
using Microsoft.Azure.WebJobs.Script.Metrics;
1314
using Microsoft.Extensions.Configuration;
@@ -122,7 +123,45 @@ private static IOpenTelemetryBuilder ConfigureTracing(this IOpenTelemetryBuilder
122123
Activity.Current.AddTag(ResourceSemanticConventions.HttpRoute, template?.RouteTemplate);
123124
}
124125
};
125-
o.Filter = context => !context.Request.Host.Host.Equals("127.0.0.1", StringComparison.OrdinalIgnoreCase);
126+
o.Filter = context =>
127+
{
128+
// Exclude localhost calls
129+
if (context.Request.Host.Host.Equals("127.0.0.1", StringComparison.OrdinalIgnoreCase))
130+
{
131+
return false;
132+
}
133+
134+
// Exclude POST /admin/host/synctriggers
135+
if (string.Equals(context.Request.Method, HttpMethods.Post, StringComparison.OrdinalIgnoreCase)
136+
&& context.Request.Path.Equals("/admin/host/synctriggers", StringComparison.OrdinalIgnoreCase))
137+
{
138+
return false;
139+
}
140+
141+
// Exclude GET admin/warmup
142+
if (string.Equals(context.Request.Method, HttpMethods.Get, StringComparison.OrdinalIgnoreCase)
143+
&& context.Request.Path.Equals("/admin/warmup", StringComparison.OrdinalIgnoreCase))
144+
{
145+
return false;
146+
}
147+
148+
// Exclude GET admin/host/status
149+
if (string.Equals(context.Request.Method, HttpMethods.Get, StringComparison.OrdinalIgnoreCase)
150+
&& context.Request.Path.Equals("/admin/host/status", StringComparison.OrdinalIgnoreCase))
151+
{
152+
return false;
153+
}
154+
155+
// Exclude GET /admin/health
156+
if (string.Equals(context.Request.Method, HttpMethods.Get, StringComparison.OrdinalIgnoreCase)
157+
&& context.Request.Path.Equals("/admin/health", StringComparison.OrdinalIgnoreCase))
158+
{
159+
return false;
160+
}
161+
162+
// Allow everything else
163+
return true;
164+
};
126165
})
127166
.AddProcessor(ActivitySanitizingProcessor.Instance);
128167
});

src/WebJobs.Script/Diagnostics/OpenTelemetry/OpenTelemetryConstants.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ internal static class OpenTelemetryConstants
88
internal const string AzureCloudProviderValue = "azure";
99
internal const string AzurePlatformValue = "azure_functions";
1010
internal const string SDKPrefix = "azurefunctions";
11-
internal const string SiteNameEnvVar = "WEBSITE_SITE_NAME";
12-
internal const string RegionNameEnvVar = "REGION_NAME";
13-
internal const string ResourceGroupEnvVar = "WEBSITE_RESOURCE_GROUP";
14-
internal const string OwnerNameEnvVar = "WEBSITE_OWNER_NAME";
1511
internal const string AzureFunctionsGroup = "azure.functions.group";
1612
internal const string HttpTriggerType = "http";
1713
internal const string HostActivitySourceName = "Microsoft.Azure.WebJobs";

src/WebJobs.Script/Diagnostics/OpenTelemetry/ResourceSemanticConventions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
namespace Microsoft.Azure.WebJobs.Script.Diagnostics.OpenTelemetry
@@ -33,5 +33,8 @@ internal static class ResourceSemanticConventions
3333

3434
// AI
3535
internal const string AISDKPrefix = "ai.sdk.prefix";
36+
37+
// Deployment
38+
internal const string DeploymentEnvironmentName = "deployment.environment.name";
3639
}
3740
}

src/WebJobs.Script/Environment/EnvironmentSettingNames.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public static class EnvironmentSettingNames
8686
public const string FunctionsTargetGroup = "FUNCTIONS_TARGET_GROUP";
8787
public const string WebsiteArmResourceId = "WEBSITE_ARM_RESOURCE_ID";
8888
public const string FunctionsDisableInProc = "FUNCTIONS_DISABLE_INPROC";
89+
public const string ResourceGroup = "WEBSITE_RESOURCE_GROUP";
90+
public const string WebsiteOwnerName = "WEBSITE_OWNER_NAME";
8991

9092
//Function in Kubernetes
9193
public const string PodNamespace = "POD_NAMESPACE";

src/WebJobs.Script/Workers/Rpc/FunctionRegistration/RpcFunctionInvocationDispatcher.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -697,14 +697,10 @@ public async Task<bool> RestartWorkerWithInvocationIdAsync(string invocationId,
697697

698698
private void AddLogUserCategory(IEnumerable<FunctionMetadata> functions)
699699
{
700-
// Add category, this is only needed for workers running AI agent
701-
if (_environment.IsApplicationInsightsAgentEnabled())
700+
foreach (FunctionMetadata metadata in functions)
702701
{
703-
foreach (FunctionMetadata metadata in functions)
704-
{
705-
metadata.Properties[LogConstants.CategoryNameKey] = LogCategories.CreateFunctionUserCategory(metadata.Name);
706-
metadata.Properties[ScriptConstants.LogPropertyHostInstanceIdKey] = _scriptOptions.InstanceId;
707-
}
702+
metadata.Properties[LogConstants.CategoryNameKey] = LogCategories.CreateFunctionUserCategory(metadata.Name);
703+
metadata.Properties[ScriptConstants.LogPropertyHostInstanceIdKey] = _scriptOptions.InstanceId;
708704
}
709705
}
710706

test/WebJobs.Script.Tests/Diagnostics/OpenTelemetry/OpenTelemetryConfigurationExtensionsTests.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
@@ -210,20 +210,21 @@ public void OnEnd_DoesNotSanitizeNonSensitiveTags()
210210
}
211211

212212
[Fact]
213-
public void ResourceDetectorLocalDevelopment2()
213+
public void ResourceDetector_Azure()
214214
{
215215
using var envVariables = SetupDefaultEnvironmentVariables();
216216

217217
FunctionsResourceDetector detector = new FunctionsResourceDetector();
218218
Resource resource = detector.Detect();
219219

220-
Assert.Equal($"/subscriptions/AAAAA-AAAAA-AAAAA-AAA/resourceGroups/rg/providers/Microsoft.Web/sites/appName",
220+
Assert.Equal("/subscriptions/AAAAA-AAAAA-AAAAA-AAA/resourceGroups/rg/providers/Microsoft.Web/sites/appName",
221221
resource.Attributes.FirstOrDefault(a => a.Key == "cloud.resource_id").Value);
222-
Assert.Equal($"EastUS", resource.Attributes.FirstOrDefault(a => a.Key == "cloud.region").Value);
222+
Assert.Equal("EastUS", resource.Attributes.FirstOrDefault(a => a.Key == "cloud.region").Value);
223+
Assert.Equal("staging", resource.Attributes.FirstOrDefault(a => a.Key == "deployment.environment.name").Value);
223224
}
224225

225226
[Fact]
226-
public void ResourceDetectorLocalDevelopment()
227+
public void ResourceDetector_LocalDevelopment()
227228
{
228229
FunctionsResourceDetector detector = new FunctionsResourceDetector();
229230
Resource resource = detector.Detect();
@@ -299,7 +300,8 @@ private static IDisposable SetupDefaultEnvironmentVariables()
299300
{ "WEBSITE_SITE_NAME", "appName" },
300301
{ "WEBSITE_RESOURCE_GROUP", "rg" },
301302
{ "WEBSITE_OWNER_NAME", "AAAAA-AAAAA-AAAAA-AAA+appName-EastUSwebspace" },
302-
{ "REGION_NAME", "EastUS" }
303+
{ "REGION_NAME", "EastUS" },
304+
{ "WEBSITE_SLOT_NAME", "staging" }
303305
});
304306
}
305307
}

test/WebJobs.Script.Tests/Workers/Rpc/GrpcWorkerChannelTests.cs

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,25 +1335,14 @@ public async Task SendInvocationRequest_ValidateTraceContext()
13351335
var attribs = ctx.Attributes;
13361336
Assert.NotNull(attribs);
13371337

1338-
if (_testEnvironment.IsApplicationInsightsAgentEnabled())
1339-
{
1340-
_testOutput.WriteLine("Checking ENABLED app-insights fields...");
1341-
Assert.True(attribs.ContainsKey(ScriptConstants.LogPropertyProcessIdKey), "ScriptConstants.LogPropertyProcessIdKey");
1342-
Assert.True(attribs.ContainsKey(ScriptConstants.LogPropertyHostInstanceIdKey), "ScriptConstants.LogPropertyHostInstanceIdKey");
1343-
Assert.True(attribs.TryGetValue(LogConstants.CategoryNameKey, out var catKey), "LogConstants.CategoryNameKey");
1344-
Assert.Equal(catKey, "testcat1");
1345-
Assert.True(attribs.TryGetValue(ScriptConstants.OperationNameKey, out var onKey), "ScriptConstants.OperationNameKey");
1346-
Assert.Equal(onKey, scriptInvocationContext.ExecutionContext.FunctionName);
1347-
Assert.Equal(4, attribs.Count);
1348-
}
1349-
else
1350-
{
1351-
_testOutput.WriteLine("Checking DISABLED app-insights fields...");
1352-
Assert.False(attribs.ContainsKey(ScriptConstants.LogPropertyProcessIdKey), "ScriptConstants.LogPropertyProcessIdKey");
1353-
Assert.False(attribs.ContainsKey(ScriptConstants.LogPropertyHostInstanceIdKey), "ScriptConstants.LogPropertyHostInstanceIdKey");
1354-
Assert.False(attribs.ContainsKey(LogConstants.CategoryNameKey), "LogConstants.CategoryNameKey");
1355-
Assert.Equal(0, attribs.Count);
1356-
}
1338+
_testOutput.WriteLine("Checking app-insights fields...");
1339+
Assert.True(attribs.ContainsKey(ScriptConstants.LogPropertyProcessIdKey), "ScriptConstants.LogPropertyProcessIdKey");
1340+
Assert.True(attribs.ContainsKey(ScriptConstants.LogPropertyHostInstanceIdKey), "ScriptConstants.LogPropertyHostInstanceIdKey");
1341+
Assert.True(attribs.TryGetValue(LogConstants.CategoryNameKey, out var catKey), "LogConstants.CategoryNameKey");
1342+
Assert.Equal(catKey, "testcat1");
1343+
Assert.True(attribs.TryGetValue(ScriptConstants.OperationNameKey, out var onKey), "ScriptConstants.OperationNameKey");
1344+
Assert.Equal(onKey, scriptInvocationContext.ExecutionContext.FunctionName);
1345+
Assert.Equal(4, attribs.Count);
13571346
}
13581347

13591348
[Fact]
@@ -1379,20 +1368,13 @@ public async Task SendInvocationRequest_ValidateTraceContext_Properties()
13791368
activity.Stop();
13801369
var attribs = grpcEvent.Message.InvocationRequest.TraceContext.Attributes;
13811370

1382-
if (_testEnvironment.IsApplicationInsightsAgentEnabled())
1383-
{
1384-
Assert.True(attribs.TryGetValue(ScriptConstants.LiveLogsSessionAIKey, out var aiKey), "ScriptConstants.LiveLogsSessionAIKey");
1385-
Assert.Equal(sessionId, aiKey);
1386-
Assert.True(attribs.TryGetValue(LogConstants.CategoryNameKey, out var catKey), "LogConstants.CategoryNameKey");
1387-
Assert.Equal("testcat1", catKey);
1388-
Assert.True(attribs.TryGetValue(ScriptConstants.OperationNameKey, out var onKey), "ScriptConstants.OperationNameKey");
1389-
Assert.Equal(scriptInvocationContext.ExecutionContext.FunctionName, onKey);
1390-
Assert.Equal(5, attribs.Count);
1391-
}
1392-
else
1393-
{
1394-
Assert.False(attribs.ContainsKey(LogConstants.CategoryNameKey), "LogConstants.CategoryNameKey");
1395-
}
1371+
Assert.True(attribs.TryGetValue(ScriptConstants.LiveLogsSessionAIKey, out var aiKey), "ScriptConstants.LiveLogsSessionAIKey");
1372+
Assert.Equal(sessionId, aiKey);
1373+
Assert.True(attribs.TryGetValue(LogConstants.CategoryNameKey, out var catKey), "LogConstants.CategoryNameKey");
1374+
Assert.Equal("testcat1", catKey);
1375+
Assert.True(attribs.TryGetValue(ScriptConstants.OperationNameKey, out var onKey), "ScriptConstants.OperationNameKey");
1376+
Assert.Equal(scriptInvocationContext.ExecutionContext.FunctionName, onKey);
1377+
Assert.Equal(5, attribs.Count);
13961378
}
13971379

13981380
[Fact]

0 commit comments

Comments
 (0)