Skip to content

Commit 6e05e21

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents 3f209ad + c41f74e commit 6e05e21

6 files changed

Lines changed: 60 additions & 17 deletions

File tree

src/ApplicationInsights.Kubernetes/Extensions/ApplicationInsightsExtensions.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ public static partial class ApplicationInsightsExtensions
1818
/// Enables Application Insights for Kubernetes on the Default TelemetryConfiguration in the dependency injection container with custom options.
1919
/// </summary>
2020
/// <param name="services">Collection of service descriptors.</param>
21-
/// <param name="applyOptions">Action to customize the configuration of Application Insights for Kubernetes.</param>
2221
/// <param name="diagnosticLogLevel">Sets the diagnostics log levels for the enricher.</param>
22+
/// <param name="disableBackgroundService">If true, the Application Insights enricher library will not use any background (hosted) services,
23+
/// and Kubernetes information will not be fetched automatically. Hosted services are not allowed in some environments, e.g. Azure Function.
24+
/// For more information see https://github.com/Azure/azure-functions-host/issues/5447#issuecomment-575368316</param>
25+
/// <param name="applyOptions">Action to customize the configuration of Application Insights for Kubernetes.</param>
2326
/// <param name="clusterCheck">Provides a custom implementation to check whether it is inside kubernetes cluster or not.</param>
2427
/// <returns>The service collection for chaining the next operation.</returns>
2528
public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
2629
this IServiceCollection services,
27-
Action<AppInsightsForKubernetesOptions>? applyOptions = default,
2830
LogLevel? diagnosticLogLevel = LogLevel.None,
31+
bool disableBackgroundService = false,
32+
Action<AppInsightsForKubernetesOptions>? applyOptions = default,
2933
IClusterEnvironmentCheck? clusterCheck = default)
3034
{
3135
diagnosticLogLevel ??= LogLevel.None; // Default to None.
@@ -37,7 +41,7 @@ public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
3741

3842
if (!KubernetesTelemetryInitializerExists(services))
3943
{
40-
services.ConfigureKubernetesTelemetryInitializer(applyOptions, clusterCheck);
44+
services.ConfigureKubernetesTelemetryInitializer(applyOptions, clusterCheck, disableBackgroundService);
4145
}
4246
return services;
4347
}
@@ -48,7 +52,7 @@ public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
4852
public static void StartApplicationInsightsKubernetesEnricher(this IServiceProvider serviceProvider)
4953
{
5054
IK8sInfoBootstrap? k8sInfoBootstrap = serviceProvider.GetService<IK8sInfoBootstrap>();
51-
if(k8sInfoBootstrap is null)
55+
if (k8sInfoBootstrap is null)
5256
{
5357
_logger.LogInformation("No service registered by type {0}. Either not running in a Kubernetes cluster or `{1}()` wasn't called on the service collection.", nameof(IK8sInfoBootstrap), nameof(AddApplicationInsightsKubernetesEnricher));
5458
return;
@@ -69,9 +73,10 @@ private static bool KubernetesTelemetryInitializerExists(IServiceCollection serv
6973
internal static void ConfigureKubernetesTelemetryInitializer(
7074
this IServiceCollection services,
7175
Action<AppInsightsForKubernetesOptions>? overwriteOptions,
72-
IClusterEnvironmentCheck? clusterCheck)
76+
IClusterEnvironmentCheck? clusterCheck,
77+
bool skipRegisterBackendService = false)
7378
{
74-
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = new KubernetesServiceCollectionBuilder(overwriteOptions, clusterCheck);
79+
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = new KubernetesServiceCollectionBuilder(overwriteOptions, clusterCheck, skipRegisterBackendService);
7580
_ = kubernetesServiceCollectionBuilder.RegisterServices(services);
7681
}
7782
}

src/ApplicationInsights.Kubernetes/Extensions/KubernetesServiceCollectionBuilder.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Microsoft.Extensions.DependencyInjection;
1717
internal class KubernetesServiceCollectionBuilder : IKubernetesServiceCollectionBuilder
1818
{
1919
private readonly IClusterEnvironmentCheck _clusterCheck;
20+
private readonly bool _skipRegisterBackendService;
2021
private readonly Action<AppInsightsForKubernetesOptions>? _customizeOptions;
2122
private readonly ApplicationInsightsKubernetesDiagnosticSource _logger = ApplicationInsightsKubernetesDiagnosticSource.Instance;
2223

@@ -29,10 +30,12 @@ internal class KubernetesServiceCollectionBuilder : IKubernetesServiceCollection
2930
/// </param>
3031
public KubernetesServiceCollectionBuilder(
3132
Action<AppInsightsForKubernetesOptions>? customizeOptions,
32-
IClusterEnvironmentCheck? clusterCheck)
33+
IClusterEnvironmentCheck? clusterCheck,
34+
bool skipRegisterBackendService)
3335
{
3436
_customizeOptions = customizeOptions;
3537
_clusterCheck = clusterCheck ?? new ClusterEnvironmentCheck();
38+
_skipRegisterBackendService = skipRegisterBackendService;
3639
}
3740

3841
/// <summary>
@@ -142,7 +145,13 @@ protected virtual void RegisterK8sEnvironmentFactory(IServiceCollection serviceC
142145
serviceCollection.TryAddScoped<IK8sEnvironmentFactory, K8sEnvironmentFactory>();
143146
serviceCollection.TryAddSingleton<IK8sEnvironmentHolder>(_ => K8sEnvironmentHolder.Instance);
144147

148+
_logger.LogTrace("Registering bootstrap and hosted service.");
145149
serviceCollection.TryAddSingleton<IK8sInfoBootstrap, K8sInfoBootstrap>();
146-
serviceCollection.AddHostedService<K8sInfoBackgroundService>();
150+
if (!_skipRegisterBackendService)
151+
{
152+
_logger.LogInformation("Skip registering {0} by user configuration.", nameof(K8sInfoBackgroundService));
153+
serviceCollection.AddHostedService<K8sInfoBackgroundService>();
154+
}
155+
_logger.LogTrace("Registered bootstrap and hosted service.");
147156
}
148157
}

src/ApplicationInsights.Kubernetes/IK8sInfoBootstrap.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Microsoft.ApplicationInsights.Kubernetes;
88
/// The intention is for the client to have a handle to start getting Kubernetes info to be consumed by the <see cref="IK8sInfoService" />.
99
/// Remark: This is supposed to only be used in Console Application. Do NOT use this in ASP.NET or Worker, where the hosted service exists.
1010
/// </summary>
11-
internal interface IK8sInfoBootstrap
11+
public interface IK8sInfoBootstrap
1212
{
1313
/// <summary>
1414
/// Bootstrap the fetch of Kubernetes information.

tests/UnitTests/AppInsightsKubernetesOptionsTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public void ShouldHaveDefaultOptions()
1818

1919
clusterCheck.Setup(c => c.IsInCluster).Returns(true);
2020

21-
KubernetesServiceCollectionBuilder builder = new KubernetesServiceCollectionBuilder(customizeOptions: default, clusterCheck.Object);
21+
KubernetesServiceCollectionBuilder builder = new KubernetesServiceCollectionBuilder(customizeOptions: default, clusterCheck.Object, skipRegisterBackendService: false);
2222

2323
IServiceCollection services = new ServiceCollection();
2424
IConfiguration configuration = (new ConfigurationBuilder()).Build();
@@ -44,7 +44,7 @@ public void ShouldTakeOptionFromIConfiguration()
4444

4545
clusterCheck.Setup(c => c.IsInCluster).Returns(true);
4646

47-
KubernetesServiceCollectionBuilder builder = new KubernetesServiceCollectionBuilder(customizeOptions: default, clusterCheck.Object);
47+
KubernetesServiceCollectionBuilder builder = new KubernetesServiceCollectionBuilder(customizeOptions: default, clusterCheck.Object, skipRegisterBackendService: false);
4848

4949
IServiceCollection services = new ServiceCollection();
5050
IConfiguration configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string>()
@@ -71,7 +71,7 @@ public void ShouldTakeDelegateOverwriteForSettings()
7171
KubernetesServiceCollectionBuilder builder = new KubernetesServiceCollectionBuilder(customizeOptions: opt =>
7272
{
7373
opt.InitializationTimeout = TimeSpan.FromSeconds(10); // The user settings through code will take precedence.
74-
}, clusterCheck.Object);
74+
}, clusterCheck.Object, skipRegisterBackendService: false);
7575

