diff --git a/Steeltoe.Debug.ruleset b/Steeltoe.Debug.ruleset
index 24c4c6487d..2b34016877 100644
--- a/Steeltoe.Debug.ruleset
+++ b/Steeltoe.Debug.ruleset
@@ -24,6 +24,7 @@
+
diff --git a/Steeltoe.Release.ruleset b/Steeltoe.Release.ruleset
index 821ac4d5cc..e8b6bf3f74 100644
--- a/Steeltoe.Release.ruleset
+++ b/Steeltoe.Release.ruleset
@@ -17,6 +17,7 @@
+
@@ -42,6 +43,7 @@
+
diff --git a/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs b/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs
index 571f16d5bd..769b412f95 100644
--- a/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs
+++ b/src/Common/src/Abstractions/DynamicTypeAccess/PackageResolver.cs
@@ -88,6 +88,7 @@ protected TypeAccessor ResolveType(params string[] typeNames)
foreach (string typeName in typeNames)
{
+#pragma warning disable S134 // Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply
try
{
Type type = assembly.GetType(typeName, true)!;
@@ -97,6 +98,7 @@ protected TypeAccessor ResolveType(params string[] typeNames)
{
exceptions.Add(exception);
}
+#pragma warning restore S134 // Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply
}
}
catch (Exception exception) when (exception is ArgumentException or IOException or BadImageFormatException)
diff --git a/src/Common/src/Common/Configuration/PropertyPlaceHolderHelper.cs b/src/Common/src/Common/Configuration/PropertyPlaceHolderHelper.cs
index c0817522c0..66a356bb49 100644
--- a/src/Common/src/Common/Configuration/PropertyPlaceHolderHelper.cs
+++ b/src/Common/src/Common/Configuration/PropertyPlaceHolderHelper.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System.Linq;
using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
@@ -77,99 +78,85 @@ public static IEnumerable> GetResolvedConfiguration
private static string ParseStringValue(string property, IConfiguration configuration, ISet visitedPlaceHolders, ILogger logger = null,
bool useEmptyStringIfNotFound = false)
{
- if (configuration == null)
- {
- return property;
- }
-
- if (string.IsNullOrEmpty(property))
+ if (configuration == null || string.IsNullOrEmpty(property))
{
return property;
}
int startIndex = property.IndexOf(Prefix, StringComparison.Ordinal);
- if (startIndex == -1)
- {
- return property;
- }
-
var result = new StringBuilder(property);
-
- while (startIndex != -1)
+ int endIndex;
+ while (startIndex != -1 && (endIndex = FindEndIndex(result, startIndex)) != -1)
{
- int endIndex = FindEndIndex(result, startIndex);
-
- if (endIndex != -1)
- {
- string placeholder = result.Substring(startIndex + Prefix.Length, endIndex);
- string originalPlaceholder = placeholder;
+ string placeholder = result.Substring(startIndex + Prefix.Length, endIndex);
- if (!visitedPlaceHolders.Add(originalPlaceholder))
- {
- throw new InvalidOperationException($"Found circular placeholder reference '{originalPlaceholder}' in property definitions.");
- }
+ string originalPlaceholder = placeholder;
- // Recursive invocation, parsing placeholders contained in the placeholder key.
- placeholder = ParseStringValue(placeholder, configuration, visitedPlaceHolders);
+ if (!visitedPlaceHolders.Add(originalPlaceholder))
+ {
+ throw new InvalidOperationException($"Found circular placeholder reference '{originalPlaceholder}' in property definitions.");
+ }
- // Handle array references foo:bar[1]:baz format -> foo:bar:1:baz
- string lookup = placeholder.Replace('[', ':').Replace("]", string.Empty, StringComparison.Ordinal);
+ // Recursive invocation, parsing placeholders contained in the placeholder key.
+ placeholder = ParseStringValue(placeholder, configuration, visitedPlaceHolders);
- // Now obtain the value for the fully resolved key...
- string propVal = configuration[lookup];
+ // Handle array references foo:bar[1]:baz format -> foo:bar:1:baz
+ string lookup = placeholder.Replace('[', ':').Replace("]", string.Empty, StringComparison.Ordinal);
- if (propVal == null)
- {
- int separatorIndex = placeholder.IndexOf(Separator, StringComparison.Ordinal);
-
- if (separatorIndex != -1)
- {
- string actualPlaceholder = placeholder.Substring(0, separatorIndex);
- string defaultValue = placeholder.Substring(separatorIndex + Separator.Length);
- propVal = configuration[actualPlaceholder] ?? defaultValue;
- }
- else if (useEmptyStringIfNotFound)
- {
- propVal = string.Empty;
- }
- }
+ // Now obtain the value for the fully resolved key...
+ string propVal = configuration[lookup];
- // Attempt to resolve as a spring-compatible placeholder
- if (propVal == null)
- {
- // Replace Spring delimiters ('.') with MS-friendly delimiters (':') so Spring placeholders can also be resolved
- lookup = placeholder.Replace('.', ':');
- propVal = configuration[lookup];
- }
+ propVal ??= ResolveValue(configuration, placeholder, propVal, useEmptyStringIfNotFound);
- if (propVal != null)
- {
- // Recursive invocation, parsing placeholders contained in these
- // previously resolved placeholder value.
- propVal = ParseStringValue(propVal, configuration, visitedPlaceHolders);
- result.Replace(startIndex, endIndex + Suffix.Length, propVal);
- logger?.LogDebug("Resolved placeholder '{placeholder}'", placeholder);
- startIndex = result.IndexOf(Prefix, startIndex + propVal.Length);
- }
- else
- {
- // Proceed with unprocessed value.
- startIndex = result.IndexOf(Prefix, endIndex + Prefix.Length);
- }
-
- visitedPlaceHolders.Remove(originalPlaceholder);
+ if (propVal != null)
+ {
+ // Recursive invocation, parsing placeholders contained in these
+ // previously resolved placeholder value.
+ propVal = ParseStringValue(propVal, configuration, visitedPlaceHolders);
+ result.Replace(startIndex, endIndex + Suffix.Length, propVal);
+ logger?.LogDebug("Resolved placeholder '{placeholder}'", placeholder);
+ startIndex = result.IndexOf(Prefix, startIndex + propVal.Length);
}
else
{
- startIndex = -1;
+ // Proceed with unprocessed value.
+ startIndex = result.IndexOf(Prefix, endIndex + Prefix.Length);
}
+
+ visitedPlaceHolders.Remove(originalPlaceholder);
+
}
return result.ToString();
}
+ private static string ResolveValue(IConfiguration configuration, string placeholder, string propVal, bool useEmptyStringIfNotFound)
+ {
+ int separatorIndex = placeholder.IndexOf(Separator, StringComparison.Ordinal);
+
+ if (separatorIndex != -1)
+ {
+ string actualPlaceholder = placeholder.Substring(0, separatorIndex);
+ string defaultValue = placeholder.Substring(separatorIndex + Separator.Length);
+ propVal = configuration[actualPlaceholder] ?? defaultValue;
+ }
+ else if (useEmptyStringIfNotFound)
+ {
+ propVal = string.Empty;
+ }
+
+ // Attempt to resolve as a spring-compatible placeholder
+ if (propVal == null)
+ {
+ // Replace Spring delimiters ('.') with MS-friendly delimiters (':') so Spring placeholders can also be resolved
+ string lookup = placeholder.Replace('.', ':');
+ propVal = configuration[lookup];
+ }
+ return propVal;
+ }
+
private static int FindEndIndex(StringBuilder property, int startIndex)
{
int index = startIndex + Prefix.Length;
diff --git a/src/Common/src/Common/Net/InetUtils.cs b/src/Common/src/Common/Net/InetUtils.cs
index 817e30dc0b..b90c2f05a9 100644
--- a/src/Common/src/Common/Net/InetUtils.cs
+++ b/src/Common/src/Common/Net/InetUtils.cs
@@ -46,39 +46,30 @@ public IPAddress FindFirstNonLoopbackAddress()
try
{
int lowest = int.MaxValue;
- NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
+ NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces()
+ .Where(x => x.OperationalStatus == OperationalStatus.Up && !x.IsReceiveOnly && !IgnoreInterface(x.Name))
+ .ToArray();
foreach (NetworkInterface @interface in interfaces)
{
- if (@interface.OperationalStatus == OperationalStatus.Up && !@interface.IsReceiveOnly)
+ _logger?.LogTrace("Testing interface: {name}, {id}", @interface.Name, @interface.Id);
+
+ IPInterfaceProperties props = @interface.GetIPProperties();
+ IPv4InterfaceProperties ipProps = props.GetIPv4Properties();
+
+ if (ipProps.Index < lowest || result == null)
+ {
+ lowest = ipProps.Index;
+ }
+ else
{
- _logger?.LogTrace("Testing interface: {name}, {id}", @interface.Name, @interface.Id);
-
- IPInterfaceProperties props = @interface.GetIPProperties();
- IPv4InterfaceProperties ipProps = props.GetIPv4Properties();
-
- if (ipProps.Index < lowest || result == null)
- {
- lowest = ipProps.Index;
- }
- else
- {
- continue;
- }
-
- if (!IgnoreInterface(@interface.Name))
- {
- foreach (UnicastIPAddressInformation addressInfo in props.UnicastAddresses)
- {
- IPAddress address = addressInfo.Address;
-
- if (IsInet4Address(address) && !IsLoopbackAddress(address) && IsPreferredAddress(address))
- {
- _logger?.LogTrace("Found non-loopback interface: {name}", @interface.Name);
- result = address;
- }
- }
- }
+ continue;
+ }
+ foreach (UnicastIPAddressInformation addressInfo in props.UnicastAddresses
+ .Where(x => IsInet4Address(x.Address) && !IsLoopbackAddress(x.Address) && IsPreferredAddress(x.Address)))
+ {
+ _logger?.LogTrace("Found non-loopback interface: {name}", @interface.Name);
+ result = addressInfo.Address;
}
}
}
@@ -195,30 +186,18 @@ internal HostInfo ConvertAddress(IPAddress address)
internal IPAddress ResolveHostAddress(string hostName)
{
- IPAddress result = null;
-
try
{
IPAddress[] results = Dns.GetHostAddresses(hostName);
- if (results.Length > 0)
- {
- foreach (IPAddress address in results)
- {
- if (address.AddressFamily == AddressFamily.InterNetwork)
- {
- result = address;
- break;
- }
- }
- }
+ return Array.Find(results, x => x.AddressFamily == AddressFamily.InterNetwork);
}
catch (Exception e)
{
_logger?.LogWarning(e, "Unable to resolve host address");
}
- return result;
+ return null;
}
internal string ResolveHostName()
diff --git a/src/Common/src/Common/Reflection/ReflectionHelpers.cs b/src/Common/src/Common/Reflection/ReflectionHelpers.cs
index e68528e800..34c6abeb44 100644
--- a/src/Common/src/Common/Reflection/ReflectionHelpers.cs
+++ b/src/Common/src/Common/Reflection/ReflectionHelpers.cs
@@ -213,16 +213,17 @@ public static Type FindType(string[] assemblyNames, string[] typeNames)
{
Assembly assembly = FindAssembly(assemblyName);
- if (assembly != null)
+ if (assembly == null)
{
- foreach (string type in typeNames)
- {
- Type result = FindType(assembly, type);
+ continue;
+ }
+ foreach (string type in typeNames)
+ {
+ Type result = FindType(assembly, type);
- if (result != null)
- {
- return result;
- }
+ if (result != null)
+ {
+ return result;
}
}
}
@@ -462,12 +463,7 @@ private static void TryLoadAssembliesWithAttribute()
try
{
Assembly assemblyRef = loadContext.LoadFromAssemblyPath(assembly);
-
- // haven't been able to get actual type comparison to work (assembly of the attribute not found?), falling back on matching the type name
- if (CustomAttributeData.GetCustomAttributes(assemblyRef).Any(attr => attr.AttributeType.FullName == typeof(T).FullName))
- {
- FindAssembly(filename);
- }
+ FindAssemblyByFullName(assemblyRef, filename);
}
catch
{
@@ -477,6 +473,15 @@ private static void TryLoadAssembliesWithAttribute()
}
}
+ private static void FindAssemblyByFullName(Assembly assemblyRef, string filename)
+ {
+ // haven't been able to get actual type comparison to work (assembly of the attribute not found?), falling back on matching the type name
+ if (CustomAttributeData.GetCustomAttributes(assemblyRef).Any(attr => attr.AttributeType.FullName == typeof(T).FullName))
+ {
+ FindAssembly(filename);
+ }
+ }
+
///
/// Build a list of file paths that are relevant to this task.
///
diff --git a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
index 00c9146d94..fe9ecdf0d7 100644
--- a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
+++ b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System;
using System.Globalization;
using System.Net;
using System.Net.Http.Json;
@@ -226,21 +227,19 @@ public override void Load()
{
return await DoLoadAsync(updateDictionary, cancellationToken);
}
- catch (ConfigServerException e)
+ catch (ConfigServerException e) when (attempts < Settings.RetryAttempts)
{
Logger.LogInformation(e, "Failed fetching configuration from server at: {uri}.", Settings.Uri);
attempts++;
- if (attempts < Settings.RetryAttempts)
- {
- Thread.CurrentThread.Join(backOff);
- int nextBackOff = (int)(backOff * Settings.RetryMultiplier);
- backOff = Math.Min(nextBackOff, Settings.RetryMaxInterval);
- }
- else
- {
- throw;
- }
+ Thread.CurrentThread.Join(backOff);
+ int nextBackOff = (int)(backOff * Settings.RetryMultiplier);
+ backOff = Math.Min(nextBackOff, Settings.RetryMaxInterval);
+ }
+ catch (ConfigServerException e) when (attempts >= Settings.RetryAttempts)
+ {
+ Logger.LogInformation(e, "Failed fetching configuration for the final time from server at: {uri} .", Settings.Uri);
+ throw;
}
}
while (true);
@@ -275,37 +274,7 @@ public override void Load()
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)
- {
- var data = new Dictionary(StringComparer.OrdinalIgnoreCase);
-
- if (!string.IsNullOrEmpty(env.State))
- {
- data["spring:cloud:config:client:state"] = env.State;
- }
-
- if (!string.IsNullOrEmpty(env.Version))
- {
- data["spring:cloud:config:client:version"] = env.Version;
- }
-
- IList sources = env.PropertySources;
- int index = sources.Count - 1;
-
- for (; index >= 0; index--)
- {
- AddPropertySource(sources[index], data);
- }
-
- // Adds client settings (e.g. spring:cloud:config:uri, etc.) back to the (new) Data dictionary
- AddConfigServerClientSettings(data);
-
- if (!AreDictionariesEqual(Data, data))
- {
- Data = data;
- OnReload();
- }
- }
+ UpdateDictionaryData(updateDictionary, env);
return env;
}
@@ -326,6 +295,42 @@ public override void Load()
return null;
}
+ private void UpdateDictionaryData(bool updateDictionary, ConfigEnvironment env)
+ {
+ if (updateDictionary)
+ {
+ return;
+ }
+ var data = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ if (!string.IsNullOrEmpty(env.State))
+ {
+ data["spring:cloud:config:client:state"] = env.State;
+ }
+
+ if (!string.IsNullOrEmpty(env.Version))
+ {
+ data["spring:cloud:config:client:version"] = env.Version;
+ }
+
+ IList sources = env.PropertySources;
+ int index = sources.Count - 1;
+
+ for (; index >= 0; index--)
+ {
+ AddPropertySource(sources[index], data);
+ }
+
+ // Adds client settings (e.g. spring:cloud:config:uri, etc.) back to the (new) Data dictionary
+ AddConfigServerClientSettings(data);
+
+ if (!AreDictionariesEqual(Data, data))
+ {
+ Data = data;
+ OnReload();
+ }
+ }
+
private static bool AreDictionariesEqual(IDictionary first, IDictionary second)
{
return first.Count == second.Count && first.Keys.All(firstKey =>
@@ -377,16 +382,7 @@ internal void UpdateSettingsFromDiscovery(IEnumerable instance
settings.Username = username;
settings.Password = password;
}
-
- if (metaData.TryGetValue("configPath", out string? path))
- {
- if (uri.EndsWith('/') && path.StartsWith('/'))
- {
- uri = uri.Substring(0, uri.Length - 1);
- }
-
- uri += path;
- }
+ uri += ExtractPath(metaData, uri);
}
endpoints.Append(uri);
@@ -400,6 +396,15 @@ internal void UpdateSettingsFromDiscovery(IEnumerable instance
}
}
+ private string ExtractPath(IDictionary metaData, string uri)
+ {
+ if (metaData.TryGetValue("configPath", out string? path))
+ {
+ return uri.EndsWith('/') && path.StartsWith('/')? path.Substring(1, path.Length - 1) : path;
+ }
+ return string.Empty;
+ }
+
internal async Task ProvideRuntimeReplacementsAsync(IDiscoveryClient? discoveryClientFromDi, CancellationToken cancellationToken)
{
if (_configServerDiscoveryService is not null)
@@ -535,21 +540,20 @@ private void AddConfigServerClientSettings(IDictionary data)
Logger.LogInformation("Config Server returned status: {statusCode} invoking path: {requestUri}", response.StatusCode,
WebUtility.UrlEncode(requestUri));
- if (response.StatusCode != HttpStatusCode.OK)
- {
- 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)}");
- }
+ if (response.StatusCode == HttpStatusCode.NotFound)
+ {
+ return null;
+ }
+ // Throw if status >= 400
+ else if (response.StatusCode >= HttpStatusCode.BadRequest)
+ {
+ // HttpClientErrorException
+ throw new HttpRequestException(
+ $"Config Server returned status: {response.StatusCode} invoking path: {WebUtility.UrlEncode(requestUri)}");
+ }
+ else if (response.StatusCode != HttpStatusCode.OK)
+ {
return null;
}
diff --git a/src/Configuration/src/Encryption/EncryptionResolverProvider.cs b/src/Configuration/src/Encryption/EncryptionResolverProvider.cs
index db31e4bfbc..94473cb521 100644
--- a/src/Configuration/src/Encryption/EncryptionResolverProvider.cs
+++ b/src/Configuration/src/Encryption/EncryptionResolverProvider.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
@@ -193,22 +194,16 @@ public void Dispose()
{
HashSet disposables = [];
- foreach (IConfigurationProvider provider in Providers)
+ foreach (IDisposable disposable in GetDisposables(Providers))
{
- if (provider is IDisposable disposable)
- {
- disposables.Add(disposable);
- }
+ disposables.Add(disposable);
}
if (Configuration != null)
{
- foreach (IConfigurationProvider provider in Configuration.Providers)
+ foreach (IDisposable disposable in GetDisposables(Configuration.Providers))
{
- if (provider is IDisposable disposable)
- {
- disposables.Add(disposable);
- }
+ disposables.Add(disposable);
}
}
@@ -220,4 +215,17 @@ public void Dispose()
_isDisposed = true;
}
}
+
+ private HashSet GetDisposables(IEnumerable providers)
+ {
+ HashSet disposables = [];
+ foreach (IConfigurationProvider provider in providers)
+ {
+ if (provider is IDisposable disposable)
+ {
+ disposables.Add(disposable);
+ }
+ }
+ return disposables;
+ }
}
diff --git a/src/Configuration/src/Placeholder/PlaceholderResolverProvider.cs b/src/Configuration/src/Placeholder/PlaceholderResolverProvider.cs
index 3d49dacd38..89abfc634a 100644
--- a/src/Configuration/src/Placeholder/PlaceholderResolverProvider.cs
+++ b/src/Configuration/src/Placeholder/PlaceholderResolverProvider.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@@ -173,22 +174,16 @@ public void Dispose()
{
HashSet disposables = [];
- foreach (IConfigurationProvider provider in Providers)
+ foreach (IDisposable disposable in GetDisposables(Providers))
{
- if (provider is IDisposable disposable)
- {
- disposables.Add(disposable);
- }
+ disposables.Add(disposable);
}
if (Configuration != null)
{
- foreach (IConfigurationProvider provider in Configuration.Providers)
+ foreach (IDisposable disposable in GetDisposables(Configuration.Providers))
{
- if (provider is IDisposable disposable)
- {
- disposables.Add(disposable);
- }
+ disposables.Add(disposable);
}
}
@@ -200,4 +195,17 @@ public void Dispose()
_isDisposed = true;
}
}
+
+ private HashSet GetDisposables(IEnumerable providers)
+ {
+ HashSet disposables = [];
+ foreach (IConfigurationProvider provider in providers)
+ {
+ if (provider is IDisposable disposable)
+ {
+ disposables.Add(disposable);
+ }
+ }
+ return disposables;
+ }
}
diff --git a/src/Connectors/src/Connectors/ConnectionStringPostProcessor.cs b/src/Connectors/src/Connectors/ConnectionStringPostProcessor.cs
index f139c54458..4922ea877f 100644
--- a/src/Connectors/src/Connectors/ConnectionStringPostProcessor.cs
+++ b/src/Connectors/src/Connectors/ConnectionStringPostProcessor.cs
@@ -139,14 +139,11 @@ private void SetConnectionString(IDictionary configurationData,
// Take the connection string from appsettings.json as baseline, then merge cloud-provided secrets into it.
connectionStringBuilder.ConnectionString = secretValue;
}
- else
+ // Never merge separately-defined secrets from appsettings.json into the connection string.
+ // Earlier Steeltoe versions used to do that, which raised the question what takes precedence.
+ else if (!IsPartOfConnectionString(secretName))
{
- // Never merge separately-defined secrets from appsettings.json into the connection string.
- // Earlier Steeltoe versions used to do that, which raised the question what takes precedence.
- if (!IsPartOfConnectionString(secretName))
- {
- separateSecrets[secretName] = secretValue;
- }
+ separateSecrets[secretName] = secretValue;
}
}
}
diff --git a/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs b/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs
index 9cf767dc40..034ee88344 100644
--- a/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs
+++ b/src/Connectors/src/Connectors/MongoDb/MongoDbConnectionStringBuilder.cs
@@ -117,7 +117,9 @@ private string ToConnectionString()
return builder.Uri.AbsoluteUri;
}
+#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
private void FromConnectionString(string? connectionString, bool preserveUnknownSettings)
+#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high
{
if (preserveUnknownSettings)
{
@@ -131,56 +133,54 @@ private void FromConnectionString(string? connectionString, bool preserveUnknown
_settings.Clear();
}
- if (!string.IsNullOrEmpty(connectionString))
+ if (string.IsNullOrEmpty(connectionString))
{
- if (connectionString.Contains(','))
- {
- // MongoDB allows multiple servers in the connection string, but we haven't found any service bindings that actually use that.
- throw new NotImplementedException("Support for multiple servers is not implemented. Please open a GitHub issue if you need this.");
- }
+ return;
+ }
+ if (connectionString.Contains(','))
+ {
+ // MongoDB allows multiple servers in the connection string, but we haven't found any service bindings that actually use that.
+ throw new NotImplementedException("Support for multiple servers is not implemented. Please open a GitHub issue if you need this.");
+ }
- // MongoDB allows semicolon as separator for query string parameters, to provide backwards compatibility.
- connectionString = connectionString.Replace(';', '&');
+ // MongoDB allows semicolon as separator for query string parameters, to provide backwards compatibility.
+ connectionString = connectionString.Replace(';', '&');
- var uri = new Uri(connectionString);
+ var uri = new Uri(connectionString);
- if (!string.IsNullOrEmpty(uri.UserInfo))
- {
- string[] parts = uri.UserInfo.Split(':', 2);
+ if (!string.IsNullOrEmpty(uri.UserInfo))
+ {
+ string[] parts = uri.UserInfo.Split(':', 2);
- _settings[KnownKeywords.Username] = Uri.UnescapeDataString(parts[0]);
+ _settings[KnownKeywords.Username] = Uri.UnescapeDataString(parts[0]);
- if (parts.Length == 2)
- {
- _settings[KnownKeywords.Password] = Uri.UnescapeDataString(parts[1]);
- }
+ if (parts.Length == 2)
+ {
+ _settings[KnownKeywords.Password] = Uri.UnescapeDataString(parts[1]);
}
+ }
- _settings[KnownKeywords.Server] = uri.Host;
+ _settings[KnownKeywords.Server] = uri.Host;
- if (uri.Port != -1)
- {
- _settings[KnownKeywords.Port] = uri.Port.ToString(CultureInfo.InvariantCulture);
- }
+ if (uri.Port != -1)
+ {
+ _settings[KnownKeywords.Port] = uri.Port.ToString(CultureInfo.InvariantCulture);
+ }
- if (uri.AbsolutePath.StartsWith('/') && uri.AbsolutePath.Length > 1)
- {
- _settings[KnownKeywords.AuthenticationDatabase] = Uri.UnescapeDataString(uri.AbsolutePath[1..]);
- }
+ if (uri.AbsolutePath.StartsWith('/') && uri.AbsolutePath.Length > 1)
+ {
+ _settings[KnownKeywords.AuthenticationDatabase] = Uri.UnescapeDataString(uri.AbsolutePath[1..]);
+ }
- NameValueCollection queryCollection = HttpUtility.ParseQueryString(uri.Query);
+ NameValueCollection queryCollection = HttpUtility.ParseQueryString(uri.Query);
- foreach (string? key in queryCollection.AllKeys)
- {
- if (key != null)
- {
- string? value = queryCollection.Get(key);
+ foreach (string? key in queryCollection.AllKeys.Where(x => x != null))
+ {
+ string? value = queryCollection.Get(key);
- if (value != null)
- {
- _settings[key] = value;
- }
- }
+ if (key != null && value != null)
+ {
+ _settings[key] = value;
}
}
}
diff --git a/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs b/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs
index 10c3d9b534..ee6a09d663 100644
--- a/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs
+++ b/src/Connectors/src/Connectors/Redis/RedisConnectionStringBuilder.cs
@@ -87,36 +87,37 @@ private void FromConnectionString(string? connectionString)
{
_settings.Clear();
- if (!string.IsNullOrEmpty(connectionString))
+ if (string.IsNullOrEmpty(connectionString))
{
- foreach (string option in connectionString.Split(',').Where(element => !string.IsNullOrWhiteSpace(element)))
+ return;
+ }
+ foreach (string option in connectionString.Split(',').Where(element => !string.IsNullOrWhiteSpace(element)))
+ {
+ int equalsIndex = option.IndexOf('=');
+
+ if (equalsIndex != -1)
{
- int equalsIndex = option.IndexOf('=');
+ string name = option[..equalsIndex].Trim();
+ string value = option[(equalsIndex + 1)..].Trim();
+ _settings[name] = value;
+ }
+ else if (option.Contains(','))
+ {
+ // Redis allows multiple servers in the connection string, but we haven't found any service bindings that actually use that.
+ throw new NotImplementedException("Support for multiple servers is not implemented. Please open a GitHub issue if you need this.");
+ }
+ else
+ {
+ string[] hostWithPort = option.Split(':', 2);
+ _settings[KnownKeywords.Host] = hostWithPort[0];
- if (equalsIndex != -1)
+ if (hostWithPort.Length > 1)
{
- string name = option[..equalsIndex].Trim();
- string value = option[(equalsIndex + 1)..].Trim();
- _settings[name] = value;
- }
- else
- {
- if (option.Contains(','))
- {
- // Redis allows multiple servers in the connection string, but we haven't found any service bindings that actually use that.
- throw new NotImplementedException("Support for multiple servers is not implemented. Please open a GitHub issue if you need this.");
- }
-
- string[] hostWithPort = option.Split(':', 2);
- _settings[KnownKeywords.Host] = hostWithPort[0];
-
- if (hostWithPort.Length > 1)
- {
- _settings[KnownKeywords.Port] = hostWithPort[1];
- }
+ _settings[KnownKeywords.Port] = hostWithPort[1];
}
}
}
+
}
private static void AssertIsKnownKeyword(string keyword)
diff --git a/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTests.cs b/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTests.cs
index 3516f465ad..82e7cf92c5 100644
--- a/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTests.cs
+++ b/src/Connectors/test/Connectors.Test/PostgreSql/PostgreSqlConnectorTests.cs
@@ -760,10 +760,12 @@ private static IEnumerable ExtractConnectionStringParameters(string? con
string name = nameValuePair[0];
string value = nameValuePair[1];
+#pragma warning disable S134 // Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply
if (TempFileKeys.Contains(name))
{
value = File.ReadAllText(value);
}
+#pragma warning restore S134 // Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply
value = value.Replace("\n", Environment.NewLine, StringComparison.Ordinal);
@@ -787,10 +789,12 @@ private static void CleanupTempFiles(params string?[] connectionStrings)
string key = pair[0];
string value = pair[1];
+#pragma warning disable S134 // Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply
if (TempFileKeys.Contains(key) && File.Exists(value))
{
File.Delete(value);
}
+#pragma warning restore S134 // Control flow statements "if", "switch", "for", "foreach", "while", "do" and "try" should not be nested too deeply
}
}
}
diff --git a/src/Discovery/src/Eureka/AppInfo/Applications.cs b/src/Discovery/src/Eureka/AppInfo/Applications.cs
index 3bc2b5b9d9..46921e7793 100644
--- a/src/Discovery/src/Eureka/AppInfo/Applications.cs
+++ b/src/Discovery/src/Eureka/AppInfo/Applications.cs
@@ -259,14 +259,11 @@ private IList DoGetByVirtualHostName(string name, ConcurrentDictio
{
InstanceInfo inst = kvp.Value;
- if (ReturnUpInstancesOnly)
+ if (ReturnUpInstancesOnly && inst.Status == InstanceStatus.Up)
{
- if (inst.Status == InstanceStatus.Up)
- {
- result.Add(inst);
- }
+ result.Add(inst);
}
- else
+ else if(!ReturnUpInstancesOnly)
{
result.Add(inst);
}
diff --git a/src/Discovery/src/Eureka/DiscoveryClient.cs b/src/Discovery/src/Eureka/DiscoveryClient.cs
index 0cd676a561..de0b64599f 100644
--- a/src/Discovery/src/Eureka/DiscoveryClient.cs
+++ b/src/Discovery/src/Eureka/DiscoveryClient.cs
@@ -168,17 +168,14 @@ public IList GetInstancesByVipAddressAndAppName(string vipAddress,
return result;
}
- foreach (Application app in localRegionApps.GetRegisteredApplications())
+ foreach (InstanceInfo instance in localRegionApps.GetRegisteredApplications().SelectMany(x => x.Instances))
{
- foreach (InstanceInfo instance in app.Instances)
- {
- string instanceVipAddress = secure ? instance.SecureVipAddress : instance.VipAddress;
+ string instanceVipAddress = secure ? instance.SecureVipAddress : instance.VipAddress;
- if (vipAddress.Equals(instanceVipAddress, StringComparison.OrdinalIgnoreCase) &&
- appName.Equals(instance.AppName, StringComparison.OrdinalIgnoreCase))
- {
- result.Add(instance);
- }
+ if (vipAddress.Equals(instanceVipAddress, StringComparison.OrdinalIgnoreCase) &&
+ appName.Equals(instance.AppName, StringComparison.OrdinalIgnoreCase))
+ {
+ result.Add(instance);
}
}
@@ -259,15 +256,10 @@ private async void HandleInstanceStatusChanged(object sender, StatusChangedEvent
logger.LogDebug("HandleInstanceStatusChanged {previousStatus}, {currentStatus}, {instanceId}, {dirty}", args.Previous, args.Current,
args.InstanceId, info.IsDirty);
- if (info.IsDirty)
+ if (info.IsDirty && await RegisterAsync(CancellationToken.None))
{
- bool result = await RegisterAsync(CancellationToken.None);
-
- if (result)
- {
- info.IsDirty = false;
- logger.LogInformation("HandleInstanceStatusChanged RegisterAsync succeeded");
- }
+ info.IsDirty = false;
+ logger.LogInformation("HandleInstanceStatusChanged RegisterAsync succeeded");
}
}
}
@@ -434,16 +426,9 @@ protected internal async Task FetchFullRegistryAsync(CancellationT
long startingCounter = registryFetchCounter;
Applications fetched = null;
- EurekaHttpResponse resp;
-
- if (string.IsNullOrEmpty(ClientConfiguration.RegistryRefreshSingleVipAddress))
- {
- resp = await HttpClient.GetApplicationsAsync(cancellationToken);
- }
- else
- {
- resp = await HttpClient.GetVipAsync(ClientConfiguration.RegistryRefreshSingleVipAddress, cancellationToken);
- }
+ EurekaHttpResponse resp = string.IsNullOrEmpty(ClientConfiguration.RegistryRefreshSingleVipAddress)
+ ? await HttpClient.GetApplicationsAsync(cancellationToken)
+ : await HttpClient.GetVipAsync(ClientConfiguration.RegistryRefreshSingleVipAddress, cancellationToken);
logger.LogDebug("FetchFullRegistry returned: {StatusCode}, {Response}", resp.StatusCode, resp.Response != null ? resp.Response.ToString() : "null");
diff --git a/src/Discovery/src/Eureka/EurekaPostConfigurer.cs b/src/Discovery/src/Eureka/EurekaPostConfigurer.cs
index 3ac74562ec..c9e7b6156d 100644
--- a/src/Discovery/src/Eureka/EurekaPostConfigurer.cs
+++ b/src/Discovery/src/Eureka/EurekaPostConfigurer.cs
@@ -71,7 +71,9 @@ public static void UpdateConfiguration(EurekaServiceInfo si, EurekaClientOptions
///
/// Information about this application instance.
///
+#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
public static void UpdateConfiguration(IConfiguration configuration, EurekaInstanceOptions options, IApplicationInstanceInfo instanceInfo)
+#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high
{
string defaultIdEnding = $":{EurekaInstanceConfiguration.DefaultAppName}:{EurekaInstanceConfiguration.DefaultNonSecurePort}";
diff --git a/src/Discovery/src/Eureka/Transport/EurekaHttpClient.cs b/src/Discovery/src/Eureka/Transport/EurekaHttpClient.cs
index 898da98fb3..a8dd00559b 100644
--- a/src/Discovery/src/Eureka/Transport/EurekaHttpClient.cs
+++ b/src/Discovery/src/Eureka/Transport/EurekaHttpClient.cs
@@ -25,9 +25,9 @@ public class EurekaHttpClient : IEurekaHttpClient
private const int DefaultGetAccessTokenTimeout = 10000; // Milliseconds
private static readonly char[] ColonDelimit =
- {
+ [
':'
- };
+ ];
private readonly IOptionsMonitor _configurationOptions;
@@ -190,10 +190,6 @@ public virtual async Task> SendHeartBeatAsync(s
{
string responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
- if (response.IsSuccessStatusCode && string.IsNullOrEmpty(responseBody))
- {
- // request was successful but body was empty. This is OK, we don't need a response body
- }
logger?.LogError(exception, "Failed to read heartbeat response. Response code: {responseCode}, Body: {responseBody}", response.StatusCode,
responseBody);
diff --git a/src/Management/src/Endpoint/Info/Contributor/GitInfoContributor.cs b/src/Management/src/Endpoint/Info/Contributor/GitInfoContributor.cs
index d657ff5191..126e31bf4c 100755
--- a/src/Management/src/Endpoint/Info/Contributor/GitInfoContributor.cs
+++ b/src/Management/src/Endpoint/Info/Contributor/GitInfoContributor.cs
@@ -54,34 +54,31 @@ public async Task ContributeAsync(IInfoBuilder builder, CancellationToken cancel
{
string[] lines = await File.ReadAllLinesAsync(propertiesPath, cancellationToken);
- if (lines.Length > 0)
+ if (lines.Length == 0)
{
- var dictionary = new Dictionary();
-
- foreach (string line in lines)
- {
- if (line.StartsWith('#') || !line.StartsWith("git.", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
-
- string[] keyValuePair = line.Split('=');
-
- if (keyValuePair.Length != 2)
- {
- continue;
- }
+ _logger.LogWarning("Unable to find valid GitInfo at {GitInfoLocation}", propertiesPath);
+ return null;
+ }
+ var dictionary = new Dictionary();
- string key = keyValuePair[0].Trim().Replace('.', ':');
- string value = keyValuePair[1].Replace("\\:", ":", StringComparison.Ordinal);
+ foreach (string line in lines.Where(x => x.StartsWith("git.", StringComparison.OrdinalIgnoreCase)))
+ {
+ string[] keyValuePair = line.Split('=');
- dictionary[key] = value;
+ if (keyValuePair.Length != 2)
+ {
+ continue;
}
- var builder = new ConfigurationBuilder();
- builder.AddInMemoryCollection(dictionary);
- return builder.Build();
+ string key = keyValuePair[0].Trim().Replace('.', ':');
+ string value = keyValuePair[1].Replace("\\:", ":", StringComparison.Ordinal);
+
+ dictionary[key] = value;
}
+
+ var builder = new ConfigurationBuilder();
+ builder.AddInMemoryCollection(dictionary);
+ return builder.Build();
}
else
{
diff --git a/src/Management/src/Endpoint/Loggers/LoggersEndpointMiddleware.cs b/src/Management/src/Endpoint/Loggers/LoggersEndpointMiddleware.cs
index 61f7d41c5e..81c60fd252 100644
--- a/src/Management/src/Endpoint/Loggers/LoggersEndpointMiddleware.cs
+++ b/src/Management/src/Endpoint/Loggers/LoggersEndpointMiddleware.cs
@@ -57,25 +57,31 @@ protected override async Task InvokeEndpointHandlerAsync(HttpCo
string loggerName = remaining.Value!.TrimStart('/');
Dictionary change = await DeserializeRequestAsync(request.Body);
+ return CheckLogger(loggerName, change);
+ }
+ }
- change.TryGetValue("configuredLevel", out string? level);
+ return new LoggersRequest();
+ }
- _logger.LogDebug("Change Request: {name}, {level}", loggerName, level ?? "RESET");
+ private LoggersRequest? CheckLogger(string loggerName, Dictionary change)
+ {
- if (!string.IsNullOrEmpty(loggerName))
- {
- if (!string.IsNullOrEmpty(level) && LoggerLevels.StringToLogLevel(level) == null)
- {
- _logger.LogDebug("Invalid LogLevel specified: {level}", level);
- return null;
- }
+ change.TryGetValue("configuredLevel", out string? level);
- return new LoggersRequest(loggerName, level);
- }
- }
+ _logger.LogDebug("Change Request: {name}, {level}", loggerName, level ?? "RESET");
+
+ if (string.IsNullOrEmpty(loggerName))
+ {
+ return new LoggersRequest();
+ }
+ if (!string.IsNullOrEmpty(level) && LoggerLevels.StringToLogLevel(level) == null)
+ {
+ _logger.LogDebug("Invalid LogLevel specified: {level}", level);
+ return null;
}
- return new LoggersRequest();
+ return new LoggersRequest(loggerName, level);
}
private async Task> DeserializeRequestAsync(Stream stream)
diff --git a/src/Management/src/Endpoint/Metrics/MetricsEndpointMiddleware.cs b/src/Management/src/Endpoint/Metrics/MetricsEndpointMiddleware.cs
index e5e2e14575..1d09252d48 100644
--- a/src/Management/src/Endpoint/Metrics/MetricsEndpointMiddleware.cs
+++ b/src/Management/src/Endpoint/Metrics/MetricsEndpointMiddleware.cs
@@ -69,18 +69,15 @@ internal IList> ParseTags(IQueryCollection query)
{
var results = new List>();
- foreach (KeyValuePair parameter in query)
+ foreach (KeyValuePair parameter in query.Where(x => x.Key.Equals("tag", StringComparison.OrdinalIgnoreCase)))
{
- if (parameter.Key.Equals("tag", StringComparison.OrdinalIgnoreCase))
+ foreach (string? value in parameter.Value)
{
- foreach (string? value in parameter.Value)
- {
- KeyValuePair? pair = ParseTag(value);
+ KeyValuePair? pair = ParseTag(value);
- if (pair != null && !results.Contains(pair.Value))
- {
- results.Add(pair.Value);
- }
+ if (pair != null && !results.Contains(pair.Value))
+ {
+ results.Add(pair.Value);
}
}
}
diff --git a/src/Management/src/Endpoint/Metrics/Observer/EventCounterListener.cs b/src/Management/src/Endpoint/Metrics/Observer/EventCounterListener.cs
index 93c737068f..d9c55ae173 100644
--- a/src/Management/src/Endpoint/Metrics/Observer/EventCounterListener.cs
+++ b/src/Management/src/Endpoint/Metrics/Observer/EventCounterListener.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Diagnostics.Tracing;
using System.Globalization;
@@ -63,21 +64,18 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
ArgumentGuard.NotNull(eventData);
- if (!_isInitialized)
- {
- return;
- }
-
try
{
- if (string.Equals(eventData.EventName, EventName, StringComparison.OrdinalIgnoreCase) && eventData.Payload != null)
+
+ if (!_isInitialized || string.Equals(eventData.EventName, EventName, StringComparison.OrdinalIgnoreCase) || eventData.Payload == null)
+ {
+ return;
+ }
+ foreach (IDictionary? payload in eventData.Payload)
{
- foreach (IDictionary? payload in eventData.Payload)
+ if (payload != null)
{
- if (payload != null)
- {
- ExtractAndRecordMetric(eventData.EventSource.Name, payload);
- }
+ ExtractAndRecordMetric(eventData.EventSource.Name, payload);
}
}
}
@@ -182,17 +180,10 @@ private void ExtractAndRecordMetric(string eventSourceName, IDictionary> labels = MakeLabels(payload.Value?.ToString());
+ if (labels.Any())
{
- string[] keyValuePairStrings = metadata.Split(',');
-
- foreach (string keyValuePairString in keyValuePairStrings)
- {
- string[] keyValuePair = keyValuePairString.Split(':');
- labelSet.Add(KeyValuePair.Create(keyValuePair[0], (object?)keyValuePair[1]));
- }
+ labelSet.AddRange(labels);
}
break;
@@ -217,6 +208,22 @@ private void ExtractAndRecordMetric(string eventSourceName, IDictionary> MakeLabels(string? metadata)
+ {
+ List> labelSet = new List>();
+ if (!string.IsNullOrEmpty(metadata))
+ {
+ string[] keyValuePairStrings = metadata.Split(',');
+
+ foreach (string keyValuePairString in keyValuePairStrings)
+ {
+ string[] keyValuePair = keyValuePairString.Split(':');
+ labelSet.Add(KeyValuePair.Create(keyValuePair[0], (object?)keyValuePair[1]));
+ }
+ }
+ return labelSet;
+ }
+
private Measurement ObserveDouble(string name, List> labelSet)
{
return new Measurement(_lastDoubleValue[name], labelSet);
diff --git a/src/Management/src/Endpoint/ThreadDump/EventPipeThreadDumper.cs b/src/Management/src/Endpoint/ThreadDump/EventPipeThreadDumper.cs
index 3a940e8b36..22e85cbdbe 100644
--- a/src/Management/src/Endpoint/ThreadDump/EventPipeThreadDumper.cs
+++ b/src/Management/src/Endpoint/ThreadDump/EventPipeThreadDumper.cs
@@ -338,7 +338,9 @@ private bool TryParseParameters(string input, ref string remaining, [NotNullWhen
}
// Much of this code is from PerfView/TraceLog.cs
+#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
private SourceLocation? GetSourceLine(TraceEventStackSource stackSource, StackSourceFrameIndex frameIndex, SymbolReader reader)
+#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high
{
TraceLog log = stackSource.TraceLog;
uint codeAddress = (uint)frameIndex - (uint)StackSourceFrameIndex.Start;
diff --git a/src/Management/src/Endpoint/Web/Hypermedia/HypermediaService.cs b/src/Management/src/Endpoint/Web/Hypermedia/HypermediaService.cs
index d55039e648..e961d64aff 100644
--- a/src/Management/src/Endpoint/Web/Hypermedia/HypermediaService.cs
+++ b/src/Management/src/Endpoint/Web/Hypermedia/HypermediaService.cs
@@ -71,19 +71,16 @@ public Links Invoke(string baseUrl)
{
selfLink = new Link(baseUrl);
}
- else
+ else if (!string.IsNullOrEmpty(endpointOptions.Id))
{
- if (!string.IsNullOrEmpty(endpointOptions.Id))
+ if (!links.Entries.ContainsKey(endpointOptions.Id))
{
- if (!links.Entries.ContainsKey(endpointOptions.Id))
- {
- string linkPath = $"{baseUrl.TrimEnd('/')}/{endpointOptions.Path}";
- links.Entries.Add(endpointOptions.Id, new Link(linkPath));
- }
- else
- {
- _logger.LogWarning("Duplicate endpoint ID detected: {DuplicateEndpointId}", endpointOptions.Id);
- }
+ string linkPath = $"{baseUrl.TrimEnd('/')}/{endpointOptions.Path}";
+ links.Entries.Add(endpointOptions.Id, new Link(linkPath));
+ }
+ else
+ {
+ _logger.LogWarning("Duplicate endpoint ID detected: {DuplicateEndpointId}", endpointOptions.Id);
}
}
}
diff --git a/src/Management/src/Tracing/TracingBaseServiceCollectionExtensions.cs b/src/Management/src/Tracing/TracingBaseServiceCollectionExtensions.cs
index c00c05e9c7..fd6b7173f4 100644
--- a/src/Management/src/Tracing/TracingBaseServiceCollectionExtensions.cs
+++ b/src/Management/src/Tracing/TracingBaseServiceCollectionExtensions.cs
@@ -50,7 +50,9 @@ public static IServiceCollection AddDistributedTracing(this IServiceCollection s
///
/// configured for distributed tracing.
///
+#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
public static IServiceCollection AddDistributedTracing(this IServiceCollection services, Action? action)
+#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high
{
ArgumentGuard.NotNull(services);
diff --git a/src/Management/src/Wavefront/Exporters/WavefrontMetricsExporter.cs b/src/Management/src/Wavefront/Exporters/WavefrontMetricsExporter.cs
index a0b9b09163..b02b412052 100644
--- a/src/Management/src/Wavefront/Exporters/WavefrontMetricsExporter.cs
+++ b/src/Management/src/Wavefront/Exporters/WavefrontMetricsExporter.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.
+using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Metrics;
@@ -58,49 +59,20 @@ public override ExportResult Export(in Batch batch)
foreach (Metric metric in batch)
{
- bool isLong = ((int)metric.MetricType & 0b_0000_1111) == 0x0a; // I8 : signed 8 byte integer
- bool isSum = metric.MetricType.IsSum();
try
{
- if (!metric.MetricType.IsHistogram())
+ List metricReadings = new List();
+ foreach (ref readonly MetricPoint metricPoint in metric.GetMetricPoints())
{
- foreach (ref readonly MetricPoint metricPoint in metric.GetMetricPoints())
- {
- long timestamp = metricPoint.EndTime.ToUnixTimeMilliseconds();
- double doubleValue;
-
- if (isLong)
- {
- doubleValue = isSum ? metricPoint.GetSumLong() : metricPoint.GetGaugeLastValueLong();
- }
- else
- {
- doubleValue = isSum ? metricPoint.GetSumDouble() : metricPoint.GetGaugeLastValueDouble();
- }
-
- IDictionary tags = GetTags(metricPoint.Tags);
-
- _wavefrontSender.SendMetric(metric.Name.ToLowerInvariant(), doubleValue, timestamp, Options.Source, tags);
-
- metricCount++;
- }
+ long timestamp = metricPoint.EndTime.ToUnixTimeMilliseconds();
+ IDictionary tags = GetTags(metricPoint.Tags);
+ metricReadings.AddRange(GetMetricData(metric, metricPoint, timestamp, tags));
}
- else
+ foreach (MetricReading metricReading in metricReadings)
{
- foreach (ref readonly MetricPoint metricPoint in metric.GetMetricPoints())
- {
- long timestamp = metricPoint.EndTime.ToUnixTimeMilliseconds();
-
- IDictionary tags = GetTags(metricPoint.Tags);
-
- _wavefrontSender.SendMetric($"{metric.Name.ToLowerInvariant()}_count", metricPoint.GetHistogramCount(), timestamp, Options.Source,
- tags);
-
- _wavefrontSender.SendMetric($"{metric.Name.ToLowerInvariant()}_sum", metricPoint.GetHistogramSum(), timestamp, Options.Source, tags);
-
- metricCount += 2;
- }
+ _wavefrontSender.SendMetric(metricReading.Key, metricReading.Value, metricReading.Timestamp, Options.Source, metricReading.Tags);
+ metricCount++;
}
}
catch (Exception exception)
@@ -113,6 +85,45 @@ public override ExportResult Export(in Batch batch)
return ExportResult.Success;
}
+ private List GetMetricData(Metric metric, MetricPoint metricPoint, long timestamp, IDictionary tags)
+ {
+ bool isLong = ((int)metric.MetricType & 0b_0000_1111) == 0x0a; // I8 : signed 8 byte integer
+ bool isSum = metric.MetricType.IsSum();
+ List metrics = [];
+ if (!metric.MetricType.IsHistogram())
+ {
+ double doubleValue;
+
+ if (isLong)
+ {
+ doubleValue = isSum ? metricPoint.GetSumLong() : metricPoint.GetGaugeLastValueLong();
+ }
+ else
+ {
+ doubleValue = isSum ? metricPoint.GetSumDouble() : metricPoint.GetGaugeLastValueDouble();
+ }
+ metrics.Add(new MetricReading(metric.Name.ToLowerInvariant(), doubleValue)
+ {
+ Tags = tags,
+ Timestamp = timestamp
+ });
+ }
+ else
+ {
+ metrics.Add(new MetricReading($"{metric.Name.ToLowerInvariant()}_count", metricPoint.GetHistogramCount())
+ {
+ Tags = tags,
+ Timestamp = timestamp
+ });
+ metrics.Add(new MetricReading($"{metric.Name.ToLowerInvariant()}_sum", metricPoint.GetHistogramSum())
+ {
+ Tags = tags,
+ Timestamp = timestamp
+ });
+ }
+ return metrics;
+ }
+
private IDictionary GetTags(ReadOnlyTagCollection inputTags)
{
IDictionary tags = inputTags.AsDictionary();
diff --git a/src/Management/src/Wavefront/MetricReading.cs b/src/Management/src/Wavefront/MetricReading.cs
new file mode 100644
index 0000000000..a739d7715d
--- /dev/null
+++ b/src/Management/src/Wavefront/MetricReading.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information.
+
+namespace Steeltoe.Management.Wavefront;
+
+internal class MetricReading
+{
+ public string Key { get; internal set; }
+ public double Value { get; internal set; }
+ public long? Timestamp { get; internal set; }
+ public IDictionary Tags { get; internal set; } = new Dictionary();
+
+ public MetricReading(string key, double value, long? timestamp, IDictionary tags)
+ {
+ Key = key;
+ Value = value;
+ Timestamp = timestamp;
+ Tags = tags;
+ }
+
+ public MetricReading(string key, double value)
+ {
+ Key = key;
+ Value = value;
+ }
+}
diff --git a/src/Security/test/Authentication.Mtls.Test/ClientCertificateAuthenticationTests.cs b/src/Security/test/Authentication.Mtls.Test/ClientCertificateAuthenticationTests.cs
index 7abe07486c..8adcc2b6b7 100644
--- a/src/Security/test/Authentication.Mtls.Test/ClientCertificateAuthenticationTests.cs
+++ b/src/Security/test/Authentication.Mtls.Test/ClientCertificateAuthenticationTests.cs
@@ -359,7 +359,9 @@ public async Task VerifyACustomHeaderFailsIfTheHeaderIsNotPresent()
}
[Fact]
+#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
public async Task VerifyNoEventWireUpWithAValidCertificateCreatesADefaultUser()
+#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high
{
TestServer server = CreateServer(new MutualTlsAuthenticationOptions
{
@@ -512,7 +514,9 @@ public async Task VerifyValidationEventPrincipalIsPropagated()
Assert.Single(responseAsXml.Elements("claim"));
}
+#pragma warning disable S3776 // Cognitive Complexity of methods should not be too high
private static TestServer CreateServer(MutualTlsAuthenticationOptions configureOptions, X509Certificate2 clientCertificate = null, Uri baseAddress = null,
+#pragma warning restore S3776 // Cognitive Complexity of methods should not be too high
bool wireUpHeaderMiddleware = false, string headerName = "")
{
IWebHostBuilder builder = new WebHostBuilder().Configure(app =>