From 578f20e824e6248029554a1f8990b29c4a7c6d11 Mon Sep 17 00:00:00 2001 From: Saar Shen Date: Mon, 12 Mar 2018 20:58:00 -0700 Subject: [PATCH] Feature/sdk version 2 (#99) * Enable stub mode for the SDK * Add some stub data * Set internal SDK version for easy identifying sdks * Further refactor: Use service colleciton builder Encapsulate the diffs for service collection. * Add some more isolation for the debugging modules Move debugging modules into separate namespaces so the user do not use it by accident. --- .../K8sDebuggingEnvironmentFactory.cs | 70 +++++++++++++++++++ .../KubeDebuggingHttpClientSettings.cs | 26 +++++++ ...rnetesDebuggingServiceCollectionBuilder.cs | 22 ++++++ .../ApplicationInsightsExtensions.cs | 17 ++--- .../IKubernetesServiceCollectionBuilder.cs | 7 ++ .../KubernetesServiceCollectionBuilder.cs | 40 +++++++++++ .../Interfaces/IK8sEnvironmentFactory.cs | 10 +++ .../K8sEnvironmentFactory.cs | 3 +- .../TelemetryInitializers/KubernetesModule.cs | 33 ++++----- .../KubernetesTelemetryInitializer.cs | 9 ++- .../Utilities/SDKVersionUtils.cs | 38 ++++++++++ src/Directory.Build.props | 1 + tests/UnitTests/KubernetesModuleTests.cs | 2 +- .../KubernetesTelemtryInitializerTests.cs | 13 ++-- 14 files changed, 253 insertions(+), 38 deletions(-) create mode 100644 src/ApplicationInsights.Kubernetes/Debuggings/K8sDebuggingEnvironmentFactory.cs create mode 100644 src/ApplicationInsights.Kubernetes/Debuggings/KubeDebuggingHttpClientSettings.cs create mode 100644 src/ApplicationInsights.Kubernetes/Debuggings/KubernetesDebuggingServiceCollectionBuilder.cs create mode 100644 src/ApplicationInsights.Kubernetes/Extensions/IKubernetesServiceCollectionBuilder.cs create mode 100644 src/ApplicationInsights.Kubernetes/Extensions/KubernetesServiceCollectionBuilder.cs create mode 100644 src/ApplicationInsights.Kubernetes/Interfaces/IK8sEnvironmentFactory.cs create mode 100644 src/ApplicationInsights.Kubernetes/Utilities/SDKVersionUtils.cs diff --git a/src/ApplicationInsights.Kubernetes/Debuggings/K8sDebuggingEnvironmentFactory.cs b/src/ApplicationInsights.Kubernetes/Debuggings/K8sDebuggingEnvironmentFactory.cs new file mode 100644 index 00000000..9f005348 --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Debuggings/K8sDebuggingEnvironmentFactory.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.ApplicationInsights.Kubernetes.Entities; + +namespace Microsoft.ApplicationInsights.Kubernetes.Debugging +{ + internal class K8sDebuggingEnvironmentFactory : IK8sEnvironmentFactory + { + public Task CreateAsync(TimeSpan timeout) + { + return Task.FromResult(new K8sEnvironment() + { + ContainerID = KubeHttpDebuggingClientSettings.FakeContainerId, + myContainerStatus = new ContainerStatus() + { + ContainerID = KubeHttpDebuggingClientSettings.FakeContainerId, + Image = nameof(ContainerStatus.Image), + ImageID = nameof(ContainerStatus.ImageID), + Name = nameof(ContainerStatus.Name), + Ready = true, + }, + myDeployment = new K8sDeployment() + { + Metadata = new K8sDeploymentMetadata() + { + Labels = new Dictionary() { { "app", "stub" } }, + Name = nameof(K8sDeploymentMetadata.Name), + Uid = nameof(K8sDeploymentMetadata.Uid), + }, + Spec = new K8sDeploymentSpec() + { + Selector = new Selector() + { + MatchLabels = new Dictionary() { { "app", "stub" } }, + }, + }, + }, + myNode = new K8sNode() + { + Metadata = new K8sNodeMetadata() + { + Labels = new Dictionary() { { "app", "stub" } }, + Name = nameof(K8sNodeMetadata.Name), + Uid = nameof(K8sNodeMetadata.Uid), + }, + Status = new K8sNodeStatus() + { + }, + }, + myPod = new K8sPod() + { + Metadata = new K8sPodMetadata() + { + Uid = "StubPodId", + Name = "StubPodName", + Labels = new Dictionary() { { "app", "stub" } }, + } + }, + myReplicaSet = new K8sReplicaSet() + { + Metadata = new K8sReplicaSetMetadata() + { + Name = "StubReplicaName", + } + } + }); + } + } +} diff --git a/src/ApplicationInsights.Kubernetes/Debuggings/KubeDebuggingHttpClientSettings.cs b/src/ApplicationInsights.Kubernetes/Debuggings/KubeDebuggingHttpClientSettings.cs new file mode 100644 index 00000000..9722c61f --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Debuggings/KubeDebuggingHttpClientSettings.cs @@ -0,0 +1,26 @@ +using System; +using System.Net.Http; + +namespace Microsoft.ApplicationInsights.Kubernetes.Debugging +{ + internal class KubeHttpDebuggingClientSettings : IKubeHttpClientSettingsProvider + { + public const string FakeContainerId = "F8E1C6FF-2217-4962-90FF-0D9195AF0785"; + + public string ContainerId => FakeContainerId; + + public string QueryNamespace => "063A30B8-6A62-4519-8BFE-0DE144B009A1"; + + public Uri ServiceBaseAddress => new Uri("http://localhost/stub"); + + public HttpMessageHandler CreateMessageHandler() + { + return null; + } + + public string GetToken() + { + return null; + } + } +} diff --git a/src/ApplicationInsights.Kubernetes/Debuggings/KubernetesDebuggingServiceCollectionBuilder.cs b/src/ApplicationInsights.Kubernetes/Debuggings/KubernetesDebuggingServiceCollectionBuilder.cs new file mode 100644 index 00000000..724230bf --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Debuggings/KubernetesDebuggingServiceCollectionBuilder.cs @@ -0,0 +1,22 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.ApplicationInsights.Kubernetes.Debugging +{ + public sealed class KubernetesDebuggingServiceCollectionBuilder : KubernetesServiceCollectionBuilder + { + #region Singleton + private KubernetesDebuggingServiceCollectionBuilder() { } + private static KubernetesDebuggingServiceCollectionBuilder _instance = new KubernetesDebuggingServiceCollectionBuilder(); + + [Obsolete("This instance is used only for debugging. Never use this in production!", false)] + public static KubernetesDebuggingServiceCollectionBuilder Instance => _instance; + #endregion + + protected override void InjectChangableServices(IServiceCollection serviceCollection) + { + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + } + } +} diff --git a/src/ApplicationInsights.Kubernetes/Extensions/ApplicationInsightsExtensions.cs b/src/ApplicationInsights.Kubernetes/Extensions/ApplicationInsightsExtensions.cs index c8fb3f5f..129e9d15 100644 --- a/src/ApplicationInsights.Kubernetes/Extensions/ApplicationInsightsExtensions.cs +++ b/src/ApplicationInsights.Kubernetes/Extensions/ApplicationInsightsExtensions.cs @@ -1,24 +1,25 @@ -namespace Microsoft.Extensions.DependencyInjection +using System; +using System.Threading.Tasks; +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.ApplicationInsights.Kubernetes; + +namespace Microsoft.Extensions.DependencyInjection { - using System; - using System.Threading.Tasks; - using Microsoft.ApplicationInsights.Extensibility; - using Microsoft.ApplicationInsights.Kubernetes; - using Microsoft.Extensions.Logging; /// /// Extnesion method to inject Kubernetes Telemtry Initializer. /// public static class ApplicationInsightsExtensions { - public static IServiceCollection EnableKubernetes(this IServiceCollection services, TimeSpan? timeout = null) + public static IServiceCollection EnableKubernetes(this IServiceCollection services, TimeSpan? timeout = null, + IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null) { // Dispatch this on a differnet thread to avoid blocking the main thread. // Mainly used with K8s Readness Probe enabled, where communicating with Server will temperory be blocked. // TODO: Instead of query the server on the start, we should depend on watch services to provide dynamic realtime data. Task.Run(() => { - KubernetesModule.EnableKubernetes(services, TelemetryConfiguration.Active, timeout); + KubernetesModule.EnableKubernetes(services, TelemetryConfiguration.Active, timeout, kubernetesServiceCollectionBuilder); }); return services; diff --git a/src/ApplicationInsights.Kubernetes/Extensions/IKubernetesServiceCollectionBuilder.cs b/src/ApplicationInsights.Kubernetes/Extensions/IKubernetesServiceCollectionBuilder.cs new file mode 100644 index 00000000..f99a6a51 --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Extensions/IKubernetesServiceCollectionBuilder.cs @@ -0,0 +1,7 @@ +namespace Microsoft.Extensions.DependencyInjection +{ + public interface IKubernetesServiceCollectionBuilder + { + IServiceCollection InjectServices(IServiceCollection serviceCollection); + } +} \ No newline at end of file diff --git a/src/ApplicationInsights.Kubernetes/Extensions/KubernetesServiceCollectionBuilder.cs b/src/ApplicationInsights.Kubernetes/Extensions/KubernetesServiceCollectionBuilder.cs new file mode 100644 index 00000000..0280efe9 --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Extensions/KubernetesServiceCollectionBuilder.cs @@ -0,0 +1,40 @@ +using Microsoft.ApplicationInsights.Kubernetes; +using Microsoft.Extensions.Logging; + +namespace Microsoft.Extensions.DependencyInjection +{ + public class KubernetesServiceCollectionBuilder : IKubernetesServiceCollectionBuilder + { + /// + /// Inject Kubernetes related service into the service collection. + /// + /// + /// + public IServiceCollection InjectServices(IServiceCollection serviceCollection) + { + IServiceCollection services = serviceCollection ?? new ServiceCollection(); + InjectCommonServices(services); + + InjectChangableServices(services); + + return services; + } + + private static void InjectCommonServices(IServiceCollection serviceCollection) + { + // According to the code, adding logging will not overwrite existing logging classes + // https://github.com/aspnet/Logging/blob/c821494678a30c323174bea8056f43b93a3ca6f4/src/Microsoft.Extensions.Logging/LoggingServiceCollectionExtensions.cs + // Becuase it uses 'TryAdd()' extenion method on service collection. + serviceCollection.AddLogging(); + + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + } + + protected virtual void InjectChangableServices(IServiceCollection serviceCollection) + { + serviceCollection.AddSingleton(p => new KubeHttpClientSettingsProvider(logger: p.GetService>())); + serviceCollection.AddSingleton(); + } + } +} diff --git a/src/ApplicationInsights.Kubernetes/Interfaces/IK8sEnvironmentFactory.cs b/src/ApplicationInsights.Kubernetes/Interfaces/IK8sEnvironmentFactory.cs new file mode 100644 index 00000000..db25ead5 --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Interfaces/IK8sEnvironmentFactory.cs @@ -0,0 +1,10 @@ +using System; +using System.Threading.Tasks; + +namespace Microsoft.ApplicationInsights.Kubernetes +{ + internal interface IK8sEnvironmentFactory + { + Task CreateAsync(TimeSpan timeout); + } +} \ No newline at end of file diff --git a/src/ApplicationInsights.Kubernetes/K8sEnvironmentFactory.cs b/src/ApplicationInsights.Kubernetes/K8sEnvironmentFactory.cs index a7db2d76..d863bf02 100644 --- a/src/ApplicationInsights.Kubernetes/K8sEnvironmentFactory.cs +++ b/src/ApplicationInsights.Kubernetes/K8sEnvironmentFactory.cs @@ -10,7 +10,7 @@ namespace Microsoft.ApplicationInsights.Kubernetes { - internal class K8sEnvironmentFactory + internal class K8sEnvironmentFactory : IK8sEnvironmentFactory { private readonly ILogger _logger; private readonly IKubeHttpClientSettingsProvider _httpClientSettings; @@ -37,6 +37,7 @@ public async Task CreateAsync(TimeSpan timeout) { K8sEnvironment instance = null; ILogger logger = null; + try { using (IKubeHttpClient httpClient = _httpClientFactory.Create(_httpClientSettings)) diff --git a/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesModule.cs b/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesModule.cs index 31125330..007aaec9 100644 --- a/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesModule.cs +++ b/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesModule.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.ApplicationInsights.Kubernetes.Utilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -47,12 +48,15 @@ public static void Initialize(TelemetryConfiguration configuration, TimeSpan? ti /// /// /// - public static void EnableKubernetes(IServiceCollection serviceCollection, TelemetryConfiguration configuration, TimeSpan? timeout = null) + public static void EnableKubernetes(IServiceCollection serviceCollection, + TelemetryConfiguration configuration, + TimeSpan? timeout = null, + IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null) { // 2 minutes maximum to spin up the container. timeout = timeout ?? TimeSpan.FromMinutes(2); - serviceCollection = BuildK8sServiceCollection(serviceCollection); + serviceCollection = BuildK8sServiceCollection(serviceCollection, kubernetesServiceCollectionBuilder); IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); ILogger logger = serviceProvider.GetService>(); @@ -71,11 +75,13 @@ public static void EnableKubernetes(IServiceCollection serviceCollection, Teleme try { - K8sEnvironment k8sEnv = serviceProvider.GetRequiredService().CreateAsync(timeout.Value).ConfigureAwait(false).GetAwaiter().GetResult(); + K8sEnvironment k8sEnv = serviceProvider.GetRequiredService().CreateAsync(timeout.Value).ConfigureAwait(false).GetAwaiter().GetResult(); if (k8sEnv != null) { // Inject the telemetry initializer. - ITelemetryInitializer initializer = new KubernetesTelemetryInitializer(k8sEnv, serviceProvider.GetService>()); + ITelemetryInitializer initializer = new KubernetesTelemetryInitializer(k8sEnv, + SDKVersionUtils.Instance, + serviceProvider.GetService>()); configuration.TelemetryInitializers.Add(initializer); logger?.LogDebug("Application Insights Kubernetes injected the service successfully."); } @@ -91,23 +97,10 @@ public static void EnableKubernetes(IServiceCollection serviceCollection, Teleme } } - internal static IServiceCollection BuildK8sServiceCollection(IServiceCollection original) + internal static IServiceCollection BuildK8sServiceCollection(IServiceCollection services, IKubernetesServiceCollectionBuilder kubernetesServiceCollectionBuilder = null) { - if (Services == null || Services != original) - { - Services = original ?? new ServiceCollection(); - // According github code, adding logging will not overwrite existing logging classes - // https://github.com/aspnet/Logging/blob/c821494678a30c323174bea8056f43b93a3ca6f4/src/Microsoft.Extensions.Logging/LoggingServiceCollectionExtensions.cs - // Becuase it uses 'TryAdd()' extenion method on service collection. - Services.AddLogging(); - - Services.AddSingleton(p => new KubeHttpClientSettingsProvider(logger: p.GetService>())); - Services.AddSingleton(); - Services.AddSingleton(); - - Services.AddSingleton(); - } - + kubernetesServiceCollectionBuilder = kubernetesServiceCollectionBuilder ?? new KubernetesServiceCollectionBuilder(); + Services = kubernetesServiceCollectionBuilder.InjectServices(services); return Services; } diff --git a/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesTelemetryInitializer.cs b/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesTelemetryInitializer.cs index 5488515d..114a4173 100644 --- a/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesTelemetryInitializer.cs +++ b/src/ApplicationInsights.Kubernetes/TelemetryInitializers/KubernetesTelemetryInitializer.cs @@ -1,6 +1,8 @@ using System; using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.ApplicationInsights.Extensibility.Implementation; +using Microsoft.ApplicationInsights.Kubernetes.Utilities; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -29,14 +31,17 @@ internal class KubernetesTelemetryInitializer : ITelemetryInitializer public const string CPU = "CPU"; public const string Memory = "Memory"; - private ILogger _logger; + private readonly ILogger _logger; + private readonly SDKVersionUtils _sdkVersionUtils; internal IK8sEnvironment K8sEnvironment { get; private set; } public KubernetesTelemetryInitializer( IK8sEnvironment k8sEnv, + SDKVersionUtils sdkVersionUtils, ILogger logger) { _logger = logger; + _sdkVersionUtils = Arguments.IsNotNull(sdkVersionUtils, nameof(sdkVersionUtils)); this.K8sEnvironment = Arguments.IsNotNull(k8sEnv, nameof(k8sEnv)); } @@ -59,13 +64,13 @@ public void Initialize(ITelemetry telemetry) #else SetCustomDimensions(telemetry); #endif - _logger.LogTrace(JsonConvert.SerializeObject(telemetry)); } else { _logger.LogError("K8s Environemnt is null."); } + telemetry.Context.GetInternalContext().SdkVersion = _sdkVersionUtils.CurrentSDKVersion; } private void SetCustomDimensions(ITelemetry telemetry) diff --git a/src/ApplicationInsights.Kubernetes/Utilities/SDKVersionUtils.cs b/src/ApplicationInsights.Kubernetes/Utilities/SDKVersionUtils.cs new file mode 100644 index 00000000..0708ce15 --- /dev/null +++ b/src/ApplicationInsights.Kubernetes/Utilities/SDKVersionUtils.cs @@ -0,0 +1,38 @@ +using System; +using System.Reflection; + +namespace Microsoft.ApplicationInsights.Kubernetes.Utilities +{ + internal sealed class SDKVersionUtils + { + #region Signleton + private SDKVersionUtils() { } + private static readonly SDKVersionUtils _instance = new SDKVersionUtils(); + public static SDKVersionUtils Instance => _instance; + #endregion + + public string CurrentSDKVersion + { + get + { + if (string.IsNullOrEmpty(_sdkVersion)) + { + _sdkVersion = $"{SdkName}:{GetSDKVersion()}"; + } + return _sdkVersion; + } + } + + #region private + private static string GetSDKVersion() + { + Assembly assembly = typeof(SDKVersionUtils).GetTypeInfo().Assembly; + Version version = assembly.GetName().Version; + return version.ToString(); + } + + private const string SdkName = "ai-k8s"; + private string _sdkVersion; + #endregion + } +} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6e05e531..5acb2839 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -19,6 +19,7 @@ $([System.DateTime]::Now.ToString(yyyyMMddHHmm)) 1.0.0-private-$(VersionSuffix) + 1.0.0.0 Microsoft Microsoft True diff --git a/tests/UnitTests/KubernetesModuleTests.cs b/tests/UnitTests/KubernetesModuleTests.cs index 117ac860..d6fc9c48 100644 --- a/tests/UnitTests/KubernetesModuleTests.cs +++ b/tests/UnitTests/KubernetesModuleTests.cs @@ -33,7 +33,7 @@ public void ServiceInjected() serviceProvider.GetRequiredService(); serviceProvider.GetRequiredService(); serviceProvider.GetRequiredService(); - serviceProvider.GetRequiredService(); + serviceProvider.GetRequiredService(); } } } diff --git a/tests/UnitTests/KubernetesTelemtryInitializerTests.cs b/tests/UnitTests/KubernetesTelemtryInitializerTests.cs index 23ab819a..88807c7b 100644 --- a/tests/UnitTests/KubernetesTelemtryInitializerTests.cs +++ b/tests/UnitTests/KubernetesTelemtryInitializerTests.cs @@ -1,6 +1,7 @@ using System; using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.DataContracts; +using Microsoft.ApplicationInsights.Kubernetes.Utilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; @@ -15,7 +16,7 @@ public void ConstructorSetsNullGetsNull() { Exception ex = Assert.Throws(() => { - KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(null, GetLogger()); + KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(null, SDKVersionUtils.Instance, GetLogger()); }); Assert.Equal("Value cannot be null.\r\nParameter name: k8sEnv", ex.Message); @@ -25,7 +26,7 @@ public void ConstructorSetsNullGetsNull() public void ConstructorSetK8sEnvironment() { var envMock = new Mock(); - KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, GetLogger()); + KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, SDKVersionUtils.Instance, GetLogger()); Assert.NotNull(target.K8sEnvironment); Assert.Equal(envMock.Object, target.K8sEnvironment); @@ -36,7 +37,7 @@ public void InitializeSetsRoleName() { var envMock = new Mock(); envMock.Setup(env => env.ContainerName).Returns("Hello RoleName"); - KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, GetLogger()); + KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, SDKVersionUtils.Instance, GetLogger()); ITelemetry telemetry = new TraceTelemetry(); target.Initialize(telemetry); @@ -48,7 +49,7 @@ public void InitializeShouldNotOverwriteExistingRoleName() { var envMock = new Mock(); envMock.Setup(env => env.ContainerName).Returns("New RoleName"); - KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, GetLogger()); + KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, SDKVersionUtils.Instance, GetLogger()); ITelemetry telemetry = new TraceTelemetry(); telemetry.Context.Cloud.RoleName = "Existing RoleName"; target.Initialize(telemetry); @@ -74,7 +75,7 @@ public void InitializeSetsCustomDimensions() envMock.Setup(env => env.NodeUid).Returns("Nid"); envMock.Setup(env => env.NodeName).Returns("NName"); - KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, GetLogger()); + KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, SDKVersionUtils.Instance, GetLogger()); ITelemetry telemetry = new TraceTelemetry(); target.Initialize(telemetry); @@ -106,7 +107,7 @@ public void InitializeWillNotOverwriteExistingCustomDimension() envMock.Setup(env => env.ContainerID).Returns("Cid"); - KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, GetLogger()); + KubernetesTelemetryInitializer target = new KubernetesTelemetryInitializer(envMock.Object, SDKVersionUtils.Instance, GetLogger()); ITelemetry telemetry = new TraceTelemetry(); telemetry.Context.Properties["K8s.Container.ID"] = "Existing Cid"; target.Initialize(telemetry);