7676
IServiceCollection services = new ServiceCollection();
7777
IConfiguration configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string>()
@@ -101,7 +101,7 @@ public void ShouldAllowSetTelemetryKeyProcessorByCode()
101101
KubernetesServiceCollectionBuilder builder = new KubernetesServiceCollectionBuilder(customizeOptions: opt =>
102102
{
103103
opt.TelemetryKeyProcessor = keyTransformer;
104-
}, clusterCheck.Object);
104+
}, clusterCheck.Object, skipRegisterBackendService: false);
105105

106106
IServiceCollection services = new ServiceCollection();
107107
IConfiguration configuration = new ConfigurationBuilder().Build();

tests/UnitTests/ApplicationInsightsExtensionsTests.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System;
2+
using System.Linq;
23
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Hosting;
35
using Microsoft.Extensions.Logging;
6+
using Moq;
47
using Xunit;
58

69
namespace Microsoft.ApplicationInsights.Kubernetes.Tests;
@@ -29,7 +32,7 @@ public void ShouldAllowOverwriteOptions()
2932
IServiceCollection collection = new ServiceCollection();
3033

3134
// If there's compile error, check if the signature of AddApplicationInsightsKubernetesEnricher was changed.
32-
collection = collection.AddApplicationInsightsKubernetesEnricher(opt => opt.InitializationTimeout = TimeSpan.FromMinutes(15));
35+
collection = collection.AddApplicationInsightsKubernetesEnricher(applyOptions: opt => opt.InitializationTimeout = TimeSpan.FromMinutes(15));
3336

3437
Assert.NotNull(collection);
3538
}
@@ -52,9 +55,35 @@ public void ShouldAllowOverwritingOptionsAndDiagnosticLoggingLevel()
5255

5356
// If there's compile error, check if the signature of AddApplicationInsightsKubernetesEnricher was changed.
5457
collection = collection.AddApplicationInsightsKubernetesEnricher(
55-
opt => opt.InitializationTimeout = TimeSpan.FromMinutes(15),
56-
diagnosticLogLevel: LogLevel.Trace);
58+
diagnosticLogLevel: LogLevel.Trace,
59+
applyOptions: opt => opt.InitializationTimeout = TimeSpan.FromMinutes(15));
5760

5861
Assert.NotNull(collection);
5962
}
63+
64+
[Theory]
65+
[InlineData(false, true)]
66+
[InlineData(true, false)]
67+
public void ShouldNotRegisterHostedServiceWhenSet(bool disableBackgroundService, bool expectServiceRegistered)
68+
{
69+
IServiceCollection collection = new ServiceCollection();
70+
71+
Mock<IClusterEnvironmentCheck> clusterCheck = new();
72+
clusterCheck.Setup(c => c.IsInCluster).Returns(true);
73+
74+
// If there's compile error, check if the signature of AddApplicationInsightsKubernetesEnricher was changed.
75+
collection = collection.AddApplicationInsightsKubernetesEnricher(disableBackgroundService: disableBackgroundService, clusterCheck: clusterCheck.Object);
76+
77+
Assert.NotNull(collection);
78+
bool registered = collection.Any(serviceDescriptor => serviceDescriptor.ServiceType == typeof(IHostedService));
79+
80+
if (expectServiceRegistered)
81+
{
82+
Assert.True(registered);
83+
}
84+
else
85+
{
86+
Assert.False(registered);
87+
}
88+
}
6089
}

tests/UnitTests/KubernetesEnablementTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public void ServicesRegistered()
2121

2222
clusterCheckMock.Setup(c => c.IsInCluster).Returns(true);
2323

24-
KubernetesServiceCollectionBuilder target = new KubernetesServiceCollectionBuilder(customizeOptions: null, clusterCheckMock.Object);
24+
KubernetesServiceCollectionBuilder target = new KubernetesServiceCollectionBuilder(customizeOptions: null, clusterCheckMock.Object, skipRegisterBackendService: false);
2525
target.RegisterServices(services);
2626

2727
Assert.NotNull(services.FirstOrDefault(sd => sd.ImplementationType == typeof(KubernetesTelemetryInitializer)));

0 commit comments

Comments
 (0)