From 64b24aede99556372e5c8a800b16b63f0d4698fd Mon Sep 17 00:00:00 2001 From: James Thompson Date: Sat, 8 Jun 2024 13:47:30 +1000 Subject: [PATCH] #1312 Add in activity creation --- .../ConfigServerConfigurationProvider.cs | 218 ++++++----- .../KubernetesConfigMapProvider.cs | 36 +- .../KubernetesBase/KubernetesProviderBase.cs | 17 +- .../Consul/Discovery/ConsulDiscoveryClient.cs | 19 +- src/Discovery/src/Eureka/DiscoveryClient.cs | 354 ++++++++++-------- .../Discovery/KubernetesDiscoveryClient.cs | 75 ++-- 6 files changed, 396 insertions(+), 323 deletions(-) diff --git a/src/Configuration/src/ConfigServerBase/ConfigServerConfigurationProvider.cs b/src/Configuration/src/ConfigServerBase/ConfigServerConfigurationProvider.cs index 4e7f3b8a31..7abef7d43e 100644 --- a/src/Configuration/src/ConfigServerBase/ConfigServerConfigurationProvider.cs +++ b/src/Configuration/src/ConfigServerBase/ConfigServerConfigurationProvider.cs @@ -11,6 +11,7 @@ using Steeltoe.Extensions.Configuration.Placeholder; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Net; @@ -60,6 +61,8 @@ public class ConfigServerConfigurationProvider : ConfigurationProvider, IConfigu private static readonly char[] COMMA_DELIMIT = new char[] { ',' }; private static readonly string[] EMPTY_LABELS = new string[] { string.Empty }; + private ActivitySource _configActivity = new ActivitySource("Steeltoe.Extensions.Configuration.ConfigServer.ConfigServerConfigurationProvider"); + /// /// Initializes a new instance of the class with default /// configuration settings. @@ -182,13 +185,16 @@ private void OnSettingsChanged() /// private void DoPolledLoad() { - try - { - DoLoad(); - } - catch (Exception e) + using (var activity = _configActivity.StartActivity(nameof(DoPolledLoad))) { - _logger.LogWarning(e, "Could not reload configuration during polling"); + try + { + DoLoad(); + } + catch (Exception e) + { + _logger.LogWarning(e, "Could not reload configuration during polling"); + } } } @@ -309,77 +315,80 @@ internal ConfigEnvironment DoLoad(bool updateDictionary = true) { foreach (var label in GetLabels()) { - Task task = null; - - if (uris.Length > 1) + using (var activity = _configActivity.StartActivity(nameof(DoLoad))) { - _logger.LogInformation("Multiple Config Server Uris listed."); + Task task = null; - // Invoke config servers - task = RemoteLoadAsync(uris, label); - } - else - { - // Single, server make Config Server URI from settings + if (uris.Length > 1) + { + _logger.LogInformation("Multiple Config Server Uris listed."); + + // Invoke config servers + task = RemoteLoadAsync(uris, label); + } + else + { + // Single, server make Config Server URI from settings #pragma warning disable CS0618 // Type or member is obsolete - var path = GetConfigServerUri(label); + var path = GetConfigServerUri(label); - // Invoke config server - task = RemoteLoadAsync(path); + // Invoke config server + task = RemoteLoadAsync(path); #pragma warning restore CS0618 // Type or member is obsolete - } + } - // Wait for results from server - var env = task.GetAwaiter().GetResult(); + // Wait for results from server + var env = task.GetAwaiter().GetResult(); - // Update config Data dictionary with any results - if (env != null) - { - _logger.LogInformation( - "Located environment name: {name}, profiles: {profiles}, labels: {label}, version: {version}, state: {state}", env.Name, env.Profiles, env.Label, env.Version, env.State); - if (updateDictionary) + // Update config Data dictionary with any results + if (env != null) { - var data = new Dictionary(StringComparer.OrdinalIgnoreCase); - - if (!string.IsNullOrEmpty(env.State)) + _logger.LogInformation( + "Located environment name: {name}, profiles: {profiles}, labels: {label}, version: {version}, state: {state}", env.Name, env.Profiles, env.Label, env.Version, env.State); + if (updateDictionary) { - data["spring:cloud:config:client:state"] = env.State; - } + var data = new Dictionary(StringComparer.OrdinalIgnoreCase); - if (!string.IsNullOrEmpty(env.Version)) - { - data["spring:cloud:config:client:version"] = env.Version; - } + if (!string.IsNullOrEmpty(env.State)) + { + data["spring:cloud:config:client:state"] = env.State; + } - var sources = env.PropertySources; - if (sources != null) - { - var index = sources.Count - 1; - for (; index >= 0; index--) + if (!string.IsNullOrEmpty(env.Version)) { - AddPropertySource(sources[index], data); + data["spring:cloud:config:client:version"] = env.Version; } - } - // Adds client settings (e.g spring:cloud:config:uri, etc) back to the (new) Data dictionary - AddConfigServerClientSettings(data); + var sources = env.PropertySources; + if (sources != null) + { + var index = sources.Count - 1; + for (; index >= 0; index--) + { + AddPropertySource(sources[index], data); + } + } - static bool AreEqual(IDictionary dict1, IDictionary dict2) - { - IEqualityComparer valueComparer = EqualityComparer.Default; + // Adds client settings (e.g spring:cloud:config:uri, etc) back to the (new) Data dictionary + AddConfigServerClientSettings(data); - return dict1.Count == dict2.Count && - dict1.Keys.All(key => dict2.ContainsKey(key) && valueComparer.Equals(dict1[key], dict2[key])); - } + static bool AreEqual(IDictionary dict1, IDictionary dict2) + { + IEqualityComparer valueComparer = EqualityComparer.Default; - if (!AreEqual(Data, data)) - { - Data = data; - OnReload(); + return dict1.Count == dict2.Count && + dict1.Keys.All(key => dict2.ContainsKey(key) && valueComparer.Equals(dict1[key], dict2[key])); + } + + if (!AreEqual(Data, data)) + { + Data = data; + OnReload(); + } } - } - return env; + return env; + } } } } @@ -585,65 +594,68 @@ protected internal async Task RemoteLoadAsync(string[] reques Exception error = null; foreach (var requestUri in requestUris) { - error = null; - - // Get a config server uri and username passwords to use - var trimUri = requestUri.Trim(); - var serverUri = _settings.GetRawUri(trimUri); - var username = _settings.GetUserName(trimUri); - var password = _settings.GetPassword(trimUri); + using (var activity = _configActivity.StartActivity(nameof(RemoteLoadAsync))) + { + error = null; - // Make Config Server URI from settings - var path = GetConfigServerUri(serverUri, label); + // Get a config server uri and username passwords to use + var trimUri = requestUri.Trim(); + var serverUri = _settings.GetRawUri(trimUri); + var username = _settings.GetUserName(trimUri); + var password = _settings.GetPassword(trimUri); - // Get the request message - var request = GetRequestMessage(path, username, password); + // Make Config Server URI from settings + var path = GetConfigServerUri(serverUri, label); - // If certificate validation is disabled, inject a callback to handle properly - var prevProtocols = (SecurityProtocolType)0; - HttpClientHelper.ConfigureCertificateValidation(_settings.ValidateCertificates, out prevProtocols, out var prevValidator); + // Get the request message + var request = GetRequestMessage(path, username, password); - // Invoke config server - try - { - using var response = await _httpClient.SendAsync(request).ConfigureAwait(false); + // If certificate validation is disabled, inject a callback to handle properly + var prevProtocols = (SecurityProtocolType)0; + HttpClientHelper.ConfigureCertificateValidation(_settings.ValidateCertificates, out prevProtocols, out var prevValidator); - _logger.LogInformation("Config Server returned status: {statusCode} invoking path: {requestUri}", response.StatusCode, WebUtility.UrlEncode(requestUri)); - if (response.StatusCode != HttpStatusCode.OK) + // Invoke config server + try { - if (response.StatusCode == HttpStatusCode.NotFound) - { - return null; - } + using var response = await _httpClient.SendAsync(request).ConfigureAwait(false); - // Throw if status >= 400 - if (response.StatusCode >= HttpStatusCode.BadRequest) + _logger.LogInformation("Config Server returned status: {statusCode} invoking path: {requestUri}", response.StatusCode, WebUtility.UrlEncode(requestUri)); + if (response.StatusCode != HttpStatusCode.OK) { - // HttpClientErrorException - throw new HttpRequestException($"Config Server returned status: {response.StatusCode} invoking path: {WebUtility.UrlEncode(requestUri)}"); + if (response.StatusCode == HttpStatusCode.NotFound) + { + return null; + } + + // Throw if status >= 400 + if (response.StatusCode >= HttpStatusCode.BadRequest) + { + // HttpClientErrorException + throw new HttpRequestException($"Config Server returned status: {response.StatusCode} invoking path: {WebUtility.UrlEncode(requestUri)}"); + } + else + { + return null; + } } - else + + return await response.Content.ReadFromJsonAsync(SerializerOptions).ConfigureAwait(false); + } + catch (Exception e) + { + error = e; + _logger.LogError(e, "Config Server exception, path: {requestUri}", WebUtility.UrlEncode(requestUri)); + if (IsContinueExceptionType(e)) { - return null; + continue; } - } - return await response.Content.ReadFromJsonAsync(SerializerOptions).ConfigureAwait(false); - } - catch (Exception e) - { - error = e; - _logger.LogError(e, "Config Server exception, path: {requestUri}", WebUtility.UrlEncode(requestUri)); - if (IsContinueExceptionType(e)) + throw; + } + finally { - continue; + HttpClientHelper.RestoreCertificateValidation(_settings.ValidateCertificates, prevProtocols, prevValidator); } - - throw; - } - finally - { - HttpClientHelper.RestoreCertificateValidation(_settings.ValidateCertificates, prevProtocols, prevValidator); } } diff --git a/src/Configuration/src/KubernetesBase/KubernetesConfigMapProvider.cs b/src/Configuration/src/KubernetesBase/KubernetesConfigMapProvider.cs index dfa007340e..d7dbc5ac6f 100644 --- a/src/Configuration/src/KubernetesBase/KubernetesConfigMapProvider.cs +++ b/src/Configuration/src/KubernetesBase/KubernetesConfigMapProvider.cs @@ -33,25 +33,28 @@ internal KubernetesConfigMapProvider(IKubernetes kubernetes, KubernetesConfigSou public override void Load() { - try + using (var activity = _kubernetesActivity.StartActivity(nameof(Load))) { - var configMapResponse = K8sClient.ReadNamespacedConfigMapWithHttpMessagesAsync(Settings.Name, Settings.Namespace).GetAwaiter().GetResult(); - ProcessData(configMapResponse.Body); - EnableReloading(); - } - catch (HttpOperationException e) - { - if (e.Response.StatusCode == HttpStatusCode.Forbidden) - { - Logger?.LogCritical(e, "Failed to retrieve config map '{configmapName}' in namespace '{configmapNamespace}'. Confirm that your service account has the necessary permissions", Settings.Name, Settings.Namespace); - } - else if (e.Response.StatusCode == HttpStatusCode.NotFound) + try { + var configMapResponse = K8sClient.ReadNamespacedConfigMapWithHttpMessagesAsync(Settings.Name, Settings.Namespace).GetAwaiter().GetResult(); + ProcessData(configMapResponse.Body); EnableReloading(); - return; } + catch (HttpOperationException e) + { + if (e.Response.StatusCode == HttpStatusCode.Forbidden) + { + Logger?.LogCritical(e, "Failed to retrieve config map '{configmapName}' in namespace '{configmapNamespace}'. Confirm that your service account has the necessary permissions", Settings.Name, Settings.Namespace); + } + else if (e.Response.StatusCode == HttpStatusCode.NotFound) + { + EnableReloading(); + return; + } - throw; + throw; + } } } @@ -89,7 +92,9 @@ private void EnableReloading() switch (Settings.ReloadSettings.Mode) { case ReloadMethods.Event: - ConfigMapWatcher = K8sClient.WatchNamespacedConfigMapAsync( + using (var activity = _kubernetesActivity.StartActivity(nameof(EnableReloading))) + { + ConfigMapWatcher = K8sClient.WatchNamespacedConfigMapAsync( Settings.Name, Settings.Namespace, onEvent: (eventType, item) => @@ -112,6 +117,7 @@ private void EnableReloading() Logger?.LogCritical(exception, "ConfigMap watcher on {namespace}.{name} encountered an error!", Settings.Namespace, Settings.Name); }, onClosed: () => { Logger?.LogInformation("ConfigMap watcher on {namespace}.{name} connection has closed", Settings.Namespace, Settings.Name); }).GetAwaiter().GetResult(); + } break; case ReloadMethods.Polling: StartPolling(Settings.ReloadSettings.Period); diff --git a/src/Configuration/src/KubernetesBase/KubernetesProviderBase.cs b/src/Configuration/src/KubernetesBase/KubernetesProviderBase.cs index b8aba05393..47df9fed7a 100644 --- a/src/Configuration/src/KubernetesBase/KubernetesProviderBase.cs +++ b/src/Configuration/src/KubernetesBase/KubernetesProviderBase.cs @@ -24,6 +24,8 @@ internal class KubernetesProviderBase : ConfigurationProvider protected ILogger Logger => Settings.LoggerFactory?.CreateLogger(this.GetType()); + private ActivitySource _kubernetesActivity = new ActivitySource("Steeltoe.Extensions.Configuration.Kubernetes.KubernetesProviderBase"); + internal KubernetesProviderBase(IKubernetes kubernetes, KubernetesConfigSourceSettings settings, CancellationToken token = default) { if (kubernetes is null) @@ -58,13 +60,16 @@ protected void StartPolling(int interval) Polling = true; while (Polling) { - Thread.Sleep(TimeSpan.FromSeconds(interval)); - Logger?.LogTrace("Interval completed for {namespace}.{name}, beginning reload", Settings.Namespace, Settings.Name); - Load(); - if (CancellationToken.IsCancellationRequested) + using (var activity = _kubernetesActivity.StartActivity(nameof(StartPolling))) { - Logger?.LogTrace("Cancellation requested for {namespace}.{name}, shutting down", Settings.Namespace, Settings.Name); - break; + Thread.Sleep(TimeSpan.FromSeconds(interval)); + Logger?.LogTrace("Interval completed for {namespace}.{name}, beginning reload", Settings.Namespace, Settings.Name); + Load(); + if (CancellationToken.IsCancellationRequested) + { + Logger?.LogTrace("Cancellation requested for {namespace}.{name}, shutting down", Settings.Namespace, Settings.Name); + break; + } } } }, diff --git a/src/Discovery/src/Consul/Discovery/ConsulDiscoveryClient.cs b/src/Discovery/src/Consul/Discovery/ConsulDiscoveryClient.cs index 964434dbc7..674148a0f6 100644 --- a/src/Discovery/src/Consul/Discovery/ConsulDiscoveryClient.cs +++ b/src/Discovery/src/Consul/Discovery/ConsulDiscoveryClient.cs @@ -9,6 +9,7 @@ using Steeltoe.Discovery.Consul.Registry; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -25,6 +26,7 @@ public class ConsulDiscoveryClient : IConsulDiscoveryClient private readonly ConsulDiscoveryOptions _options; private readonly IServiceInstance _thisServiceInstance; private readonly IConsulServiceRegistrar _registrar; + private ActivitySource _consulActivity = new ActivitySource("Steeltoe.Discovery.Consul.Discovery.ConsulDiscoveryClient"); internal ConsulDiscoveryOptions Options { @@ -131,7 +133,10 @@ public IList Services /// the list of service instances public IList GetInstances(string serviceId, QueryOptions queryOptions = null) { - return GetInstancesAsync(serviceId, queryOptions).GetAwaiter().GetResult(); + using (var activity = _consulActivity.StartActivity(nameof(GetInstances))) + { + return GetInstancesAsync(serviceId, queryOptions).GetAwaiter().GetResult(); + } } /// @@ -141,7 +146,10 @@ public IList GetInstances(string serviceId, QueryOptions query /// the list of service instances public IList GetAllInstances(QueryOptions queryOptions = null) { - return GetAllInstancesAsync().GetAwaiter().GetResult(); + using (var activity = _consulActivity.StartActivity(nameof(GetAllInstances))) + { + return GetAllInstancesAsync().GetAwaiter().GetResult(); + } async Task> GetAllInstancesAsync() { @@ -164,8 +172,11 @@ async Task> GetAllInstancesAsync() /// the list of services public IList GetServices(QueryOptions queryOptions = null) { - queryOptions ??= QueryOptions.Default; - return GetServicesAsync(queryOptions).GetAwaiter().GetResult(); + using (var activity = _consulActivity.StartActivity(nameof(GetServices))) + { + queryOptions ??= QueryOptions.Default; + return GetServicesAsync(queryOptions).GetAwaiter().GetResult(); + } } internal async Task> GetInstancesAsync(string serviceId, QueryOptions queryOptions) diff --git a/src/Discovery/src/Eureka/DiscoveryClient.cs b/src/Discovery/src/Eureka/DiscoveryClient.cs index c1c853a592..01376747e5 100644 --- a/src/Discovery/src/Eureka/DiscoveryClient.cs +++ b/src/Discovery/src/Eureka/DiscoveryClient.cs @@ -10,6 +10,7 @@ using Steeltoe.Discovery.Eureka.Transport; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Net; using System.Threading; using T = System.Threading.Tasks; @@ -57,6 +58,8 @@ public Applications Applications public IHealthCheckHandler HealthCheckHandler { get; set; } + private ActivitySource _eurekaActivity = new ActivitySource("Steeltoe.Discovery.Eureka.DiscoveryClient"); + public DiscoveryClient(IEurekaClientConfig clientConfig, IEurekaHttpClient httpClient = null, ILoggerFactory logFactory = null) : this(ApplicationInfoManager.Instance, logFactory) { @@ -100,157 +103,172 @@ public Application GetApplication(string appName) public IList GetInstanceById(string id) { - if (string.IsNullOrEmpty(id)) + using (var activity = _eurekaActivity.StartActivity(nameof(GetInstanceById))) { - throw new ArgumentException(nameof(id)); - } + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentException(nameof(id)); + } - var results = new List(); + var results = new List(); - var apps = Applications; - if (apps == null) - { - return results; - } + var apps = Applications; + if (apps == null) + { + return results; + } - var regApps = apps.GetRegisteredApplications(); - foreach (var app in regApps) - { - var instance = app.GetInstance(id); - if (instance != null) + var regApps = apps.GetRegisteredApplications(); + foreach (var app in regApps) { - results.Add(instance); + var instance = app.GetInstance(id); + if (instance != null) + { + results.Add(instance); + } } - } - return results; + return results; + } } public IList GetInstancesByVipAddress(string vipAddress, bool secure) { - if (string.IsNullOrEmpty(vipAddress)) + using (var activity = _eurekaActivity.StartActivity(nameof(GetInstancesByVipAddressAndAppName))) { - throw new ArgumentException(nameof(vipAddress)); - } + if (string.IsNullOrEmpty(vipAddress)) + { + throw new ArgumentException(nameof(vipAddress)); + } - var results = new List(); + var results = new List(); - var apps = Applications; - if (apps == null) - { - return results; - } + var apps = Applications; + if (apps == null) + { + return results; + } - if (secure) - { - return apps.GetInstancesBySecureVirtualHostName(vipAddress); - } - else - { - return apps.GetInstancesByVirtualHostName(vipAddress); + if (secure) + { + return apps.GetInstancesBySecureVirtualHostName(vipAddress); + } + else + { + return apps.GetInstancesByVirtualHostName(vipAddress); + } } } public IList GetInstancesByVipAddressAndAppName(string vipAddress, string appName, bool secure) { - IList result = new List(); - if (vipAddress == null && appName == null) - { - throw new ArgumentNullException("vipAddress and appName both null"); - } - else if (vipAddress != null && appName == null) + using (var activity = _eurekaActivity.StartActivity(nameof(GetInstancesByVipAddressAndAppName))) { - return GetInstancesByVipAddress(vipAddress, secure); - } - else if (vipAddress == null) - { - // note: if appName were null, we would not get into this block - var application = GetApplication(appName); - if (application != null) + IList result = new List(); + if (vipAddress == null && appName == null) { - result = application.Instances; + throw new ArgumentNullException("vipAddress and appName both null"); } - - return result; - } - - foreach (var app in _localRegionApps.GetRegisteredApplications()) - { - foreach (var instance in app.Instances) + else if (vipAddress != null && appName == null) { - string instanceVipAddress; - if (secure) - { - instanceVipAddress = instance.SecureVipAddress; - } - else + return GetInstancesByVipAddress(vipAddress, secure); + } + else if (vipAddress == null) + { + // note: if appName were null, we would not get into this block + var application = GetApplication(appName); + if (application != null) { - instanceVipAddress = instance.VipAddress; + result = application.Instances; } - if (vipAddress.Equals(instanceVipAddress, StringComparison.OrdinalIgnoreCase) && - appName.Equals(instance.AppName, StringComparison.OrdinalIgnoreCase)) + return result; + } + + foreach (var app in _localRegionApps.GetRegisteredApplications()) + { + foreach (var instance in app.Instances) { - result.Add(instance); + string instanceVipAddress; + if (secure) + { + instanceVipAddress = instance.SecureVipAddress; + } + else + { + instanceVipAddress = instance.VipAddress; + } + + if (vipAddress.Equals(instanceVipAddress, StringComparison.OrdinalIgnoreCase) && + appName.Equals(instance.AppName, StringComparison.OrdinalIgnoreCase)) + { + result.Add(instance); + } } } - } - return result; + return result; + } } public InstanceInfo GetNextServerFromEureka(string vipAddress, bool secure) { - if (string.IsNullOrEmpty(vipAddress)) + using (var activity = _eurekaActivity.StartActivity(nameof(GetNextServerFromEureka))) { - throw new ArgumentException(nameof(vipAddress)); - } + if (string.IsNullOrEmpty(vipAddress)) + { + throw new ArgumentException(nameof(vipAddress)); + } - var results = GetInstancesByVipAddress(vipAddress, secure); - if (results.Count == 0) - { - return null; - } + var results = GetInstancesByVipAddress(vipAddress, secure); + if (results.Count == 0) + { + return null; + } - var index = _random.Next() % results.Count; - return results[index]; + var index = _random.Next() % results.Count; + return results[index]; + } } public virtual async T.Task ShutdownAsync() { - var shutdown = Interlocked.Exchange(ref _shutdown, 1); - if (shutdown > 0) + using (var activity = _eurekaActivity.StartActivity(nameof(ShutdownAsync))) { - return; - } + var shutdown = Interlocked.Exchange(ref _shutdown, 1); + if (shutdown > 0) + { + return; + } - if (_cacheRefreshTimer != null) - { - _cacheRefreshTimer.Dispose(); - _cacheRefreshTimer = null; - } + if (_cacheRefreshTimer != null) + { + _cacheRefreshTimer.Dispose(); + _cacheRefreshTimer = null; + } - if (_heartBeatTimer != null) - { - _heartBeatTimer.Dispose(); - _heartBeatTimer = null; - } + if (_heartBeatTimer != null) + { + _heartBeatTimer.Dispose(); + _heartBeatTimer = null; + } - if (ClientConfig.ShouldOnDemandUpdateStatusChange) - { - _appInfoManager.StatusChangedEvent -= Instance_StatusChangedEvent; - } + if (ClientConfig.ShouldOnDemandUpdateStatusChange) + { + _appInfoManager.StatusChangedEvent -= Instance_StatusChangedEvent; + } - if (ClientConfig.ShouldRegisterWithEureka) - { - var info = _appInfoManager.InstanceInfo; - if (info != null) + if (ClientConfig.ShouldRegisterWithEureka) { - info.Status = InstanceStatus.DOWN; - var result = await UnregisterAsync().ConfigureAwait(false); - if (!result) + var info = _appInfoManager.InstanceInfo; + if (info != null) { - _logger.LogWarning("Unregister failed during Shutdown"); + info.Status = InstanceStatus.DOWN; + var result = await UnregisterAsync().ConfigureAwait(false); + if (!result) + { + _logger.LogWarning("Unregister failed during Shutdown"); + } } } } @@ -264,30 +282,33 @@ public virtual async T.Task ShutdownAsync() internal async void Instance_StatusChangedEvent(object sender, StatusChangedArgs args) { - var info = _appInfoManager.InstanceInfo; - if (info != null) + using (var activity = _eurekaActivity.StartActivity(nameof(Instance_StatusChangedEvent))) { - _logger.LogDebug( - "Instance_StatusChangedEvent {previousStatus}, {currentStatus}, {instanceId}, {dirty}", - args.Previous, - args.Current, - args.InstanceId, - info.IsDirty); - - if (info.IsDirty) + var info = _appInfoManager.InstanceInfo; + if (info != null) { - try + _logger.LogDebug( + "Instance_StatusChangedEvent {previousStatus}, {currentStatus}, {instanceId}, {dirty}", + args.Previous, + args.Current, + args.InstanceId, + info.IsDirty); + + if (info.IsDirty) { - var result = await RegisterAsync().ConfigureAwait(false); - if (result) + try { - info.IsDirty = false; - _logger.LogInformation("Instance_StatusChangedEvent RegisterAsync Succeed"); + var result = await RegisterAsync().ConfigureAwait(false); + if (result) + { + info.IsDirty = false; + _logger.LogInformation("Instance_StatusChangedEvent RegisterAsync Succeed"); + } + } + catch (Exception e) + { + _logger.LogError(e, "Instance_StatusChangedEvent RegisterAsync Failed"); } - } - catch (Exception e) - { - _logger.LogError(e, "Instance_StatusChangedEvent RegisterAsync Failed"); } } } @@ -571,43 +592,46 @@ protected internal async T.Task RegisterDirtyInstanceInfo(InstanceInfo ins protected async T.Task InitializeAsync() { - Interlocked.Exchange(ref _logger, _startupLogger); - _localRegionApps = new Applications + using (var activity = _eurekaActivity.StartActivity(nameof(InitializeAsync))) { - ReturnUpInstancesOnly = ClientConfig.ShouldFilterOnlyUpInstances - }; + Interlocked.Exchange(ref _logger, _startupLogger); + _localRegionApps = new Applications + { + ReturnUpInstancesOnly = ClientConfig.ShouldFilterOnlyUpInstances + }; - // TODO: add Enabled to IEurekaClientConfig - var eurekaClientConfig = ClientConfig as EurekaClientConfig; - if (!eurekaClientConfig.Enabled || (!ClientConfig.ShouldRegisterWithEureka && !ClientConfig.ShouldFetchRegistry)) - { - return; - } + // TODO: add Enabled to IEurekaClientConfig + var eurekaClientConfig = ClientConfig as EurekaClientConfig; + if (!eurekaClientConfig.Enabled || (!ClientConfig.ShouldRegisterWithEureka && !ClientConfig.ShouldFetchRegistry)) + { + return; + } - if (ClientConfig.ShouldRegisterWithEureka && _appInfoManager.InstanceInfo != null) - { - if (!await RegisterAsync().ConfigureAwait(false)) + if (ClientConfig.ShouldRegisterWithEureka && _appInfoManager.InstanceInfo != null) { - _logger.LogInformation("Initial Registration failed."); + if (!await RegisterAsync().ConfigureAwait(false)) + { + _logger.LogInformation("Initial Registration failed."); + } + + _logger.LogInformation("Starting HeartBeat"); + var intervalInMilli = _appInfoManager.InstanceInfo.LeaseInfo.RenewalIntervalInSecs * 1000; + _heartBeatTimer = StartTimer("HeartBeat", intervalInMilli, HeartBeatTaskAsync); + if (ClientConfig.ShouldOnDemandUpdateStatusChange) + { + _appInfoManager.StatusChangedEvent += Instance_StatusChangedEvent; + } } - _logger.LogInformation("Starting HeartBeat"); - var intervalInMilli = _appInfoManager.InstanceInfo.LeaseInfo.RenewalIntervalInSecs * 1000; - _heartBeatTimer = StartTimer("HeartBeat", intervalInMilli, HeartBeatTaskAsync); - if (ClientConfig.ShouldOnDemandUpdateStatusChange) + if (ClientConfig.ShouldFetchRegistry) { - _appInfoManager.StatusChangedEvent += Instance_StatusChangedEvent; + await FetchRegistryAsync(true).ConfigureAwait(false); + var intervalInMilli = ClientConfig.RegistryFetchIntervalSeconds * 1000; + _cacheRefreshTimer = StartTimer("Query", intervalInMilli, CacheRefreshTaskAsync); } - } - if (ClientConfig.ShouldFetchRegistry) - { - await FetchRegistryAsync(true).ConfigureAwait(false); - var intervalInMilli = ClientConfig.RegistryFetchIntervalSeconds * 1000; - _cacheRefreshTimer = StartTimer("Query", intervalInMilli, CacheRefreshTaskAsync); + Interlocked.Exchange(ref _logger, _regularLogger); } - - Interlocked.Exchange(ref _logger, _regularLogger); } private bool IsHealthCheckHandlerEnabled() @@ -646,29 +670,35 @@ private void UpdateInstanceRemoteStatus() #pragma warning disable S3168 // "async" methods should not return "void" private async void HeartBeatTaskAsync() { - if (_shutdown > 0) + using (var activity = _eurekaActivity.StartActivity(nameof(HeartBeatTaskAsync))) { - return; - } + if (_shutdown > 0) + { + return; + } - var result = await RenewAsync().ConfigureAwait(false); - if (!result) - { - _logger.LogError("HeartBeat failed"); + var result = await RenewAsync().ConfigureAwait(false); + if (!result) + { + _logger.LogError("HeartBeat failed"); + } } } private async void CacheRefreshTaskAsync() { - if (_shutdown > 0) + using (var activity = _eurekaActivity.StartActivity(nameof(CacheRefreshTaskAsync))) { - return; - } + if (_shutdown > 0) + { + return; + } - var result = await FetchRegistryAsync(false).ConfigureAwait(false); - if (!result) - { - _logger.LogError("CacheRefresh failed"); + var result = await FetchRegistryAsync(false).ConfigureAwait(false); + if (!result) + { + _logger.LogError("CacheRefresh failed"); + } } } #pragma warning restore S3168 // "async" methods should not return "void" diff --git a/src/Discovery/src/Kubernetes/Discovery/KubernetesDiscoveryClient.cs b/src/Discovery/src/Kubernetes/Discovery/KubernetesDiscoveryClient.cs index ee19151727..59f797dfaa 100644 --- a/src/Discovery/src/Kubernetes/Discovery/KubernetesDiscoveryClient.cs +++ b/src/Discovery/src/Kubernetes/Discovery/KubernetesDiscoveryClient.cs @@ -9,6 +9,7 @@ using Steeltoe.Common.Discovery; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -35,6 +36,8 @@ public static void EnsureAssemblyIsLoaded() public IKubernetes KubernetesClient { get; set; } + private ActivitySource _kubernetesActivity = new ActivitySource("Steeltoe.Discovery.Kubernetes.Discovery.KubernetesDiscoveryClient"); + public KubernetesDiscoveryClient( DefaultIsServicePortSecureResolver isServicePortSecureResolver, IKubernetes kubernetesClient, @@ -49,57 +52,63 @@ public KubernetesDiscoveryClient( public IList GetServices(IDictionary labels) { - if (!_discoveryOptions.CurrentValue.Enabled) - { - return Array.Empty(); - } - else + using (var activity = _kubernetesActivity.StartActivity(nameof(GetServices))) { - var labelSelectorValue = - labels != null ? - string.Join(",", labels.Keys.Select(k => k + "=" + labels[k])) : - null; - if (_discoveryOptions.CurrentValue.AllNamespaces) + if (!_discoveryOptions.CurrentValue.Enabled) { - return KubernetesClient.ListServiceForAllNamespaces( - labelSelector: labelSelectorValue).Items - .Select(service => service.Metadata.Name).ToList(); + return Array.Empty(); } else { - return KubernetesClient.ListNamespacedService( - namespaceParameter: _discoveryOptions.CurrentValue.Namespace, - labelSelector: labelSelectorValue).Items - .Select(service => service.Metadata.Name).ToList(); + var labelSelectorValue = + labels != null ? + string.Join(",", labels.Keys.Select(k => k + "=" + labels[k])) : + null; + if (_discoveryOptions.CurrentValue.AllNamespaces) + { + return KubernetesClient.ListServiceForAllNamespaces( + labelSelector: labelSelectorValue).Items + .Select(service => service.Metadata.Name).ToList(); + } + else + { + return KubernetesClient.ListNamespacedService( + namespaceParameter: _discoveryOptions.CurrentValue.Namespace, + labelSelector: labelSelectorValue).Items + .Select(service => service.Metadata.Name).ToList(); + } } } } public IList GetInstances(string serviceId) { - if (serviceId == null) + using (var activity = _kubernetesActivity.StartActivity(nameof(GetInstances))) { - throw new ArgumentNullException(nameof(serviceId)); - } + if (serviceId == null) + { + throw new ArgumentNullException(nameof(serviceId)); + } - var endpoints = _discoveryOptions.CurrentValue.AllNamespaces - ? KubernetesClient.ListEndpointsForAllNamespaces(fieldSelector: $"metadata.name={serviceId}").Items - : KubernetesClient.ListNamespacedEndpoints( - _discoveryOptions.CurrentValue.Namespace ?? DefaultNamespace, - fieldSelector: $"metadata.name={serviceId}").Items; + var endpoints = _discoveryOptions.CurrentValue.AllNamespaces + ? KubernetesClient.ListEndpointsForAllNamespaces(fieldSelector: $"metadata.name={serviceId}").Items + : KubernetesClient.ListNamespacedEndpoints( + _discoveryOptions.CurrentValue.Namespace ?? DefaultNamespace, + fieldSelector: $"metadata.name={serviceId}").Items; - var subsetsNs = endpoints.Select(GetSubsetsFromEndpoints); + var subsetsNs = endpoints.Select(GetSubsetsFromEndpoints); - var serviceInstances = new List(); - if (subsetsNs.Any()) - { - foreach (var es in subsetsNs) + var serviceInstances = new List(); + if (subsetsNs.Any()) { - serviceInstances.AddRange(GetNamespacedServiceInstances(es, serviceId)); + foreach (var es in subsetsNs) + { + serviceInstances.AddRange(GetNamespacedServiceInstances(es, serviceId)); + } } - } - return serviceInstances; + return serviceInstances; + } } public IServiceInstance GetLocalServiceInstance()