Dev/saars/split service collection (#151)
* Refactor service collection builder * Update version number and build scripts * Build basic services * Add logging for user configurations * Clean up the APIs to enable AI.K8S * Add unit tests for configurations * Update readme * Fix a mistake in the readme
This commit is contained in:
Родитель
de1b629fea
Коммит
68922e6242
|
@ -2,16 +2,44 @@
|
|||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"label": "Build Debug",
|
||||
"command": "${workspaceFolder}/build/Build.cmd",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build Release",
|
||||
"command": "${workspaceFolder}/build/Build.cmd",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/ApplicationInsights.Kubernetes.sln"
|
||||
"Release",
|
||||
],
|
||||
"problemMatcher": "$msCompile",
|
||||
},
|
||||
{
|
||||
"label": "ReBuild Debug",
|
||||
"command": "${workspaceFolder}/build/Build.cmd",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"args": [
|
||||
"Debug",
|
||||
"True",
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "ReBuild Release",
|
||||
"command": "${workspaceFolder}/build/Build.cmd",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"args": [
|
||||
"Release",
|
||||
"True",
|
||||
],
|
||||
"problemMatcher": "$msCompile",
|
||||
},
|
||||
{
|
||||
"label": "Run Unit Tests",
|
||||
"command": "dotnet",
|
||||
|
|
36
README.md
36
README.md
|
@ -24,6 +24,42 @@ We support **ASP.NET Core** application as well as **.NET Core** application.
|
|||
|
||||
* Follow [this example](examples/BasicUsage_clr21_RBAC) for Role-based access control (RBAC) enabled Kubernetes clusters.
|
||||
|
||||
### Configuration Details
|
||||
|
||||
Customize configurations are supported for `v1.0.2+`. There are several ways to customize the settings. For example:
|
||||
|
||||
1. By the code:
|
||||
```csharp
|
||||
services.AddApplicationInsightsKubernetesEnricher(option=> {
|
||||
option.InitializationTimeout = TimeSpan.FromSeconds(15);
|
||||
});
|
||||
```
|
||||
|
||||
2. By `appsettings.json`:
|
||||
```jsonc
|
||||
{
|
||||
"Logging": {
|
||||
// ...
|
||||
},
|
||||
// Adding the following section to set the timeout to 15 seconds
|
||||
"AppInsightsForKubernetes": {
|
||||
"InitializationTimeout": "00:00:15"
|
||||
}
|
||||
}
|
||||
```
|
||||
3. By environment varialbe:
|
||||
```
|
||||
AppInsightsForKubernetes__InitializationTimeout=3.1:12:15.34
|
||||
```
|
||||
|
||||
All the related configurations have to be put in a section named `AppInsightsForKubernetes`. The supported keys/values are listed below:
|
||||
|
||||
| Key | Value/Types | Default Value | Description |
|
||||
|-----------------------|-------------|---------------|--------------------------------------------------------------------------------------------------------|
|
||||
| InitializationTimeout | TimeSpan | 00:02:00 | Maximum time to wait for spinning up the container. Accepted format: [d.]hh:mm:ss[.fffffff]. |
|
||||
|
||||
The configuration uses with the conventions in ASP.NET Core. Refer [Configuration in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1) for more information.
|
||||
|
||||
### Verify the cluster configuration
|
||||
Use the [troubleshooting image](https://github.com/Microsoft/ApplicationInsights-Kubernetes/tree/develop/troubleshooting) to verify the cluster is properly configured.
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ SETLOCAL
|
|||
SET CONFIG=%1
|
||||
SET REBUILD=%2
|
||||
IF '%CONFIG%' == '' SET CONFIG=Debug
|
||||
SET REBUILD_PARAM=--no-incremental
|
||||
IF '%REBUILD%' == '' SET REBUILD_PARAM=
|
||||
|
||||
|
||||
ECHO Target Configuration: %CONFIG%.
|
||||
FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET CDATE=%%B
|
||||
|
@ -13,7 +16,7 @@ FOR /F "TOKENS=1-2 delims=/:" %%a in ("%TIME%") DO SET mytime=%%a%%b
|
|||
SET CURRENT_DATE_TIME=%yyyy%%mm%%dd%%mytime%
|
||||
ECHO Version:%CURRENT_DATE_TIME%
|
||||
|
||||
dotnet build %~dp0\..\ApplicationInsights.Kubernetes.sln
|
||||
dotnet build -c %CONFIG% %REBUILD_PARAM% %~dp0\..\ApplicationInsights.Kubernetes.sln
|
||||
|
||||
:HELP
|
||||
GOTO :EXIT
|
||||
|
|
|
@ -27,17 +27,23 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.3'">
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.6'">
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.4.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Object model of configuration for Application Insights for Kubernetes.
|
||||
/// </summary>
|
||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||
public class AppInsightsForKubernetesOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum time to wait for spinning up the container.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[JsonProperty("InitializationTimeout")]
|
||||
public TimeSpan InitializationTimeout { get; set; } = TimeSpan.FromMinutes(2);
|
||||
}
|
||||
}
|
|
@ -4,54 +4,91 @@ using System.Linq;
|
|||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.Kubernetes;
|
||||
using Microsoft.ApplicationInsights.Kubernetes.Utilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using static Microsoft.ApplicationInsights.Kubernetes.StringUtils;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Extnesion method to inject Kubernetes Telemtry Initializer.
|
||||
/// </summary>
|
||||
public static class ApplicationInsightsExtensions
|
||||
public static partial class ApplicationInsightsExtensions
|
||||
{
|
||||
private const string ConfigurationSectionName = "AppInsightsForKubernetes";
|
||||
|
||||
/// <summary>
|
||||
/// Enables Application Insights for Kubernetes on the Default TelemtryConfiguration in the dependency injection system.
|
||||
/// </summary>
|
||||
/// <param name="services">Collection of service descriptors.</param>
|
||||
/// <param name="timeout">Maximum time to wait for spinning up the container.</param>
|
||||
/// <param name="kubernetesServiceCollectionBuilder">Collection builder.</param>
|
||||
/// <param name="detectKubernetes">Delegate to detect if the current application is running in Kubernetes hosted container.</param>
|
||||
/// <returns>The collection of services descriptors we injected into.</returns>
|
||||
/// <returns>The collection of services descriptors injected into.</returns>
|
||||
public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
|
||||
this IServiceCollection services)
|
||||
{
|
||||
return services.AddApplicationInsightsKubernetesEnricher(applyOptions: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables Application Insights for Kubernetes on the Default TelemtryConfiguration in the dependency injection system with custom options.
|
||||
/// </summary>
|
||||
/// <param name="services">Collection of service descriptors.</param>
|
||||
/// <param name="applyOptions">Action to customize the configuration of Application Insights for Kubernetes.</param>
|
||||
/// <returns>The collection of services descriptors injected into.</returns>
|
||||
public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
|
||||
this IServiceCollection services,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null)
|
||||
Action<AppInsightsForKubernetesOptions> applyOptions)
|
||||
{
|
||||
return services.AddApplicationInsightsKubernetesEnricher(
|
||||
applyOptions,
|
||||
kubernetesServiceCollectionBuilder: null,
|
||||
detectKubernetes: null,
|
||||
logger: null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables Application Insights for Kubernetes on the Default TelemtryConfiguration in the dependency injection system with custom options and debugging components.
|
||||
/// </summary>
|
||||
/// <param name="services">Collection of service descriptors.</param>
|
||||
/// <param name="applyOptions">Action to customize the configuration of Application Insights for Kubernetes.</param>
|
||||
/// <param name="kubernetesServiceCollectionBuilder">Sets the service collection builder for Application Insights for Kubernetes to overwrite the default one.</param>
|
||||
/// <param name="detectKubernetes">Sets a delegate overwrite the default detector of the Kubernetes environment.</param>
|
||||
/// <param name="logger">Sets a logger to overwrite the default logger from the given service collection.</param>
|
||||
/// <returns>The collection of services descriptors injected into.</returns>
|
||||
public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
|
||||
this IServiceCollection services,
|
||||
Action<AppInsightsForKubernetesOptions> applyOptions,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder,
|
||||
Func<bool> detectKubernetes,
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger)
|
||||
{
|
||||
// Inject of the service shall return immediately.
|
||||
EnableKubernetesImpl(services, detectKubernetes, kubernetesServiceCollectionBuilder, null, timeout);
|
||||
return services;
|
||||
return EnableKubernetesImpl(services, detectKubernetes, kubernetesServiceCollectionBuilder, applyOptions: applyOptions, logger: logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables Application Insights Kubernetes for a given TelemetryConfiguration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The use of AddApplicationInsightsKubernetesEnricher() on the ServiceCollection is always preferred unless you have more than one TelemetryConfiguration
|
||||
/// instance, or if you are using Application Insights from a non ASP.NET environment, like a console app.
|
||||
/// </remarks>
|
||||
/// <param name="telemetryConfiguration">Sets the telemetry configuration to add the telemetry initializer to.</param>
|
||||
/// <param name="applyOptions">Sets a delegate to apply the configuration for the telemetry initializer.</param>
|
||||
/// <param name="kubernetesServiceCollectionBuilder">Sets a service collection builder.</param>
|
||||
/// <param name="detectKubernetes">Sets a delegate to detect if the current application is running in Kubernetes hosted container.</param>
|
||||
/// <param name="logger">Sets a logger for building the service collection.</param>
|
||||
public static void AddApplicationInsightsKubernetesEnricher(
|
||||
this TelemetryConfiguration telemetryConfiguration,
|
||||
TimeSpan? timeout = null,
|
||||
Action<AppInsightsForKubernetesOptions> applyOptions = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null)
|
||||
Func<bool> detectKubernetes = null,
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger = null)
|
||||
{
|
||||
IServiceCollection standaloneServiceCollection = new ServiceCollection();
|
||||
standaloneServiceCollection = EnableKubernetesImpl(standaloneServiceCollection, detectKubernetes, kubernetesServiceCollectionBuilder, null, timeout);
|
||||
standaloneServiceCollection = standaloneServiceCollection.AddApplicationInsightsKubernetesEnricher(
|
||||
applyOptions,
|
||||
kubernetesServiceCollectionBuilder,
|
||||
detectKubernetes,
|
||||
logger);
|
||||
|
||||
// Static class can't used as generic types.
|
||||
ILogger logger = standaloneServiceCollection.GetLogger<IKubernetesServiceCollectionBuilder>();
|
||||
IServiceProvider serviceProvider = standaloneServiceCollection.BuildServiceProvider();
|
||||
ITelemetryInitializer k8sTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>()
|
||||
.FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
@ -59,104 +96,85 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
if (k8sTelemetryInitializer != null)
|
||||
{
|
||||
telemetryConfiguration.TelemetryInitializers.Add(k8sTelemetryInitializer);
|
||||
logger?.LogInformation($"{nameof(KubernetesTelemetryInitializer)} is injected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError($"Getting ${nameof(KubernetesTelemetryInitializer)} from the service provider failed.");
|
||||
logger?.LogError($"Getting ${nameof(KubernetesTelemetryInitializer)} from the service provider failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Please use AddApplicationInsightsKubernetesEnricher() insead.
|
||||
/// Enables Application Insights Kubernetes for the Default TelemtryConfiguration in the dependency injection system.
|
||||
/// </summary>
|
||||
/// <param name="services">Collection of service descriptors.</param>
|
||||
/// <param name="timeout">Maximum time to wait for spinning up the container.</param>
|
||||
/// <param name="kubernetesServiceCollectionBuilder">Collection builder.</param>
|
||||
/// <param name="detectKubernetes">Delegate to detect if the current application is running in Kubernetes hosted container.</param>
|
||||
/// <returns>The collection of services descriptors we injected into.</returns>
|
||||
[Obsolete("Use AddApplicationInsightsKubernetesEnricher() instead", false)]
|
||||
public static IServiceCollection EnableKubernetes(
|
||||
this IServiceCollection services,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null)
|
||||
{
|
||||
return services.AddApplicationInsightsKubernetesEnricher(timeout, kubernetesServiceCollectionBuilder, detectKubernetes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Please use "AddApplicationInsightsKubernetesEnricher()" insead.
|
||||
/// Enables Application Insights Kubernetes for a given
|
||||
/// TelemetryConfiguration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The use of AddApplicationInsightsKubernetesEnricher() on the ServiceCollection is always
|
||||
/// preferred unless you have more than one TelemetryConfiguration
|
||||
/// instance, or if you are using Application Insights from a non ASP.NET
|
||||
/// environment, like a console app.
|
||||
/// </remarks>
|
||||
[Obsolete("Use AddApplicationInsightsKubernetesEnricher() instead", false)]
|
||||
public static void EnableKubernetes(
|
||||
this TelemetryConfiguration telemetryConfiguration,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null)
|
||||
{
|
||||
telemetryConfiguration.AddApplicationInsightsKubernetesEnricher(
|
||||
timeout, kubernetesServiceCollectionBuilder, detectKubernetes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables applicaiton insights for kubernetes.
|
||||
/// </summary>
|
||||
private static IServiceCollection EnableKubernetesImpl(IServiceCollection serviceCollection,
|
||||
Func<bool> detectKubernetes,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder,
|
||||
ILogger<KubernetesServiceCollectionBuilder> logger = null,
|
||||
TimeSpan? timeout = null)
|
||||
Action<AppInsightsForKubernetesOptions> applyOptions,
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger = null)
|
||||
{
|
||||
logger = logger ?? serviceCollection.GetLogger<KubernetesServiceCollectionBuilder>();
|
||||
|
||||
// 2 minutes by default maximum to wait for spinning up the container.
|
||||
timeout = timeout ?? TimeSpan.FromMinutes(2);
|
||||
|
||||
logger.LogInformation(Invariant($"ApplicationInsights.Kubernetes.Version:{SDKVersionUtils.Instance.CurrentSDKVersion}"));
|
||||
try
|
||||
{
|
||||
serviceCollection = BuildK8sServiceCollection(serviceCollection, timeout.Value, detectKubernetes, logger, kubernetesServiceCollectionBuilder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError("Failed to fetch ApplicaitonInsights.Kubernetes' info. Details " + ex.ToString());
|
||||
}
|
||||
BuildServiceBases(serviceCollection, applyOptions, ref logger);
|
||||
serviceCollection = BuildK8sServiceCollection(
|
||||
serviceCollection,
|
||||
detectKubernetes,
|
||||
logger: logger,
|
||||
kubernetesServiceCollectionBuilder: kubernetesServiceCollectionBuilder);
|
||||
return serviceCollection;
|
||||
}
|
||||
|
||||
private static void BuildServiceBases(
|
||||
IServiceCollection serviceCollection,
|
||||
Action<AppInsightsForKubernetesOptions> applyOptions,
|
||||
ref ILogger<IKubernetesServiceCollectionBuilder> logger)
|
||||
{
|
||||
serviceCollection.AddLogging();
|
||||
serviceCollection.AddOptions();
|
||||
IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
// Create a default logger when not passed in.
|
||||
logger = logger ?? serviceProvider.GetService<ILogger<IKubernetesServiceCollectionBuilder>>();
|
||||
|
||||
// Apply the conifguraitons ifnot yet.
|
||||
IOptions<AppInsightsForKubernetesOptions> options = serviceProvider.GetService<IOptions<AppInsightsForKubernetesOptions>>();
|
||||
|
||||
if (options.Value == null)
|
||||
{
|
||||
serviceCollection.AddSingleton<IOptions<AppInsightsForKubernetesOptions>>(
|
||||
new OptionsWrapper<AppInsightsForKubernetesOptions>(new AppInsightsForKubernetesOptions()));
|
||||
}
|
||||
|
||||
// Update settings from configuration.
|
||||
IConfiguration configuration = serviceProvider.GetService<IConfiguration>();
|
||||
if (configuration != null)
|
||||
{
|
||||
serviceCollection.Configure<AppInsightsForKubernetesOptions>(configuration.GetSection(ConfigurationSectionName));
|
||||
}
|
||||
|
||||
// Update settings when parameter is provided for backward compatibility.
|
||||
if (applyOptions != null)
|
||||
{
|
||||
serviceCollection.Configure<AppInsightsForKubernetesOptions>(option =>
|
||||
{
|
||||
applyOptions(option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static IServiceCollection BuildK8sServiceCollection(
|
||||
IServiceCollection services,
|
||||
TimeSpan timeout,
|
||||
Func<bool> detectKubernetes,
|
||||
ILogger<KubernetesServiceCollectionBuilder> logger,
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null)
|
||||
{
|
||||
detectKubernetes = detectKubernetes ?? IsRunningInKubernetes;
|
||||
kubernetesServiceCollectionBuilder = kubernetesServiceCollectionBuilder ?? new KubernetesServiceCollectionBuilder(detectKubernetes, logger);
|
||||
services = kubernetesServiceCollectionBuilder.InjectServices(services, timeout);
|
||||
kubernetesServiceCollectionBuilder = kubernetesServiceCollectionBuilder ??
|
||||
new KubernetesServiceCollectionBuilder(detectKubernetes, logger);
|
||||
|
||||
services = kubernetesServiceCollectionBuilder.InjectServices(services);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static bool IsRunningInKubernetes() => Directory.Exists(@"/var/run/secrets/kubernetes.io") || Directory.Exists(@"C:\var\run\secrets\kubernetes.io");
|
||||
|
||||
/// <summary>
|
||||
/// Gets a logger for given type.
|
||||
/// Note: This method leads to build service provider during the injection of services and shall be avoid whenever possible.
|
||||
/// </summary>
|
||||
private static ILogger<T> GetLogger<T>(this IServiceCollection services)
|
||||
{
|
||||
// AddLogging() is safe to call multiple times.
|
||||
// https://github.com/aspnet/Logging/blob/75a1cecf24f8418a45426b6cc3606f0d53640f89/src/Microsoft.Extensions.Logging/LoggingServiceCollectionExtensions.cs#L41
|
||||
return services.AddLogging().BuildServiceProvider().GetService<ILogger<T>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,20 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// </summary>
|
||||
public interface IKubernetesServiceCollectionBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Injects Application Insights for Kubernetes services into the service collection.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The collection of service descriptors.</param>
|
||||
/// <returns>The collection of services descriptors we injected into.</returns>
|
||||
IServiceCollection InjectServices(IServiceCollection serviceCollection);
|
||||
|
||||
/// <summary>
|
||||
/// Injects Application Insights for Kubernetes services into the service collection.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The collection of service descriptors.</param>
|
||||
/// <param name="timeout">Maximum time to wait for spinning up the container.</param>
|
||||
/// <returns>The collection of services descriptors we injected into.</returns>
|
||||
[Obsolete("Use InjectServices(IServiceCollection serviceCollection) instead.", error: true)]
|
||||
IServiceCollection InjectServices(IServiceCollection serviceCollection, TimeSpan timeout);
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly Func<bool> _isRunningInKubernetes;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Construction for <see cref="KubernetesServiceCollectionBuilder"/>.
|
||||
/// </summary>
|
||||
|
@ -22,12 +22,36 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// <param name="logger"></param>
|
||||
public KubernetesServiceCollectionBuilder(
|
||||
Func<bool> isRunningInKubernetes,
|
||||
ILogger<KubernetesServiceCollectionBuilder> logger)
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_logger = logger;
|
||||
_isRunningInKubernetes = isRunningInKubernetes ?? throw new ArgumentNullException(nameof(isRunningInKubernetes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects Kubernetes related service into the service collection.
|
||||
/// </summary>
|
||||
/// <param name="serviceCollection">The service collector to inject the services into.</param>
|
||||
/// <returns>Returns the service collector with services injected.</returns>
|
||||
public IServiceCollection InjectServices(IServiceCollection serviceCollection)
|
||||
{
|
||||
if (_isRunningInKubernetes())
|
||||
{
|
||||
IServiceCollection services = serviceCollection ?? throw new ArgumentNullException(nameof(serviceCollection));
|
||||
InjectCommonServices(services);
|
||||
InjectChangableServices(services);
|
||||
|
||||
services.AddSingleton<ITelemetryInitializer, KubernetesTelemetryInitializer>();
|
||||
_logger?.LogDebug("Application Insights Kubernetes injected the service successfully.");
|
||||
return services;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.LogWarning("Application is not running inside a Kubernetes cluster.");
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Injects Kubernetes related service into the service collection.
|
||||
/// </summary>
|
||||
|
@ -38,29 +62,16 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
if (_isRunningInKubernetes())
|
||||
{
|
||||
|
||||
IServiceCollection services = serviceCollection ?? new ServiceCollection();
|
||||
InjectCommonServices(services);
|
||||
|
||||
InjectChangableServices(services);
|
||||
|
||||
// Inject the telemetry initializer.
|
||||
services.AddSingleton<ITelemetryInitializer>(provider =>
|
||||
{
|
||||
KubernetesTelemetryInitializer initializer = new KubernetesTelemetryInitializer(
|
||||
provider.GetRequiredService<IK8sEnvironmentFactory>(),
|
||||
timeout,
|
||||
SDKVersionUtils.Instance,
|
||||
provider.GetRequiredService<ILogger<KubernetesTelemetryInitializer>>()
|
||||
);
|
||||
_logger.LogDebug("Application Insights Kubernetes injected the service successfully.");
|
||||
return initializer;
|
||||
});
|
||||
return services;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("Application is not running inside a Kubernetes cluster.");
|
||||
_logger?.LogWarning("Application is not running inside a Kubernetes cluster.");
|
||||
return serviceCollection;
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +80,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
serviceCollection.AddSingleton<KubeHttpClientFactory>();
|
||||
serviceCollection.AddSingleton<K8sQueryClientFactory>();
|
||||
serviceCollection.AddSingleton<SDKVersionUtils>(SDKVersionUtils.Instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -79,11 +91,13 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
serviceCollection.AddSingleton<IKubeHttpClientSettingsProvider>(p => new KubeHttpClientSettingsProvider(logger: p.GetService<ILogger<KubeHttpClientSettingsProvider>>()));
|
||||
serviceCollection.AddSingleton<IKubeHttpClientSettingsProvider>(p =>
|
||||
new KubeHttpClientSettingsProvider(logger: p.GetService<ILogger<KubeHttpClientSettingsProvider>>()));
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
serviceCollection.AddSingleton<IKubeHttpClientSettingsProvider>(p => new KubeHttpSettingsWinContainerProvider(logger: p.GetService<ILogger<KubeHttpSettingsWinContainerProvider>>()));
|
||||
serviceCollection.AddSingleton<IKubeHttpClientSettingsProvider>(p =>
|
||||
new KubeHttpSettingsWinContainerProvider(logger: p.GetService<ILogger<KubeHttpSettingsWinContainerProvider>>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.Kubernetes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// This class holds all the obsoleted methods for ApplicationInsightsExtensions for readability.
|
||||
/// </summary>
|
||||
public static partial class ApplicationInsightsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables Application Insights for Kubernetes on the Default TelemtryConfiguration in the dependency injection system.
|
||||
/// </summary>
|
||||
/// <param name="services">Sets the collection of service descriptors.</param>
|
||||
/// <param name="timeout">Sets the maximum time to wait for spinning up the container.</param>
|
||||
/// <param name="kubernetesServiceCollectionBuilder">Sets the collection builder.</param>
|
||||
/// <param name="detectKubernetes">Sets a delegate to detect if the current application is running in Kubernetes hosted container.</param>
|
||||
/// <param name="logger">Sets a logger for building the service collection.</param>
|
||||
/// <returns>The collection of services descriptors injected into.</returns>
|
||||
[Obsolete("Use AddApplicationInsightsKubernetesEnricher with Options instead.", error: false)]
|
||||
public static IServiceCollection AddApplicationInsightsKubernetesEnricher(
|
||||
this IServiceCollection services,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null,
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger = null)
|
||||
{
|
||||
return services.AddApplicationInsightsKubernetesEnricher(option =>
|
||||
{
|
||||
if (timeout != null && timeout.HasValue)
|
||||
{
|
||||
option.InitializationTimeout = timeout.Value;
|
||||
}
|
||||
}, kubernetesServiceCollectionBuilder, detectKubernetes, logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables Application Insights Kubernetes for a given TelemetryConfiguration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The use of AddApplicationInsightsKubernetesEnricher() on the ServiceCollection is always preferred unless you have more than one TelemetryConfiguration
|
||||
/// instance, or if you are using Application Insights from a non ASP.NET environment, like a console app.
|
||||
/// </remarks>
|
||||
[Obsolete("Use AddApplicationInsightsKubernetesEnricher with Options instead.", error: false)]
|
||||
public static void AddApplicationInsightsKubernetesEnricher(
|
||||
this TelemetryConfiguration telemetryConfiguration,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null,
|
||||
ILogger<IKubernetesServiceCollectionBuilder> logger = null)
|
||||
{
|
||||
IServiceCollection standaloneServiceCollection = new ServiceCollection();
|
||||
standaloneServiceCollection = standaloneServiceCollection.AddApplicationInsightsKubernetesEnricher(
|
||||
timeout, kubernetesServiceCollectionBuilder, detectKubernetes);
|
||||
|
||||
// Static class can't used as generic types.
|
||||
IServiceProvider serviceProvider = standaloneServiceCollection.BuildServiceProvider();
|
||||
ITelemetryInitializer k8sTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>()
|
||||
.FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
||||
if (k8sTelemetryInitializer != null)
|
||||
{
|
||||
telemetryConfiguration.TelemetryInitializers.Add(k8sTelemetryInitializer);
|
||||
logger?.LogInformation($"{nameof(KubernetesTelemetryInitializer)} is injected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger?.LogError($"Getting ${nameof(KubernetesTelemetryInitializer)} from the service provider failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Please use AddApplicationInsightsKubernetesEnricher() insead.
|
||||
/// Enables Application Insights Kubernetes for the Default TelemtryConfiguration in the dependency injection system.
|
||||
/// </summary>
|
||||
/// <param name="services">Collection of service descriptors.</param>
|
||||
/// <param name="timeout">Maximum time to wait for spinning up the container.</param>
|
||||
/// <param name="kubernetesServiceCollectionBuilder">Collection builder.</param>
|
||||
/// <param name="detectKubernetes">Delegate to detect if the current application is running in Kubernetes hosted container.</param>
|
||||
/// <returns>The collection of services descriptors injected into.</returns>
|
||||
[Obsolete("Use AddApplicationInsightsKubernetesEnricher() instead", false)]
|
||||
public static IServiceCollection EnableKubernetes(
|
||||
this IServiceCollection services,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null)
|
||||
{
|
||||
return services.AddApplicationInsightsKubernetesEnricher(timeout, kubernetesServiceCollectionBuilder, detectKubernetes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Please use "AddApplicationInsightsKubernetesEnricher()" insead.
|
||||
/// Enables Application Insights Kubernetes for a given
|
||||
/// TelemetryConfiguration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The use of AddApplicationInsightsKubernetesEnricher() on the ServiceCollection is always
|
||||
/// preferred unless you have more than one TelemetryConfiguration
|
||||
/// instance, or if you are using Application Insights from a non ASP.NET
|
||||
/// environment, like a console app.
|
||||
/// </remarks>
|
||||
[Obsolete("Use AddApplicationInsightsKubernetesEnricher() instead", false)]
|
||||
public static void EnableKubernetes(
|
||||
this TelemetryConfiguration telemetryConfiguration,
|
||||
TimeSpan? timeout = null,
|
||||
IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null,
|
||||
Func<bool> detectKubernetes = null)
|
||||
{
|
||||
telemetryConfiguration.AddApplicationInsightsKubernetesEnricher(
|
||||
timeout, kubernetesServiceCollectionBuilder, detectKubernetes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.Extensibility.Implementation;
|
||||
using Microsoft.ApplicationInsights.Kubernetes.Utilities;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using static Microsoft.ApplicationInsights.Kubernetes.StringUtils;
|
||||
|
||||
#if !NETSTANDARD1_3 && !NETSTANDARD1_6
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
#endif
|
||||
|
||||
|
@ -31,26 +33,24 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
public const string CPU = "CPU";
|
||||
public const string Memory = "Memory";
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly SDKVersionUtils _sdkVersionUtils;
|
||||
private readonly DateTime _timeoutAt;
|
||||
|
||||
internal readonly IK8sEnvironmentFactory _k8sEnvFactory;
|
||||
internal IK8sEnvironment _k8sEnvironment { get; private set; }
|
||||
|
||||
internal bool _isK8sQueryTimeout = false;
|
||||
private bool _isK8sQueryTimeoutReported = false;
|
||||
|
||||
public KubernetesTelemetryInitializer(
|
||||
IK8sEnvironmentFactory k8sEnvFactory,
|
||||
TimeSpan timeout,
|
||||
IOptions<AppInsightsForKubernetesOptions> options,
|
||||
SDKVersionUtils sdkVersionUtils,
|
||||
ILogger<KubernetesTelemetryInitializer> logger)
|
||||
{
|
||||
_k8sEnvironment = null;
|
||||
_logger = logger;
|
||||
|
||||
// Options can't be null.
|
||||
Debug.Assert(options != null, "Options can't be null.");
|
||||
_options = Arguments.IsNotNull(options?.Value, nameof(options));
|
||||
|
||||
_logger.LogDebug($@"Initialize Application Insihgts for Kubernetes telemetry initializer with Options:
|
||||
{JsonConvert.SerializeObject(_options)}");
|
||||
|
||||
_sdkVersionUtils = Arguments.IsNotNull(sdkVersionUtils, nameof(sdkVersionUtils));
|
||||
_timeoutAt = DateTime.Now.Add(Arguments.IsNotNull(timeout, nameof(timeout)));
|
||||
_timeoutAt = DateTime.Now.Add(_options.InitializationTimeout);
|
||||
_k8sEnvFactory = Arguments.IsNotNull(k8sEnvFactory, nameof(k8sEnvFactory));
|
||||
|
||||
var _forget = SetK8sEnvironment();
|
||||
|
@ -206,5 +206,17 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly SDKVersionUtils _sdkVersionUtils;
|
||||
private readonly DateTime _timeoutAt;
|
||||
|
||||
internal readonly IK8sEnvironmentFactory _k8sEnvFactory;
|
||||
internal IK8sEnvironment _k8sEnvironment { get; private set; }
|
||||
|
||||
internal AppInsightsForKubernetesOptions _options { get; private set; }
|
||||
|
||||
internal bool _isK8sQueryTimeout = false;
|
||||
private bool _isK8sQueryTimeoutReported = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)PublicKey.snk</AssemblyOriginatorKeyFile>
|
||||
<!--Package-->
|
||||
<VersionSuffix Condition=" '$(VersionSuffix)' == '' ">$([System.DateTime]::Now.ToString(yyyyMMddHHmm))</VersionSuffix>
|
||||
<Version Condition=" '$(Version)' == '' ">1.0.1-private-$(VersionSuffix)</Version>
|
||||
<AssemblyVersion Condition=" '$(AssemblyVersion)' == '' " >1.0.1.0</AssemblyVersion>
|
||||
<Version Condition=" '$(Version)' == '' ">1.0.2-private-$(VersionSuffix)</Version>
|
||||
<AssemblyVersion Condition=" '$(AssemblyVersion)' == '' " >1.0.2.0</AssemblyVersion>
|
||||
<Authors>Microsoft</Authors>
|
||||
<Company>Microsoft</Company>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Microsoft.ApplicationInsights.Netcore.Kubernetes
|
|||
using (KubeHttpClient httpClient = new KubeHttpClient(settingsMock.Object, GetLogger<KubeHttpClient>()))
|
||||
using (K8sQueryClient target = new K8sQueryClient(httpClient, GetLogger<K8sQueryClient>()))
|
||||
{
|
||||
Assert.Equal(httpClient, target.KubeHttpClient);
|
||||
Assert.Same(httpClient, target.KubeHttpClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.ApplicationInsights.Channel;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.ApplicationInsights.Kubernetes;
|
||||
using Microsoft.ApplicationInsights.Kubernetes.Utilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
@ -17,7 +20,8 @@ namespace Microsoft.ApplicationInsights.Netcore.Kubernetes
|
|||
public void ServiceInjected()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services = services.AddApplicationInsightsKubernetesEnricher(detectKubernetes: () => true);
|
||||
services = services.AddApplicationInsightsKubernetesEnricher(applyOptions: null, kubernetesServiceCollectionBuilder: null, detectKubernetes: () => true, logger: null);
|
||||
Assert.NotNull(services.FirstOrDefault(sd => sd.ImplementationType == typeof(KubernetesTelemetryInitializer)));
|
||||
|
||||
// Replace the IKubeHttpClientSetingsProvider in case the test is not running inside a container.
|
||||
Assert.NotNull(services.FirstOrDefault(s => s.ServiceType == typeof(IKubeHttpClientSettingsProvider)));
|
||||
|
@ -26,6 +30,7 @@ namespace Microsoft.ApplicationInsights.Netcore.Kubernetes
|
|||
services.AddSingleton<IKubeHttpClientSettingsProvider>(p => mock.Object);
|
||||
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
ITelemetryInitializer targetTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>().FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
||||
// Logging
|
||||
serviceProvider.GetRequiredService<ILoggerFactory>();
|
||||
|
@ -38,6 +43,137 @@ namespace Microsoft.ApplicationInsights.Netcore.Kubernetes
|
|||
serviceProvider.GetRequiredService<IK8sEnvironmentFactory>();
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Default timeout for waiting container to spin us is 2 minutes")]
|
||||
public void EnableAppInsightsForKubernetesWithDefaultTimeOut()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services = services.AddApplicationInsightsKubernetesEnricher(
|
||||
applyOptions:null,
|
||||
kubernetesServiceCollectionBuilder: null,
|
||||
detectKubernetes: () => true,
|
||||
logger: null);
|
||||
Assert.NotNull(services.FirstOrDefault(sd => sd.ImplementationType == typeof(KubernetesTelemetryInitializer)));
|
||||
|
||||
// Replace the IKubeHttpClientSetingsProvider in case the test is not running inside a container.
|
||||
Assert.NotNull(services.FirstOrDefault(s => s.ServiceType == typeof(IKubeHttpClientSettingsProvider)));
|
||||
Mock<IKubeHttpClientSettingsProvider> mock = new Mock<IKubeHttpClientSettingsProvider>();
|
||||
services.Remove(new ServiceDescriptor(typeof(IKubeHttpClientSettingsProvider), typeof(KubeHttpClientSettingsProvider), ServiceLifetime.Singleton));
|
||||
services.AddSingleton<IKubeHttpClientSettingsProvider>(p => mock.Object);
|
||||
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
ITelemetryInitializer targetTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>().FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
||||
if (targetTelemetryInitializer is KubernetesTelemetryInitializer target)
|
||||
{
|
||||
Assert.StrictEqual(TimeSpan.FromMinutes(2), target._options.InitializationTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(false, "Not the target telementry initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Set timeout through options works for telemetry initializer.")]
|
||||
public void EnableAppInsightsForKubernetesWithTimeOutSetThroughOptions()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services = services.AddApplicationInsightsKubernetesEnricher(applyOptions:
|
||||
option =>
|
||||
{
|
||||
option.InitializationTimeout = TimeSpan.FromSeconds(5);
|
||||
}, kubernetesServiceCollectionBuilder: null, detectKubernetes: () => true, logger: null);
|
||||
Assert.NotNull(services.FirstOrDefault(sd => sd.ImplementationType == typeof(KubernetesTelemetryInitializer)));
|
||||
|
||||
// Replace the IKubeHttpClientSetingsProvider in case the test is not running inside a container.
|
||||
Assert.NotNull(services.FirstOrDefault(s => s.ServiceType == typeof(IKubeHttpClientSettingsProvider)));
|
||||
Mock<IKubeHttpClientSettingsProvider> mock = new Mock<IKubeHttpClientSettingsProvider>();
|
||||
services.Remove(new ServiceDescriptor(typeof(IKubeHttpClientSettingsProvider), typeof(KubeHttpClientSettingsProvider), ServiceLifetime.Singleton));
|
||||
services.AddSingleton<IKubeHttpClientSettingsProvider>(p => mock.Object);
|
||||
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
ITelemetryInitializer targetTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>().FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
||||
if (targetTelemetryInitializer is KubernetesTelemetryInitializer target)
|
||||
{
|
||||
Assert.StrictEqual(TimeSpan.FromSeconds(5), target._options.InitializationTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(false, "Not the target telementry initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Set timeout through configuration works for telemetry initializer.")]
|
||||
public void EnableAppInsightsForKubernetesWithTimeOutSetThroughConfiguration()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
IConfiguration config = new ConfigurationBuilder().AddInMemoryCollection(
|
||||
new Dictionary<string, string>(){
|
||||
{"a" , "b"},
|
||||
{"AppInsightsForKubernetes:InitializationTimeout", "3.1:12:15.34"}
|
||||
}).Build();
|
||||
services.AddSingleton<IConfiguration>(config);
|
||||
|
||||
services = services.AddApplicationInsightsKubernetesEnricher(
|
||||
applyOptions: null, kubernetesServiceCollectionBuilder: null, detectKubernetes: () => true, logger: null);
|
||||
Assert.NotNull(services.FirstOrDefault(sd => sd.ImplementationType == typeof(KubernetesTelemetryInitializer)));
|
||||
|
||||
// Replace the IKubeHttpClientSetingsProvider in case the test is not running inside a container.
|
||||
Assert.NotNull(services.FirstOrDefault(s => s.ServiceType == typeof(IKubeHttpClientSettingsProvider)));
|
||||
Mock<IKubeHttpClientSettingsProvider> mock = new Mock<IKubeHttpClientSettingsProvider>();
|
||||
services.Remove(new ServiceDescriptor(typeof(IKubeHttpClientSettingsProvider), typeof(KubeHttpClientSettingsProvider), ServiceLifetime.Singleton));
|
||||
services.AddSingleton<IKubeHttpClientSettingsProvider>(p => mock.Object);
|
||||
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
ITelemetryInitializer targetTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>().FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
||||
if (targetTelemetryInitializer is KubernetesTelemetryInitializer target)
|
||||
{
|
||||
Assert.StrictEqual(new TimeSpan(days: 3, hours: 1, minutes: 12, seconds: 15, milliseconds: 340), target._options.InitializationTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(false, "Not the target telementry initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Set timeout through configuration works for telemetry initializer.")]
|
||||
public void EnableAppInsightsForKubernetesWithTimeOutSetThroughOptionsOverwritingConfiugure()
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
IConfiguration config = new ConfigurationBuilder().AddInMemoryCollection(
|
||||
new Dictionary<string, string>(){
|
||||
{"a" , "b"},
|
||||
{"AppInsightsForKubernetes:InitializationTimeout", "3.1:12:15.34"}
|
||||
}).Build();
|
||||
services.AddSingleton<IConfiguration>(config);
|
||||
|
||||
services = services.AddApplicationInsightsKubernetesEnricher(
|
||||
applyOptions: option =>
|
||||
{
|
||||
option.InitializationTimeout = TimeSpan.FromSeconds(30);
|
||||
}, kubernetesServiceCollectionBuilder: null, detectKubernetes: () => true, logger: null);
|
||||
Assert.NotNull(services.FirstOrDefault(sd => sd.ImplementationType == typeof(KubernetesTelemetryInitializer)));
|
||||
|
||||
// Replace the IKubeHttpClientSetingsProvider in case the test is not running inside a container.
|
||||
Assert.NotNull(services.FirstOrDefault(s => s.ServiceType == typeof(IKubeHttpClientSettingsProvider)));
|
||||
Mock<IKubeHttpClientSettingsProvider> mock = new Mock<IKubeHttpClientSettingsProvider>();
|
||||
services.Remove(new ServiceDescriptor(typeof(IKubeHttpClientSettingsProvider), typeof(KubeHttpClientSettingsProvider), ServiceLifetime.Singleton));
|
||||
services.AddSingleton<IKubeHttpClientSettingsProvider>(p => mock.Object);
|
||||
|
||||
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||
ITelemetryInitializer targetTelemetryInitializer = serviceProvider.GetServices<ITelemetryInitializer>().FirstOrDefault(ti => ti is KubernetesTelemetryInitializer);
|
||||
|
||||
if (targetTelemetryInitializer is KubernetesTelemetryInitializer target)
|
||||
{
|
||||
Assert.StrictEqual(TimeSpan.FromSeconds(30), target._options.InitializationTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(false, "Not the target telementry initializer.");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Support adding KubernetesTelemetryInitializer to given TelemetryConfiguration")]
|
||||
public void AddTheInitializerToGivenConfiguration()
|
||||
{
|
||||
|
@ -45,6 +181,8 @@ namespace Microsoft.ApplicationInsights.Netcore.Kubernetes
|
|||
Mock<IKubernetesServiceCollectionBuilder> serviceCollectionBuilderMock = new Mock<IKubernetesServiceCollectionBuilder>();
|
||||
ServiceCollection sc = new ServiceCollection();
|
||||
sc.AddLogging();
|
||||
sc.AddOptions();
|
||||
sc.Configure<AppInsightsForKubernetesOptions>(options => options.InitializationTimeout = TimeSpan.FromSeconds(5));
|
||||
|
||||
sc.AddSingleton<ITelemetryInitializer>(p =>
|
||||
{
|
||||
|
@ -52,16 +190,23 @@ namespace Microsoft.ApplicationInsights.Netcore.Kubernetes
|
|||
envMock.Setup(env => env.ContainerID).Returns("Cid");
|
||||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(envMock.Object, TimeSpan.FromMinutes(1));
|
||||
return new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(5), SDKVersionUtils.Instance, p.GetService<ILogger<KubernetesTelemetryInitializer>>());
|
||||
return new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
p.GetService<IOptions<AppInsightsForKubernetesOptions>>(),
|
||||
SDKVersionUtils.Instance,
|
||||
p.GetService<ILogger<KubernetesTelemetryInitializer>>());
|
||||
});
|
||||
serviceCollectionBuilderMock.Setup(b => b.InjectServices(It.IsAny<IServiceCollection>(), It.IsAny<TimeSpan>()))
|
||||
serviceCollectionBuilderMock.Setup(b => b.InjectServices(It.IsAny<IServiceCollection>()))
|
||||
.Returns(sc);
|
||||
|
||||
TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration("123", channelMock.Object);
|
||||
telemetryConfiguration.AddApplicationInsightsKubernetesEnricher(null, serviceCollectionBuilderMock.Object, detectKubernetes: () => true);
|
||||
telemetryConfiguration.AddApplicationInsightsKubernetesEnricher(
|
||||
applyOptions: null,
|
||||
kubernetesServiceCollectionBuilder: serviceCollectionBuilderMock.Object,
|
||||
detectKubernetes: () => true);
|
||||
|
||||
Assert.NotNull(telemetryConfiguration.TelemetryInitializers);
|
||||
Assert.True(telemetryConfiguration.TelemetryInitializers.Count == 1);
|
||||
Assert.Single(telemetryConfiguration.TelemetryInitializers);
|
||||
Assert.True(telemetryConfiguration.TelemetryInitializers.First() is KubernetesTelemetryInitializer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using Microsoft.ApplicationInsights.Kubernetes.Utilities;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Internal;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
@ -18,7 +19,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
{
|
||||
Exception ex = Assert.Throws<ArgumentNullException>(() =>
|
||||
{
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(null, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
null,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
});
|
||||
|
||||
Assert.Equal("Value cannot be null.\r\nParameter name: k8sEnvFactory", ex.Message);
|
||||
|
@ -31,7 +36,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
var factoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
factoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(() => envMock.Object);
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(factoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
factoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
|
||||
Assert.NotNull(target._k8sEnvironment);
|
||||
Assert.Equal(factoryMock.Object, target._k8sEnvFactory);
|
||||
|
@ -46,7 +55,10 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(() => envMock.Object);
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
target.Initialize(telemetry);
|
||||
|
||||
|
@ -61,7 +73,10 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(() => envMock.Object);
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance, GetLogger());
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
telemetry.Context.Cloud.RoleName = "Existing RoleName";
|
||||
target.Initialize(telemetry);
|
||||
|
@ -93,7 +108,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
|
||||
var loggerMock = new Mock<ILogger<KubernetesTelemetryInitializer>>();
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, loggerMock.Object);
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
loggerMock.Object);
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
target.Initialize(telemetry);
|
||||
loggerMock.Verify(l => l.Log(LogLevel.Error, 0, It.IsAny<FormattedLogValues>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()), Times.Never());
|
||||
|
@ -123,7 +142,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
|
||||
var loggerMock = new Mock<ILogger<KubernetesTelemetryInitializer>>();
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, loggerMock.Object);
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
loggerMock.Object);
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
target.Initialize(telemetry);
|
||||
loggerMock.Verify(l => l.Log(LogLevel.Error, 0, It.IsAny<FormattedLogValues>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()), Times.Exactly(2));
|
||||
|
@ -150,7 +173,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(() => envMock.Object);
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
target.Initialize(telemetry);
|
||||
|
||||
|
@ -184,7 +211,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(() => envMock.Object);
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
telemetry.Context.Properties["K8s.Container.ID"] = "Existing Cid";
|
||||
target.Initialize(telemetry);
|
||||
|
@ -199,7 +230,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
envMock.Setup(env => env.ContainerID).Returns("Cid");
|
||||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(envMock.Object, TimeSpan.FromMinutes(1));
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
|
||||
ITelemetry telemetry = new TraceTelemetry();
|
||||
telemetry.Context.Properties["K8s.Container.ID"] = "No Crash";
|
||||
|
@ -215,8 +250,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
envMock.Setup(env => env.ContainerID).Returns("Cid");
|
||||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(envMock.Object, TimeSpan.FromMinutes(1));
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(1), SDKVersionUtils.Instance, GetLogger());
|
||||
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(1)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
Assert.False(target._isK8sQueryTimeout);
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
Assert.True(target._isK8sQueryTimeout);
|
||||
|
@ -229,7 +267,11 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
envMock.Setup(env => env.ContainerID).Returns("Cid");
|
||||
var envFactoryMock = new Mock<IK8sEnvironmentFactory>();
|
||||
envFactoryMock.Setup(f => f.CreateAsync(It.IsAny<DateTime>())).ReturnsAsync(envMock.Object, TimeSpan.FromMinutes(1));
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envFactoryMock.Object, TimeSpan.FromSeconds(30), SDKVersionUtils.Instance, GetLogger());
|
||||
KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(
|
||||
envFactoryMock.Object,
|
||||
GetOptions(TimeSpan.FromSeconds(30)),
|
||||
SDKVersionUtils.Instance,
|
||||
GetLogger());
|
||||
|
||||
// K8s Enviornment is still null.
|
||||
Assert.Null(target._k8sEnvironment);
|
||||
|
@ -254,5 +296,13 @@ namespace Microsoft.ApplicationInsights.Kubernetes
|
|||
serviceCollection.AddLogging();
|
||||
return serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
private IOptions<AppInsightsForKubernetesOptions> GetOptions(TimeSpan timeout)
|
||||
{
|
||||
return new OptionsWrapper<AppInsightsForKubernetesOptions>(new AppInsightsForKubernetesOptions()
|
||||
{
|
||||
InitializationTimeout = timeout,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче