Skip to content

Commit 7b42c24

Browse files
authored
adding AI project (#944)
1 parent 4aaf5cb commit 7b42c24

39 files changed

+1542
-316
lines changed

DotNetWorker.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ EndProject
100100
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Worker.Extensions.Storage.Blobs", "extensions\Worker.Extensions.Storage.Blobs\src\Worker.Extensions.Storage.Blobs.csproj", "{FC352905-BD72-4049-8D32-3CBB9304FDC8}"
101101
EndProject
102102
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Worker.Extensions.Storage.Tables", "extensions\Worker.Extensions.Storage.Tables\src\Worker.Extensions.Storage.Tables.csproj", "{2B2B47E9-2973-4269-AC5D-E5C32BDD5346}"
103+
EndProject
103104
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdk.Generators", "sdk\Sdk.Generators\Sdk.Generators.csproj", "{F77CCCE6-2DC3-48AA-8FE8-1B135B76B90E}"
104105
EndProject
105106
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdk.Generator.Tests", "test\Sdk.Generator.Tests\Sdk.Generator.Tests.csproj", "{18A09B24-8646-40A6-BD85-2773AF567453}"
@@ -112,6 +113,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Worker.Extensions.Sample-In
112113
EndProject
113114
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetFxWorker", "samples\NetFxWorker\NetFxWorker.csproj", "{B37E6BAC-F16B-4366-94FB-8B94B52A08C9}"
114115
EndProject
116+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetWorker.ApplicationInsights", "src\DotNetWorker.ApplicationInsights\DotNetWorker.ApplicationInsights.csproj", "{65DE66B6-568F-46AC-8F0D-C79A02F48214}"
117+
EndProject
115118
Global
116119
GlobalSection(SolutionConfigurationPlatforms) = preSolution
117120
Debug|Any CPU = Debug|Any CPU
@@ -274,6 +277,10 @@ Global
274277
{B37E6BAC-F16B-4366-94FB-8B94B52A08C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
275278
{B37E6BAC-F16B-4366-94FB-8B94B52A08C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
276279
{B37E6BAC-F16B-4366-94FB-8B94B52A08C9}.Release|Any CPU.Build.0 = Release|Any CPU
280+
{65DE66B6-568F-46AC-8F0D-C79A02F48214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
281+
{65DE66B6-568F-46AC-8F0D-C79A02F48214}.Debug|Any CPU.Build.0 = Debug|Any CPU
282+
{65DE66B6-568F-46AC-8F0D-C79A02F48214}.Release|Any CPU.ActiveCfg = Release|Any CPU
283+
{65DE66B6-568F-46AC-8F0D-C79A02F48214}.Release|Any CPU.Build.0 = Release|Any CPU
277284
EndGlobalSection
278285
GlobalSection(SolutionProperties) = preSolution
279286
HideSolutionNode = FALSE
@@ -322,6 +329,7 @@ Global
322329
{922A387F-8595-4C74-ABF1-AEFF9530950C} = {B5821230-6E0A-4535-88A9-ED31B6F07596}
323330
{22FCE0DF-65FE-4650-8202-765832C40E6D} = {922A387F-8595-4C74-ABF1-AEFF9530950C}
324331
{B37E6BAC-F16B-4366-94FB-8B94B52A08C9} = {9D6603BD-7EA2-4D11-A69C-0D9E01317FD6}
332+
{65DE66B6-568F-46AC-8F0D-C79A02F48214} = {083592CA-7DAB-44CE-8979-44FAFA46AEC3}
325333
EndGlobalSection
326334
GlobalSection(ExtensibilityGlobals) = postSolution
327335
SolutionGuid = {497D2ED4-A13E-4BCA-8D29-F30CA7D0EA4A}

build/DotNetWorker.Core.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"sdk\\Sdk.Analyzers\\Sdk.Analyzers.csproj",
66
"sdk\\Sdk.Generators\\Sdk.Generators.csproj",
77
"sdk\\Sdk\\Sdk.csproj",
8+
"src\\DotNetWorker.ApplicationInsights\\DotNetWorker.ApplicationInsights.csproj",
89
"src\\DotNetWorker.Core\\DotNetWorker.Core.csproj",
910
"src\\DotNetWorker.Grpc\\DotNetWorker.Grpc.csproj",
1011
"src\\DotNetWorker\\DotNetWorker.csproj"

samples/FunctionApp/FunctionApp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<ProjectReference Include="..\..\extensions\Worker.Extensions.Abstractions\src\Worker.Extensions.Abstractions.csproj" />
2323
<ProjectReference Include="..\..\extensions\Worker.Extensions.Http\src\Worker.Extensions.Http.csproj" />
2424
<ProjectReference Include="..\..\extensions\Worker.Extensions.Storage\src\Worker.Extensions.Storage.csproj" />
25+
<ProjectReference Include="..\..\src\DotNetWorker.ApplicationInsights\DotNetWorker.ApplicationInsights.csproj" />
2526
<ProjectReference Include="..\..\src\DotNetWorker\DotNetWorker.csproj" />
2627
</ItemGroup>
2728
<ItemGroup>

samples/FunctionApp/Program.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System.Threading.Tasks;
5+
using Microsoft.Azure.Functions.Worker;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Extensions.Hosting;
78

@@ -17,7 +18,12 @@ static async Task Main(string[] args)
1718
//<docsnippet_startup>
1819
var host = new HostBuilder()
1920
//<docsnippet_configure_defaults>
20-
.ConfigureFunctionsWorkerDefaults()
21+
.ConfigureFunctionsWorkerDefaults(builder =>
22+
{
23+
builder
24+
.AddApplicationInsights()
25+
.AddApplicationInsightsLogger();
26+
})
2127
//</docsnippet_configure_defaults>
2228
//<docsnippet_dependency_injection>
2329
.ConfigureServices(s =>
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"IsEncrypted": false,
3-
"Values": {
4-
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
5-
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
6-
}
2+
"IsEncrypted": false,
3+
"Values": {
4+
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
5+
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
76
}
7+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<PackageId>Microsoft.Azure.Functions.Worker.ApplicationInsights</PackageId>
6+
<AssemblyName>Microsoft.Azure.Functions.Worker.ApplicationInsights</AssemblyName>
7+
<RootNamespace>Microsoft.Azure.Functions.Worker.ApplicationInsights</RootNamespace>
8+
<MajorProductVersion>1</MajorProductVersion>
9+
<MinorProductVersion>0</MinorProductVersion>
10+
<PatchProductVersion>0</PatchProductVersion>
11+
<VersionSuffix>-preview1</VersionSuffix>
12+
</PropertyGroup>
13+
14+
<Import Project="..\..\build\Common.props" />
15+
16+
<ItemGroup>
17+
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.20.0" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\DotNetWorker.Core\DotNetWorker.Core.csproj" />
22+
</ItemGroup>
23+
24+
</Project>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System.Diagnostics;
5+
6+
namespace Microsoft.Azure.Functions.Worker.Core.Diagnostics
7+
{
8+
/// Note: This class will eventually move in to the core worker assembly. Including it in the
9+
/// ApplicationInsights package so we can utilize it during preview.
10+
internal static class FunctionActivitySource
11+
{
12+
private const string InvocationIdKey = "InvocationId";
13+
private const string NameKey = "Name";
14+
private const string ProcessIdKey = "ProcessId";
15+
16+
private static readonly ActivitySource _activitySource = new("Microsoft.Azure.Functions.Worker");
17+
private static readonly string _processId = Process.GetCurrentProcess().Id.ToString();
18+
19+
public static Activity? StartInvoke(FunctionContext context)
20+
{
21+
var activity = _activitySource.StartActivity("Invoke", ActivityKind.Internal, context.TraceContext.TraceParent);
22+
23+
if (activity is not null)
24+
{
25+
activity.AddTag(InvocationIdKey, context.InvocationId);
26+
activity.AddTag(NameKey, context.FunctionDefinition.Name);
27+
activity.AddTag(ProcessIdKey, _processId);
28+
}
29+
30+
return activity;
31+
}
32+
}
33+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
using Microsoft.Azure.Functions.Worker.Core.Diagnostics;
6+
using Microsoft.Azure.Functions.Worker.Middleware;
7+
8+
namespace Microsoft.Azure.Functions.Worker.ApplicationInsights;
9+
10+
internal class FunctionActivitySourceMiddleware : IFunctionsWorkerMiddleware
11+
{
12+
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
13+
{
14+
using (FunctionActivitySource.StartInvoke(context))
15+
{
16+
await next.Invoke(context);
17+
}
18+
}
19+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using Microsoft.ApplicationInsights.Extensibility;
7+
using Microsoft.ApplicationInsights.WorkerService;
8+
using Microsoft.Azure.Functions.Worker.ApplicationInsights;
9+
using Microsoft.Azure.Functions.Worker.Logging;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Microsoft.Extensions.DependencyInjection.Extensions;
12+
using Microsoft.Extensions.Logging;
13+
using Microsoft.Extensions.Logging.ApplicationInsights;
14+
15+
namespace Microsoft.Azure.Functions.Worker
16+
{
17+
public static class FunctionsApplicationInsightsExtensions
18+
{
19+
/// <summary>
20+
/// Adds Application Insights support by internally calling <see cref="ApplicationInsightsExtensions.AddApplicationInsightsTelemetryWorkerService(IServiceCollection)"/>.
21+
/// </summary>
22+
/// <param name="builder">The <see cref="IFunctionsWorkerApplicationBuilder"/></param>
23+
/// <param name="configureOptions">Action to configure ApplicationInsights services.</param>
24+
/// <returns>The <see cref="IFunctionsWorkerApplicationBuilder"/></returns>
25+
public static IFunctionsWorkerApplicationBuilder AddApplicationInsights(this IFunctionsWorkerApplicationBuilder builder, Action<ApplicationInsightsServiceOptions>? configureOptions = null)
26+
{
27+
builder.AddCommonServices();
28+
29+
builder.Services.AddApplicationInsightsTelemetryWorkerService(options =>
30+
{
31+
configureOptions?.Invoke(options);
32+
});
33+
34+
return builder;
35+
}
36+
37+
/// <summary>
38+
/// Adds the <see cref="ApplicationInsightsLoggerProvider"/> and disables the Functions host passthrough logger.
39+
/// </summary>
40+
/// <param name="builder">The <see cref="IFunctionsWorkerApplicationBuilder"/></param>
41+
/// <param name="configureOptions">Action to configure ApplicationInsights logger.</param>
42+
/// <returns>The <see cref="IFunctionsWorkerApplicationBuilder"/></returns>
43+
public static IFunctionsWorkerApplicationBuilder AddApplicationInsightsLogger(this IFunctionsWorkerApplicationBuilder builder, Action<ApplicationInsightsLoggerOptions>? configureOptions = null)
44+
{
45+
builder.AddCommonServices();
46+
47+
builder.Services.AddLogging(logging =>
48+
{
49+
logging.AddApplicationInsights(options =>
50+
{
51+
options.IncludeScopes = false;
52+
configureOptions?.Invoke(options);
53+
});
54+
});
55+
56+
return builder;
57+
}
58+
59+
private static IFunctionsWorkerApplicationBuilder AddCommonServices(this IFunctionsWorkerApplicationBuilder builder)
60+
{
61+
builder.Services.TryAddEnumerable(new ServiceDescriptor(typeof(ITelemetryInitializer), typeof(FunctionsTelemetryInitializer), ServiceLifetime.Singleton));
62+
builder.Services.TryAddEnumerable(new ServiceDescriptor(typeof(ITelemetryModule), typeof(FunctionsTelemetryModule), ServiceLifetime.Singleton));
63+
64+
// User logs will be written directly to Application Insights; this prevents duplicate logging.
65+
builder.Services.AddSingleton<IUserLogWriter>(_ => NullUserLogWriter.Instance);
66+
67+
// This middleware is temporary for the preview. Eventually this behavior will move into the
68+
// core worker assembly.
69+
if (!builder.Services.Any(p => p.ImplementationType == typeof(FunctionActivitySourceMiddleware)))
70+
{
71+
builder.Services.AddSingleton<FunctionActivitySourceMiddleware>();
72+
builder.Use(next =>
73+
{
74+
return async context =>
75+
{
76+
var middleware = context.InstanceServices.GetRequiredService<FunctionActivitySourceMiddleware>();
77+
await middleware.Invoke(context, next);
78+
};
79+
});
80+
}
81+
82+
return builder;
83+
}
84+
}
85+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.Reflection;
7+
using Microsoft.ApplicationInsights.Channel;
8+
using Microsoft.ApplicationInsights.DataContracts;
9+
using Microsoft.ApplicationInsights.Extensibility;
10+
using Microsoft.ApplicationInsights.Extensibility.Implementation;
11+
12+
namespace Microsoft.Azure.Functions.Worker.ApplicationInsights
13+
{
14+
internal class FunctionsTelemetryInitializer : ITelemetryInitializer
15+
{
16+
private const string NameKey = "Name";
17+
18+
private readonly string _sdkVersion;
19+
private readonly string _roleInstanceName;
20+
21+
internal FunctionsTelemetryInitializer(string sdkVersion, string roleInstanceName)
22+
{
23+
_sdkVersion = sdkVersion;
24+
_roleInstanceName = roleInstanceName;
25+
}
26+
27+
public FunctionsTelemetryInitializer() :
28+
this(GetSdkVersion(), GetRoleInstanceName())
29+
{
30+
}
31+
32+
private static string GetSdkVersion()
33+
{
34+
return "azurefunctions-netiso: " + typeof(FunctionsTelemetryInitializer).Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>()!.Version;
35+
}
36+
37+
private static string GetRoleInstanceName()
38+
{
39+
const string ComputerNameKey = "COMPUTERNAME";
40+
const string WebSiteInstanceIdKey = "WEBSITE_INSTANCE_ID";
41+
const string ContainerNameKey = "CONTAINER_NAME";
42+
43+
string? instanceName = Environment.GetEnvironmentVariable(WebSiteInstanceIdKey);
44+
if (string.IsNullOrEmpty(instanceName))
45+
{
46+
instanceName = Environment.GetEnvironmentVariable(ComputerNameKey);
47+
if (string.IsNullOrEmpty(instanceName))
48+
{
49+
instanceName = Environment.GetEnvironmentVariable(ContainerNameKey);
50+
}
51+
}
52+
53+
return instanceName ?? Environment.MachineName;
54+
}
55+
56+
public void Initialize(ITelemetry telemetry)
57+
{
58+
if (telemetry == null)
59+
{
60+
return;
61+
}
62+
63+
telemetry.Context.Cloud.RoleInstance = _roleInstanceName;
64+
telemetry.Context.GetInternalContext().SdkVersion = _sdkVersion;
65+
66+
telemetry.Context.Location.Ip ??= "0.0.0.0";
67+
68+
if (Activity.Current is not null)
69+
{
70+
foreach (var tag in Activity.Current.Tags)
71+
{
72+
switch (tag.Key)
73+
{
74+
case NameKey:
75+
telemetry.Context.Operation.Name = tag.Value;
76+
continue;
77+
default:
78+
break;
79+
}
80+
81+
if (telemetry is ISupportProperties properties && !tag.Key.StartsWith("ai_"))
82+
{
83+
properties.Properties[tag.Key] = tag.Value;
84+
}
85+
}
86+
87+
}
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)