diff --git a/BannedSymbols.NetFx.txt b/BannedSymbols.NetFx.txt new file mode 100644 index 000000000000..0c40b2407e4b --- /dev/null +++ b/BannedSymbols.NetFx.txt @@ -0,0 +1,4 @@ +# Banned APIs for Datadog.Trace when targeting .NET Framework + +M:System.String.ToUpperInvariant;Use StringUtil.ToUpperInvariant(value) instead - on .NET Framework it avoids allocating when the string is already uppercase +M:System.String.ToLowerInvariant;Use StringUtil.ToLowerInvariant(value) instead - on .NET Framework it avoids allocating when the string is already lowercase diff --git a/docs/development/Configuration/AddingConfigurationKeys.md b/docs/development/Configuration/AddingConfigurationKeys.md index 80ca67155d3d..524d91a4321b 100644 --- a/docs/development/Configuration/AddingConfigurationKeys.md +++ b/docs/development/Configuration/AddingConfigurationKeys.md @@ -212,7 +212,8 @@ Aliases use the normal `WithKeys()` fallback chain. When a key marked for redact - **Banned API Analyzer** - Uses Microsoft's `BannedApiAnalyzers` package to prevent direct usage of `System.Environment.GetEnvironmentVariable()` throughout the codebase. **Configuration:** -- **`BannedSymbols.txt`** (`tracer/src/Datadog.Trace.Tools.Analyzers/ConfigurationAnalyzers/BannedSymbols.txt`) - Defines banned APIs with custom error messages +- **`BannedSymbols.txt`** (repo root) - Defines banned APIs with custom error messages, applied to every project under `tracer/` that wires it up via `AdditionalFiles` +- **`BannedSymbols.NetFx.txt`** (repo root) - Additional bans applied only when building `Datadog.Trace` for `net461` - **`.editorconfig`** - Configures RS0030 diagnostic severity as error, with exceptions for vendored code and `EnvironmentConfigurationSource.cs` ##### Diagnostic rules: diff --git a/tracer/src/Datadog.Trace.SourceGenerators/EnumExtensions/Sources.cs b/tracer/src/Datadog.Trace.SourceGenerators/EnumExtensions/Sources.cs index 44381cb9f760..94c78d29e35d 100644 --- a/tracer/src/Datadog.Trace.SourceGenerators/EnumExtensions/Sources.cs +++ b/tracer/src/Datadog.Trace.SourceGenerators/EnumExtensions/Sources.cs @@ -209,25 +209,32 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => + #if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); + #else + value.ToUpperInvariant(); + #endif } } diff --git a/tracer/src/Datadog.Trace/Activity/OperationNameMapper.cs b/tracer/src/Datadog.Trace/Activity/OperationNameMapper.cs index d2bee810b159..ea7fe16188fd 100644 --- a/tracer/src/Datadog.Trace/Activity/OperationNameMapper.cs +++ b/tracer/src/Datadog.Trace/Activity/OperationNameMapper.cs @@ -56,7 +56,7 @@ internal static string GetOperationName(OpenTelemetryTags tags) if (tags.SpanKind == SpanKinds.Client && tags.GetTag("db.system") is { Length: > 0 } dbSystem) { // IsDatabase - return $"{dbSystem.ToLowerInvariant()}.query"; + return $"{StringUtil.ToLowerInvariant(dbSystem)}.query"; } if (tags.SpanKind is SpanKinds.Client or SpanKinds.Server or SpanKinds.Producer or SpanKinds.Consumer @@ -64,7 +64,7 @@ internal static string GetOperationName(OpenTelemetryTags tags) && tags.GetTag(Tags.MessagingOperation) is { Length: > 0 } messagingOperation) { // IsMessaging - return $"{messagingSystem}.{messagingOperation}".ToLowerInvariant(); + return StringUtil.ToLowerInvariant($"{messagingSystem}.{messagingOperation}"); } var rpcSystem = tags.GetTag(Tags.RpcSystem); @@ -73,27 +73,27 @@ internal static string GetOperationName(OpenTelemetryTags tags) if (tags.SpanKind == SpanKinds.Client && string.Equals(rpcSystem, "aws-api", StringComparison.OrdinalIgnoreCase)) { // IsAwsClient - var service = tags.GetTag(Tags.RpcService)?.ToLowerInvariant(); + var service = StringUtil.ToLowerInvariant(tags.GetTag(Tags.RpcService)); return !StringUtil.IsNullOrEmpty(service) ? $"aws.{service}.request" : "aws.client.request"; } if (tags.SpanKind == SpanKinds.Client) { // IsRpcClient - return $"{rpcSystem.ToLowerInvariant()}.client.request"; + return $"{StringUtil.ToLowerInvariant(rpcSystem)}.client.request"; } if (tags.SpanKind == SpanKinds.Server) { // IsRpcServer - return $"{rpcSystem.ToLowerInvariant()}.server.request"; + return $"{StringUtil.ToLowerInvariant(rpcSystem)}.server.request"; } } if (tags.SpanKind == SpanKinds.Server && tags.GetTag("faas.trigger") is { Length: > 0 } faasTrigger) { // IsFaasServer - return $"{faasTrigger.ToLowerInvariant()}.invoke"; + return $"{StringUtil.ToLowerInvariant(faasTrigger)}.invoke"; } if (tags.SpanKind == SpanKinds.Client @@ -101,7 +101,7 @@ internal static string GetOperationName(OpenTelemetryTags tags) && tags.GetTag("faas.invoked_name") is { Length: > 0 } faasInvokedName) { // IsFaasClient - return $"{faasInvokedProvider}.{faasInvokedName}.invoke".ToLowerInvariant(); + return StringUtil.ToLowerInvariant($"{faasInvokedProvider}.{faasInvokedName}.invoke"); } if (tags.SpanKind == SpanKinds.Server && !StringUtil.IsNullOrEmpty(tags.GetTag("graphql.operation.type"))) @@ -114,19 +114,19 @@ internal static string GetOperationName(OpenTelemetryTags tags) { // IsGenericServer var name = tags.GetTag("network.protocol.name"); - return !StringUtil.IsNullOrEmpty(name) ? $"{name.ToLowerInvariant()}.server.request" : "server.request"; + return !StringUtil.IsNullOrEmpty(name) ? $"{StringUtil.ToLowerInvariant(name)}.server.request" : "server.request"; } if (tags.SpanKind == SpanKinds.Client) { // IsGenericClient var name = tags.GetTag("network.protocol.name"); - return !StringUtil.IsNullOrEmpty(name) ? $"{name.ToLowerInvariant()}.client.request" : "client.request"; + return !StringUtil.IsNullOrEmpty(name) ? $"{StringUtil.ToLowerInvariant(name)}.client.request" : "client.request"; } // when there is no SpanKind defined (possible on Activity objects without "Kind") // fallback to using "internal" for the name. - return !StringUtil.IsNullOrEmpty(tags.SpanKind) ? tags.SpanKind.ToLowerInvariant() : SpanKinds.Internal; + return !StringUtil.IsNullOrEmpty(tags.SpanKind) ? StringUtil.ToLowerInvariant(tags.SpanKind) : SpanKinds.Internal; } } } diff --git a/tracer/src/Datadog.Trace/Activity/OtlpHelpers.cs b/tracer/src/Datadog.Trace/Activity/OtlpHelpers.cs index 490a1f426e03..4e5c937c6282 100644 --- a/tracer/src/Datadog.Trace/Activity/OtlpHelpers.cs +++ b/tracer/src/Datadog.Trace/Activity/OtlpHelpers.cs @@ -507,7 +507,7 @@ internal static void AgentSetOtlpTag(Span span, string key, string? value, bool case "operation.name": if (setKnownValues) { - span.OperationName = value?.ToLowerInvariant(); + span.OperationName = StringUtil.ToLowerInvariant(value); } break; diff --git a/tracer/src/Datadog.Trace/Agent/OtlpSpanStatsSerializer.cs b/tracer/src/Datadog.Trace/Agent/OtlpSpanStatsSerializer.cs index 129113149c96..f8d5f4230ceb 100644 --- a/tracer/src/Datadog.Trace/Agent/OtlpSpanStatsSerializer.cs +++ b/tracer/src/Datadog.Trace/Agent/OtlpSpanStatsSerializer.cs @@ -647,7 +647,7 @@ private static string CanonicalizeSpanKind(string spanKind) name = name.Substring(11); } - name = name.ToUpperInvariant(); + name = StringUtil.ToUpperInvariant(name); // Accept common single-L alias and compact form if (name == "CANCELED") diff --git a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs index 9842973e2e6d..35a528d2c7ef 100644 --- a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs +++ b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs @@ -506,7 +506,7 @@ public Dictionary GetResponseHeadersForWaf() var keyForDictionary = originalKey ?? string.Empty; if (!keyForDictionary.Equals("cookie", StringComparison.OrdinalIgnoreCase)) { - keyForDictionary = keyForDictionary.ToLowerInvariant(); + keyForDictionary = StringUtil.ToLowerInvariant(keyForDictionary); if (!headersDic.ContainsKey(keyForDictionary)) { headersDic.Add(keyForDictionary, GetHeaderAsArray(response.Headers.GetValues(originalKey))); diff --git a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.cs b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.cs index 257b06d577ae..d873cde9fe7e 100644 --- a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.cs +++ b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.cs @@ -231,7 +231,7 @@ private void SetErrorInformation(bool isRasp, IResult? result) var currentKey = key ?? string.Empty; if (!currentKey.Equals("cookie", StringComparison.OrdinalIgnoreCase)) { - currentKey = currentKey.ToLowerInvariant(); + currentKey = StringUtil.ToLowerInvariant(currentKey); var value = getHeaderValue(collection, currentKey); #if NETCOREAPP if (!headersDic.TryAdd(currentKey, value)) diff --git a/tracer/src/Datadog.Trace/AppSec/Waf/ConfigurationState.cs b/tracer/src/Datadog.Trace/AppSec/Waf/ConfigurationState.cs index ee3b29706bd0..95f503820fbd 100644 --- a/tracer/src/Datadog.Trace/AppSec/Waf/ConfigurationState.cs +++ b/tracer/src/Datadog.Trace/AppSec/Waf/ConfigurationState.cs @@ -390,7 +390,7 @@ private void ApplyAsmFeatures(bool appsecCurrentlyEnabled) } else { - AutoUserInstrumMode = autoUserInstrumMode?.Mode?.ToLowerInvariant(); + AutoUserInstrumMode = StringUtil.ToLowerInvariant(autoUserInstrumMode?.Mode); } } diff --git a/tracer/src/Datadog.Trace/AspNet/TracingHttpModule.cs b/tracer/src/Datadog.Trace/AspNet/TracingHttpModule.cs index db4c9369a565..926b04bdfac6 100644 --- a/tracer/src/Datadog.Trace/AspNet/TracingHttpModule.cs +++ b/tracer/src/Datadog.Trace/AspNet/TracingHttpModule.cs @@ -90,11 +90,11 @@ private static string BuildResourceName(Tracer tracer, HttpRequest httpRequest) if (url is not null) { var path = UriHelpers.GetCleanUriPath(url, httpRequest.ApplicationPath); - return $"{httpRequest.HttpMethod.ToUpperInvariant()} {path.ToLowerInvariant()}"; + return $"{StringUtil.ToUpperInvariant(httpRequest.HttpMethod)} {StringUtil.ToLowerInvariant(path)}"; } else { - return $"{httpRequest.HttpMethod.ToUpperInvariant()}"; + return $"{StringUtil.ToUpperInvariant(httpRequest.HttpMethod)}"; } } @@ -182,7 +182,7 @@ private void OnBeginRequest(object sender, EventArgs eventArgs) string host = requestHeaders.Get("Host"); var userAgent = requestHeaders.Get(HttpHeaderNames.UserAgent); - string httpMethod = httpRequest.HttpMethod.ToUpperInvariant(); + string httpMethod = StringUtil.ToUpperInvariant(httpRequest.HttpMethod); var url = httpContext.Request.GetUrlForSpan(tracer.TracerManager.QueryStringManager, tracer.Settings.BypassHttpRequestUrlCachingEnabled); var tags = new AspNetRequestTags(); scope = tracer.StartActiveInternal(_requestOperationName, extractedContext.SpanContext, tags: tags); diff --git a/tracer/src/Datadog.Trace/Ci/CiEnvironment/BuildkiteEnvironmentValues.cs b/tracer/src/Datadog.Trace/Ci/CiEnvironment/BuildkiteEnvironmentValues.cs index 747fe94df0c6..c9b407dd7c7e 100644 --- a/tracer/src/Datadog.Trace/Ci/CiEnvironment/BuildkiteEnvironmentValues.cs +++ b/tracer/src/Datadog.Trace/Ci/CiEnvironment/BuildkiteEnvironmentValues.cs @@ -49,7 +49,7 @@ protected override void OnInitialize(IGitInfo gitInfo) { if (envvar?.Key is string key && key.StartsWith(PlatformKeys.Ci.Buildkite.AgentMetadata, StringComparison.OrdinalIgnoreCase)) { - var name = key.Substring(PlatformKeys.Ci.Buildkite.AgentMetadata.Length).ToLowerInvariant(); + var name = StringUtil.ToLowerInvariant(key.Substring(PlatformKeys.Ci.Buildkite.AgentMetadata.Length)); var value = envvar?.Value?.ToString(); lstNodeLabels.Add($"{name}:{value}"); } diff --git a/tracer/src/Datadog.Trace/Ci/CiEnvironment/JenkinsEnvironmentValues.cs b/tracer/src/Datadog.Trace/Ci/CiEnvironment/JenkinsEnvironmentValues.cs index fa33fbcfae2b..f453d068017d 100644 --- a/tracer/src/Datadog.Trace/Ci/CiEnvironment/JenkinsEnvironmentValues.cs +++ b/tracer/src/Datadog.Trace/Ci/CiEnvironment/JenkinsEnvironmentValues.cs @@ -62,7 +62,7 @@ protected override void OnInitialize(IGitInfo gitInfo) var jobNameParts = jobNameNoBranch.Split('/'); if (jobNameParts.Length > 1 && jobNameParts[1].Contains("=")) { - var configsStr = jobNameParts[1].ToLowerInvariant().Trim(); + var configsStr = StringUtil.ToLowerInvariant(jobNameParts[1]).Trim(); var configsKeyValue = configsStr.Split(','); foreach (var configKeyValue in configsKeyValue) { diff --git a/tracer/src/Datadog.Trace/Ci/Coverage/Backfill/CoverageBackfillCommandLine.cs b/tracer/src/Datadog.Trace/Ci/Coverage/Backfill/CoverageBackfillCommandLine.cs index 49c152c8518b..bd1f8d13e6bb 100644 --- a/tracer/src/Datadog.Trace/Ci/Coverage/Backfill/CoverageBackfillCommandLine.cs +++ b/tracer/src/Datadog.Trace/Ci/Coverage/Backfill/CoverageBackfillCommandLine.cs @@ -4738,7 +4738,7 @@ private bool CoverletOutputDirectoryWritesLineCapableReportPath(string outputPat continue; } - var fileName = $"coverage.{normalizedFormat.ToLowerInvariant()}.xml"; + var fileName = $"coverage.{StringUtil.ToLowerInvariant(normalizedFormat)}.xml"; if (CoverletOutputPathsEqual(Path.Combine(outputPath, fileName), reportPath) || CoverletOutputDirectoryWithTargetFrameworkReferencesReportPath(outputPath, fileName, reportPath)) { @@ -4840,7 +4840,7 @@ private bool CoverletOutputFileWritesLineCapableReportPath(string outputPath, st continue; } - var extension = $".{normalizedFormat.ToLowerInvariant()}.xml"; + var extension = $".{StringUtil.ToLowerInvariant(normalizedFormat)}.xml"; if (CoverletOutputPathsEqual($"{outputPath}{extension}", reportPath) || CoverletOutputFileWithTargetFrameworkReferencesReportPath(outputPath, extension, reportPath)) { diff --git a/tracer/src/Datadog.Trace/Ci/GitCommandHelper.cs b/tracer/src/Datadog.Trace/Ci/GitCommandHelper.cs index 6f85e9982869..b315a50c4d22 100644 --- a/tracer/src/Datadog.Trace/Ci/GitCommandHelper.cs +++ b/tracer/src/Datadog.Trace/Ci/GitCommandHelper.cs @@ -69,7 +69,7 @@ internal static class GitCommandHelper lock (Hasher) { var hash = Hasher.ComputeHash(Encoding.UTF8.GetBytes(arguments)); - cacheKey = Path.Combine(cacheFolder, BitConverter.ToString(hash).ToLowerInvariant() + ".json"); + cacheKey = Path.Combine(cacheFolder, StringUtil.ToLowerInvariant(BitConverter.ToString(hash)) + ".json"); } if (File.Exists(cacheKey)) diff --git a/tracer/src/Datadog.Trace/Ci/Net/FileTestOptimizationClient.cs b/tracer/src/Datadog.Trace/Ci/Net/FileTestOptimizationClient.cs index 725dd76eee23..bd8e73cb4fbb 100644 --- a/tracer/src/Datadog.Trace/Ci/Net/FileTestOptimizationClient.cs +++ b/tracer/src/Datadog.Trace/Ci/Net/FileTestOptimizationClient.cs @@ -39,7 +39,7 @@ internal FileTestOptimizationClient(ITestOptimizationClient testOptimizationClie lock (Hasher) { var hash = Hasher.ComputeHash(Encoding.UTF8.GetBytes(salt)); - salt = BitConverter.ToString(hash).ToLowerInvariant(); + salt = StringUtil.ToLowerInvariant(BitConverter.ToString(hash)); } var runFolder = CoverageBackfillDataStore.GetOrCreateRunFolder(testOptimization); diff --git a/tracer/src/Datadog.Trace/Ci/Propagators/DictionaryGetterAndSetter.cs b/tracer/src/Datadog.Trace/Ci/Propagators/DictionaryGetterAndSetter.cs index 7802924edbe0..dbb1ceb2a068 100644 --- a/tracer/src/Datadog.Trace/Ci/Propagators/DictionaryGetterAndSetter.cs +++ b/tracer/src/Datadog.Trace/Ci/Propagators/DictionaryGetterAndSetter.cs @@ -15,10 +15,9 @@ namespace Datadog.Trace.Propagators; internal readonly struct DictionaryGetterAndSetter : ICarrierGetter, ICarrierSetter { - public static readonly Func EnvironmentVariableKeyProcessor = key => key - .Replace(".", "_") - .Replace("-", "_") - .ToUpperInvariant(); + public static readonly Func EnvironmentVariableKeyProcessor = key => StringUtil.ToUpperInvariant( + key.Replace(".", "_") + .Replace("-", "_")); private readonly Func? _keyProcessor; diff --git a/tracer/src/Datadog.Trace/Ci/Test.cs b/tracer/src/Datadog.Trace/Ci/Test.cs index ce4ff133e155..fe001f6ecc5e 100644 --- a/tracer/src/Datadog.Trace/Ci/Test.cs +++ b/tracer/src/Datadog.Trace/Ci/Test.cs @@ -55,7 +55,7 @@ internal Test(TestSuite suite, string name, DateTimeOffset? startDate, TraceId t var tags = new TestSpanTags(Suite.Tags, name); var tracer = Tracer.Instance; var span = tracer.StartSpan( - StringUtil.IsNullOrEmpty(module.Framework) ? "test" : $"{module.Framework!.ToLowerInvariant()}.test", + StringUtil.IsNullOrEmpty(module.Framework) ? "test" : $"{StringUtil.ToLowerInvariant(module.Framework)}.test", tags: tags, startTime: startDate, traceId: traceId, diff --git a/tracer/src/Datadog.Trace/Ci/TestModule.cs b/tracer/src/Datadog.Trace/Ci/TestModule.cs index 9e67866b32c5..c5e1c3788a8d 100644 --- a/tracer/src/Datadog.Trace/Ci/TestModule.cs +++ b/tracer/src/Datadog.Trace/Ci/TestModule.cs @@ -185,7 +185,7 @@ _testOptimization.SkippableFeature is { } sf tags.TestsSkipped = "false"; var span = Tracer.Instance.StartSpan( - string.IsNullOrEmpty(framework) ? "test_module" : $"{framework!.ToLowerInvariant()}.test_module", + string.IsNullOrEmpty(framework) ? "test_module" : $"{StringUtil.ToLowerInvariant(framework)}.test_module", tags: tags, startTime: startDate); TelemetryFactory.Metrics.RecordCountSpanCreated(MetricTags.IntegrationName.CiAppManual); diff --git a/tracer/src/Datadog.Trace/Ci/TestSession.cs b/tracer/src/Datadog.Trace/Ci/TestSession.cs index 60ef7ad3a918..90b90ab4c402 100644 --- a/tracer/src/Datadog.Trace/Ci/TestSession.cs +++ b/tracer/src/Datadog.Trace/Ci/TestSession.cs @@ -102,7 +102,7 @@ _testOptimization.SkippableFeature is { } sf tags.SetCIEnvironmentValues(ciValues); var span = Tracer.Instance.StartSpan( - string.IsNullOrEmpty(framework) ? "test_session" : $"{framework!.ToLowerInvariant()}.test_session", + string.IsNullOrEmpty(framework) ? "test_session" : $"{StringUtil.ToLowerInvariant(framework)}.test_session", tags: tags, startTime: startDate); TelemetryFactory.Metrics.RecordCountSpanCreated(MetricTags.IntegrationName.CiAppManual); diff --git a/tracer/src/Datadog.Trace/Ci/TestSuite.cs b/tracer/src/Datadog.Trace/Ci/TestSuite.cs index 749e45d1e5c4..e936ff73aa4d 100644 --- a/tracer/src/Datadog.Trace/Ci/TestSuite.cs +++ b/tracer/src/Datadog.Trace/Ci/TestSuite.cs @@ -38,7 +38,7 @@ internal TestSuite(TestModule module, string name, DateTimeOffset? startDate) var tags = new TestSuiteSpanTags(module.Tags, name); var span = Tracer.Instance.StartSpan( - string.IsNullOrEmpty(module.Framework) ? "test_suite" : $"{module.Framework!.ToLowerInvariant()}.test_suite", + string.IsNullOrEmpty(module.Framework) ? "test_suite" : $"{StringUtil.ToLowerInvariant(module.Framework)}.test_suite", tags: tags, startTime: startDate); TelemetryFactory.Metrics.RecordCountSpanCreated(MetricTags.IntegrationName.CiAppManual); diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeAsyncIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeAsyncIntegration.cs index bd42f7178f13..f70185d72645 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeAsyncIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeAsyncIntegration.cs @@ -81,7 +81,7 @@ internal static TResponse OnAsyncMethodEnd(TTarget instance, { if (state.State is IExecutionContext { RequestContext.Request: { } request }) { - tags.HttpMethod = request.HttpMethod?.ToUpperInvariant(); + tags.HttpMethod = StringUtil.ToUpperInvariant(request.HttpMethod); if (tags.HttpUrl is null) { var uri = request.Endpoint; diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeSyncIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeSyncIntegration.cs index aaf1e6b0246d..914bbfc96298 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeSyncIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/SDK/RuntimePipelineInvokeSyncIntegration.cs @@ -81,7 +81,7 @@ internal static CallTargetReturn OnMethodEnd // the + 1 could be dangerous and cause IndexOutOfRangeException, but this shouldn't happen // a period should never be the last character in a namespace - namespaceName.Substring(namespaceName.LastIndexOf('.') + 1).ToLowerInvariant(), + StringUtil.ToLowerInvariant(namespaceName.Substring(namespaceName.LastIndexOf('.') + 1)), _ when commandTypeName == commandSuffix => - namespaceName.ToLowerInvariant(), + StringUtil.ToLowerInvariant(namespaceName), _ when commandTypeName.EndsWith(commandSuffix) => - commandTypeName.Substring(0, commandTypeName.Length - commandSuffix.Length).ToLowerInvariant(), - _ => commandTypeName.ToLowerInvariant() + StringUtil.ToLowerInvariant(commandTypeName.Substring(0, commandTypeName.Length - commandSuffix.Length)), + _ => StringUtil.ToLowerInvariant(commandTypeName) }; return true; } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetMvcIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetMvcIntegration.cs index db47dcbe7ddf..5226fd4a5bb5 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetMvcIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetMvcIntegration.cs @@ -65,7 +65,7 @@ internal static Scope CreateScope(ControllerContextStruct controllerContext) var newResourceNamesEnabled = tracer.Settings.RouteTemplateResourceNamesEnabled; string host = httpContext.Request.Headers.Get("Host"); var userAgent = httpContext.Request.Headers.Get(HttpHeaderNames.UserAgent); - string httpMethod = httpContext.Request.HttpMethod.ToUpperInvariant(); + string httpMethod = StringUtil.ToUpperInvariant(httpContext.Request.HttpMethod); var url = httpContext.Request.GetUrlForSpan(tracer.TracerManager.QueryStringManager); string resourceName = null; @@ -115,15 +115,15 @@ internal static Scope CreateScope(ControllerContextStruct controllerContext) else { // just grab area/controller/action directly - areaName = (routeValues?.GetValueOrDefault("area") as string)?.ToLowerInvariant(); - controllerName = (routeValues?.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); - actionName = (routeValues?.GetValueOrDefault("action") as string)?.ToLowerInvariant(); + areaName = StringUtil.ToLowerInvariant(routeValues?.GetValueOrDefault("area") as string); + controllerName = StringUtil.ToLowerInvariant(routeValues?.GetValueOrDefault("controller") as string); + actionName = StringUtil.ToLowerInvariant(routeValues?.GetValueOrDefault("action") as string); } if (string.IsNullOrEmpty(resourceName) && httpContext.Request.Url != null) { var cleanUri = UriHelpers.GetCleanUriPath(httpContext.Request.Url, httpContext.Request.ApplicationPath); - resourceName = $"{httpMethod} {cleanUri.ToLowerInvariant()}"; + resourceName = $"{httpMethod} {StringUtil.ToLowerInvariant(cleanUri)}"; } if (string.IsNullOrEmpty(resourceName)) diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetResourceNameHelper.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetResourceNameHelper.cs index 6f85d5479de4..71b42126d918 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetResourceNameHelper.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetResourceNameHelper.cs @@ -59,7 +59,7 @@ public static string CalculateResourceName( sb.Append('/'); } - sb.Append(routeTemplate.ToLowerInvariant()); + sb.Append(StringUtil.ToLowerInvariant(routeTemplate)); areaName = null; controllerName = null; @@ -69,17 +69,17 @@ public static string CalculateResourceName( { if (string.Equals(kvp.Key, "action", StringComparison.OrdinalIgnoreCase) && kvp.Value is string action) { - actionName = action.ToLowerInvariant(); + actionName = StringUtil.ToLowerInvariant(action); sb.Replace("{action}", actionName); } else if (string.Equals(kvp.Key, "controller", StringComparison.OrdinalIgnoreCase) && kvp.Value is string controller) { - controllerName = controller.ToLowerInvariant(); + controllerName = StringUtil.ToLowerInvariant(controller); sb.Replace("{controller}", controllerName); } else if (string.Equals(kvp.Key, "area", StringComparison.OrdinalIgnoreCase) && kvp.Value is string area) { - areaName = area.ToLowerInvariant(); + areaName = StringUtil.ToLowerInvariant(area); sb.Replace("{area}", areaName); } else if (expandRouteTemplates) @@ -129,7 +129,7 @@ private static void ReplaceValue(StringBuilder sb, string key, string? value, Re else { sb.Remove(startIndex, length); - sb.Insert(startIndex, value?.ToLowerInvariant() ?? string.Empty); + sb.Insert(startIndex, StringUtil.ToLowerInvariant(value) ?? string.Empty); } } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetWebApi2Integration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetWebApi2Integration.cs index b36285183514..ce26e9bcace0 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetWebApi2Integration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AspNet/AspNetWebApi2Integration.cs @@ -130,7 +130,7 @@ internal static void UpdateSpan(IHttpControllerContext controllerContext, Span s string host = request.Headers.Host ?? string.Empty; var userAgent = request.Headers.UserAgent?.ToString() ?? string.Empty; - string method = request.Method.Method?.ToUpperInvariant() ?? "GET"; + string method = StringUtil.ToUpperInvariant(request.Method.Method) ?? "GET"; string route = null; try { @@ -183,9 +183,9 @@ internal static void UpdateSpan(IHttpControllerContext controllerContext, Span s // get the route values. Not sure how this is possible, but is preexisting behaviour try { - area = (routeValues.GetValueOrDefault("area") as string)?.ToLowerInvariant(); - controller = (routeValues.GetValueOrDefault("controller") as string)?.ToLowerInvariant(); - action = (routeValues.GetValueOrDefault("action") as string)?.ToLowerInvariant(); + area = StringUtil.ToLowerInvariant(routeValues.GetValueOrDefault("area") as string); + controller = StringUtil.ToLowerInvariant(routeValues.GetValueOrDefault("controller") as string); + action = StringUtil.ToLowerInvariant(routeValues.GetValueOrDefault("action") as string); } catch { diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AwsApiGatewaySpanFactory.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AwsApiGatewaySpanFactory.cs index c8931d3f8c11..ee0579d8cb99 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AwsApiGatewaySpanFactory.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AwsApiGatewaySpanFactory.cs @@ -24,7 +24,7 @@ internal sealed class AwsApiGatewaySpanFactory : IInferredSpanFactory { try { - var resourceUrl = data.Path is null ? string.Empty : UriHelpers.GetCleanUriPath(data.Path).ToLowerInvariant(); + var resourceUrl = data.Path is null ? string.Empty : StringUtil.ToLowerInvariant(UriHelpers.GetCleanUriPath(data.Path)); var tags = new InferredProxyTags { diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AzureApiManagementSpanFactory.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AzureApiManagementSpanFactory.cs index 9b1bf5c09eff..b0672d7274fd 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AzureApiManagementSpanFactory.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/AzureApiManagementSpanFactory.cs @@ -25,7 +25,7 @@ internal sealed class AzureApiManagementSpanFactory : IInferredSpanFactory { try { - var resourceUrl = data.Path is null ? string.Empty : UriHelpers.GetCleanUriPath(data.Path).ToLowerInvariant(); + var resourceUrl = data.Path is null ? string.Empty : StringUtil.ToLowerInvariant(UriHelpers.GetCleanUriPath(data.Path)); var tags = new InferredProxyTags { diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/InferredProxyData.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/InferredProxyData.cs index d35a30acc4ba..4bc2bcf8b32c 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/InferredProxyData.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Proxy/InferredProxyData.cs @@ -31,7 +31,7 @@ internal readonly struct InferredProxyData(string proxyName, DateTimeOffset star public readonly string? DomainName = domainName; // x-dd-proxy-httpmethod - public readonly string? HttpMethod = httpMethod?.ToUpperInvariant(); + public readonly string? HttpMethod = StringUtil.ToUpperInvariant(httpMethod); // x-dd-proxy-path public readonly string? Path = path; diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Remoting/Client/HttpProcessAndSendIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Remoting/Client/HttpProcessAndSendIntegration.cs index 3b35d87210de..18990692238c 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Remoting/Client/HttpProcessAndSendIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Remoting/Client/HttpProcessAndSendIntegration.cs @@ -80,7 +80,7 @@ internal static CallTargetReturn OnMethodEnd(TTarget return new CallTargetReturn(returnValue); } - var requestMethod = request.Method.ToUpperInvariant(); + var requestMethod = StringUtil.ToUpperInvariant(request.Method); if (requestUri != null) { diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Testing/DotnetTest/DotnetCommon.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Testing/DotnetTest/DotnetCommon.cs index e9eea378c657..58a4009d9357 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Testing/DotnetTest/DotnetCommon.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Testing/DotnetTest/DotnetCommon.cs @@ -108,7 +108,7 @@ internal static bool IsDataCollectorDomain #if NETCOREAPP return (_isDataCollectorDomainCache = DomainMetadata.Instance.AppDomainName.Contains("datacollector", StringComparison.OrdinalIgnoreCase)).Value; #else - return (_isDataCollectorDomainCache = DomainMetadata.Instance.AppDomainName.ToLowerInvariant().Contains("datacollector")).Value; + return (_isDataCollectorDomainCache = StringUtil.ToLowerInvariant(DomainMetadata.Instance.AppDomainName).Contains("datacollector")).Value; #endif } } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Wcf/WcfCommon.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Wcf/WcfCommon.cs index bd893faa1ea5..f5ccb2874936 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Wcf/WcfCommon.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/Wcf/WcfCommon.cs @@ -76,7 +76,7 @@ internal static class WcfCommon // we're using an http transport host = webHeaderCollection[HttpRequestHeader.Host]; userAgent = webHeaderCollection[HttpRequestHeader.UserAgent]; - httpMethod = httpRequestPropertyProxy.Method?.ToUpperInvariant(); + httpMethod = StringUtil.ToUpperInvariant(httpRequestPropertyProxy.Method); // try to extract propagated context values from http headers if (tracer.ActiveScope is { } activeScope) diff --git a/tracer/src/Datadog.Trace/ClrProfiler/Helpers/HttpBypassHelper.cs b/tracer/src/Datadog.Trace/ClrProfiler/Helpers/HttpBypassHelper.cs index 79404664c01e..dfbae827833b 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/Helpers/HttpBypassHelper.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/Helpers/HttpBypassHelper.cs @@ -37,7 +37,7 @@ private static bool UriContainsAnyOfSlow(Uri requestUri, string[] substrings) } } #else - var uriString = requestUri.ToString().ToUpperInvariant(); + var uriString = StringUtil.ToUpperInvariant(requestUri.ToString()); for (var index = 0; index < substrings.Length; index++) { diff --git a/tracer/src/Datadog.Trace/ClrProfiler/ScopeFactory.cs b/tracer/src/Datadog.Trace/ClrProfiler/ScopeFactory.cs index 9afb33ef4e5c..0ca2b628e0e7 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/ScopeFactory.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/ScopeFactory.cs @@ -127,7 +127,7 @@ internal static Span CreateInactiveOutboundHttpSpan( string resourceUrl = requestUri != null ? UriHelpers.CleanUri(requestUri, removeScheme: true, tryRemoveIds: true) : null; span.ResourceName = $"{httpMethod} {resourceUrl}"; - tags.HttpMethod = httpMethod?.ToUpperInvariant(); + tags.HttpMethod = StringUtil.ToUpperInvariant(httpMethod); if (requestUri is not null) { tags.HttpUrl = HttpRequestUtils.GetUrl(requestUri, tracer.TracerManager.QueryStringManager); diff --git a/tracer/src/Datadog.Trace/Configuration/ImmutableAzureAppServiceSettings.cs b/tracer/src/Datadog.Trace/Configuration/ImmutableAzureAppServiceSettings.cs index 8c7fda95c942..e73df01f5413 100644 --- a/tracer/src/Datadog.Trace/Configuration/ImmutableAzureAppServiceSettings.cs +++ b/tracer/src/Datadog.Trace/Configuration/ImmutableAzureAppServiceSettings.cs @@ -158,7 +158,7 @@ private static bool ShouldSkipClientSpanWithinFunctions(Scope? scope) return null; } - return $"/subscriptions/{subscriptionId}/resourcegroups/{resourceGroup}/providers/microsoft.web/sites/{siteName}".ToLowerInvariant(); + return StringUtil.ToLowerInvariant($"/subscriptions/{subscriptionId}/resourcegroups/{resourceGroup}/providers/microsoft.web/sites/{siteName}"); } private static string? GetSubscriptionId(IConfigurationSource source, IConfigurationTelemetry telemetry) diff --git a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs index 139ec44b30e0..20de872c1b3c 100644 --- a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs +++ b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs @@ -550,7 +550,7 @@ not null when string.Equals(value, "otlp", StringComparison.OrdinalIgnoreCase) = .WithKeys(ConfigurationKeys.PropagationBehaviorExtract) .GetAs( defaultValue: new(ExtractBehavior.Continue, "continue"), - converter: x => x.ToLowerInvariant() switch + converter: x => StringUtil.ToLowerInvariant(x) switch { "continue" => ExtractBehavior.Continue, "restart" => ExtractBehavior.Restart, @@ -741,7 +741,7 @@ not null when string.Equals(value, "otlp", StringComparison.OrdinalIgnoreCase) = } HttpClientExcludedUrlSubstrings = !string.IsNullOrEmpty(urlSubstringSkips) - ? TrimSplitString(urlSubstringSkips.ToUpperInvariant(), commaSeparator) + ? TrimSplitString(StringUtil.ToUpperInvariant(urlSubstringSkips), commaSeparator) : []; var dbmPropagationMode = config diff --git a/tracer/src/Datadog.Trace/Datadog.Trace.csproj b/tracer/src/Datadog.Trace/Datadog.Trace.csproj index f855e1c35207..c252944976e1 100644 --- a/tracer/src/Datadog.Trace/Datadog.Trace.csproj +++ b/tracer/src/Datadog.Trace/Datadog.Trace.csproj @@ -114,6 +114,7 @@ + Never diff --git a/tracer/src/Datadog.Trace/ExtensionMethods/StringExtensions.cs b/tracer/src/Datadog.Trace/ExtensionMethods/StringExtensions.cs index 53364a9ce3ad..c68813bed7ff 100644 --- a/tracer/src/Datadog.Trace/ExtensionMethods/StringExtensions.cs +++ b/tracer/src/Datadog.Trace/ExtensionMethods/StringExtensions.cs @@ -114,7 +114,7 @@ public static bool TryConvertToNormalizedTagName(this string? value, bool normal } var sb = StringBuilderCache.Acquire(trimmedValue.Length); - sb.Append(trimmedValue.ToLowerInvariant()); + sb.Append(StringUtil.ToLowerInvariant(trimmedValue)); for (var x = 0; x < sb.Length; x++) { diff --git a/tracer/src/Datadog.Trace/FeatureFlags/Agentless/AgentlessEndpoint.cs b/tracer/src/Datadog.Trace/FeatureFlags/Agentless/AgentlessEndpoint.cs index 08868b22573d..64bda187b754 100644 --- a/tracer/src/Datadog.Trace/FeatureFlags/Agentless/AgentlessEndpoint.cs +++ b/tracer/src/Datadog.Trace/FeatureFlags/Agentless/AgentlessEndpoint.cs @@ -99,7 +99,7 @@ public static bool TryCreate(string? site, string? baseUrl, [NotNullWhen(true)] } } - var managedHost = ManagedHostPrefix + trimmedSite.ToLowerInvariant(); + var managedHost = ManagedHostPrefix + StringUtil.ToLowerInvariant(trimmedSite); if (!Uri.TryCreate($"https://{managedHost}{DefaultPath}", UriKind.Absolute, out var managedUri)) { diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs index 1082a62da2ba..20b20f78f193 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs @@ -540,24 +540,31 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => +#if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); +#else + value.ToUpperInvariant(); +#endif } } diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs index 1082a62da2ba..20b20f78f193 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs @@ -540,24 +540,31 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => +#if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); +#else + value.ToUpperInvariant(); +#endif } } diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs index 1082a62da2ba..20b20f78f193 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs @@ -540,24 +540,31 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => +#if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); +#else + value.ToUpperInvariant(); +#endif } } diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs index 1082a62da2ba..20b20f78f193 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/IntegrationNameToKeys.g.cs @@ -540,24 +540,31 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => +#if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); +#else + value.ToUpperInvariant(); +#endif } } diff --git a/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs b/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs index e038ce536c79..6634da2e8d13 100644 --- a/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs +++ b/tracer/src/Datadog.Trace/Iast/Aspects/System/StringAspects.cs @@ -969,7 +969,9 @@ public static string ToUpper(string target, global::System.Globalization.Culture [AspectMethodReplace("System.String::ToUpperInvariant()", AspectFilter.StringLiteral_0)] public static string ToUpperInvariant(string target) { +#pragma warning disable RS0030 // This aspect replaces the BCL method, so it must call it directly var result = target.ToUpperInvariant(); +#pragma warning restore RS0030 try { PropagationModuleImpl.PropagateTaint(target, result); @@ -1033,7 +1035,9 @@ public static string ToLower(string target, global::System.Globalization.Culture [AspectMethodReplace("System.String::ToLowerInvariant()", AspectFilter.StringLiteral_0)] public static string ToLowerInvariant(string target) { +#pragma warning disable RS0030 // This aspect replaces the BCL method, so it must call it directly var result = target.ToLowerInvariant(); +#pragma warning restore RS0030 try { PropagationModuleImpl.PropagateTaint(target, result); diff --git a/tracer/src/Datadog.Trace/Iast/ReturnedHeadersAnalyzer.cs b/tracer/src/Datadog.Trace/Iast/ReturnedHeadersAnalyzer.cs index dcf9186ce208..eab8f0cf9b9a 100644 --- a/tracer/src/Datadog.Trace/Iast/ReturnedHeadersAnalyzer.cs +++ b/tracer/src/Datadog.Trace/Iast/ReturnedHeadersAnalyzer.cs @@ -300,7 +300,7 @@ private static bool IsHtmlResponse(string contentTypeValue) #if NETCOREAPP return contentTypeValue.Contains("text/html", StringComparison.OrdinalIgnoreCase) || contentTypeValue.Contains("application/xhtml+xml", StringComparison.OrdinalIgnoreCase); #else - var contentType = contentTypeValue.ToLowerInvariant(); + var contentType = StringUtil.ToLowerInvariant(contentTypeValue); return contentType.Contains("text/html") || contentType.Contains("application/xhtml+xml"); #endif } diff --git a/tracer/src/Datadog.Trace/Iast/Settings/IastSettings.cs b/tracer/src/Datadog.Trace/Iast/Settings/IastSettings.cs index 1ec545c3f182..605794912ef7 100644 --- a/tracer/src/Datadog.Trace/Iast/Settings/IastSettings.cs +++ b/tracer/src/Datadog.Trace/Iast/Settings/IastSettings.cs @@ -5,6 +5,7 @@ #nullable enable +using System; using Datadog.Trace.Configuration; using Datadog.Trace.Configuration.ConfigurationSources.Telemetry; using Datadog.Trace.Configuration.Telemetry; @@ -82,7 +83,7 @@ public IastSettings(IConfigurationSource source, IConfigurationTelemetry telemet .WithKeys(ConfigurationKeys.Iast.TelemetryVerbosity) .GetAs( defaultValue: new(IastMetricsVerbosityLevel.Information, "information"), - converter: value => value.ToLowerInvariant() switch + converter: value => StringUtil.ToLowerInvariant(value) switch { "off" => IastMetricsVerbosityLevel.Off, "debug" => IastMetricsVerbosityLevel.Debug, diff --git a/tracer/src/Datadog.Trace/Logging/DirectSubmission/DirectSubmissionLogLevelExtensions.cs b/tracer/src/Datadog.Trace/Logging/DirectSubmission/DirectSubmissionLogLevelExtensions.cs index 24a3b1dfc326..20209cbfe538 100644 --- a/tracer/src/Datadog.Trace/Logging/DirectSubmission/DirectSubmissionLogLevelExtensions.cs +++ b/tracer/src/Datadog.Trace/Logging/DirectSubmission/DirectSubmissionLogLevelExtensions.cs @@ -4,6 +4,8 @@ // #nullable enable +using System; + namespace Datadog.Trace.Logging.DirectSubmission { internal static class DirectSubmissionLogLevelExtensions @@ -30,7 +32,7 @@ public static string GetName(this DirectSubmissionLogLevel logLevel) }; public static DirectSubmissionLogLevel? Parse(string? value) - => value?.ToUpperInvariant() switch + => StringUtil.ToUpperInvariant(value) switch { "TRACE" => DirectSubmissionLogLevel.Verbose, "VERBOSE" => DirectSubmissionLogLevel.Verbose, diff --git a/tracer/src/Datadog.Trace/Tagging/SpanTagHelper.cs b/tracer/src/Datadog.Trace/Tagging/SpanTagHelper.cs index 6a88f6aa34c7..edc66156e9a3 100644 --- a/tracer/src/Datadog.Trace/Tagging/SpanTagHelper.cs +++ b/tracer/src/Datadog.Trace/Tagging/SpanTagHelper.cs @@ -5,6 +5,7 @@ #nullable enable +using System; using System.Diagnostics.CodeAnalysis; using Datadog.Trace.Util; @@ -68,7 +69,7 @@ internal static bool TryNormalizeTagName( } var sb = StringBuilderCache.Acquire(trimmedValue.Length); - sb.Append(trimmedValue.ToLowerInvariant()); + sb.Append(StringUtil.ToLowerInvariant(trimmedValue)); for (var x = 0; x < sb.Length; x++) { diff --git a/tracer/src/Datadog.Trace/Util/StringUtil.cs b/tracer/src/Datadog.Trace/Util/StringUtil.cs index 19684ea1a541..e0f49ddb9c8a 100644 --- a/tracer/src/Datadog.Trace/Util/StringUtil.cs +++ b/tracer/src/Datadog.Trace/Util/StringUtil.cs @@ -45,8 +45,14 @@ public static bool IsNullOrWhiteSpace([NotNullWhen(false)] string? value) /// Non-allocating alternative to .ToUpperInvariant(). May return the same /// instance (instead of allocating) when no character in actually needs to change. /// - public static string ToUpperInvariant(string value) + [return: NotNullIfNotNull(nameof(value))] + public static string? ToUpperInvariant(string? value) { + if (value is null) + { + return null; + } + foreach (var digit in value) { if (digit > '\x7F' || char.IsBetween(digit, 'a', 'z')) @@ -63,8 +69,14 @@ public static string ToUpperInvariant(string value) /// Non-allocating alternative to .ToLowerInvariant(). May return the same /// instance (instead of allocating) when no character in actually needs to change. /// - public static string ToLowerInvariant(string value) + [return: NotNullIfNotNull(nameof(value))] + public static string? ToLowerInvariant(string? value) { + if (value is null) + { + return null; + } + foreach (var digit in value) { if (digit > '\x7F' || char.IsBetween(digit, 'A', 'Z')) @@ -76,5 +88,15 @@ public static string ToLowerInvariant(string value) return value; } +#else + [return: NotNullIfNotNull(nameof(value))] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string? ToUpperInvariant(string? value) + => value?.ToUpperInvariant(); + + [return: NotNullIfNotNull(nameof(value))] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string? ToLowerInvariant(string? value) + => value?.ToLowerInvariant(); #endif } diff --git a/tracer/test/Datadog.Trace.SourceGenerators.Tests/EnumExtensionsGeneratorTests.cs b/tracer/test/Datadog.Trace.SourceGenerators.Tests/EnumExtensionsGeneratorTests.cs index a1f29643141b..d79ecf21b494 100644 --- a/tracer/test/Datadog.Trace.SourceGenerators.Tests/EnumExtensionsGeneratorTests.cs +++ b/tracer/test/Datadog.Trace.SourceGenerators.Tests/EnumExtensionsGeneratorTests.cs @@ -499,28 +499,35 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => + #if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); + #else + value.ToUpperInvariant(); + #endif } } - + """; var (diagnostics, output) = TestHelpers.GetGeneratedTrees(input); @@ -649,28 +656,35 @@ public static System.Collections.Generic.KeyValuePair GetInteg }; private static System.Collections.Generic.KeyValuePair GetIntegrationEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ENABLED", integrationName), $"DD_{integrationName}_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsEnabledKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_ENABLED", integrationName), $"DD_{integrationName}_ANALYTICS_ENABLED" ]); private static System.Collections.Generic.KeyValuePair GetIntegrationAnalyticsSampleRateKeysFallback(string integrationName) => - new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName.ToUpperInvariant()), + new(string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", ToUpperInvariant(integrationName)), [ string.Format("DD_TRACE_{0}_ANALYTICS_SAMPLE_RATE", integrationName), $"DD_{integrationName}_ANALYTICS_SAMPLE_RATE" ]); + + private static string ToUpperInvariant(string value) => + #if NETFRAMEWORK + System.StringUtil.ToUpperInvariant(value); + #else + value.ToUpperInvariant(); + #endif } } - + """; var (diagnostics, output) = TestHelpers.GetGeneratedTrees(input); diff --git a/tracer/test/Datadog.Trace.Tests/Util/StringUtilTests.cs b/tracer/test/Datadog.Trace.Tests/Util/StringUtilTests.cs index f352bce4d0d2..04e9700bf630 100644 --- a/tracer/test/Datadog.Trace.Tests/Util/StringUtilTests.cs +++ b/tracer/test/Datadog.Trace.Tests/Util/StringUtilTests.cs @@ -70,6 +70,18 @@ public void StringUtil_Flow_Analysis_NoErrors() } } + [Fact] + public void ToUpperInvariant_Null_ReturnsNull() + { + StringUtil.ToUpperInvariant(null).Should().BeNull(); + } + + [Fact] + public void ToLowerInvariant_Null_ReturnsNull() + { + StringUtil.ToLowerInvariant(null).Should().BeNull(); + } + #if NETFRAMEWORK [Theory] [MemberData(nameof(Data.SemanticEquivalenceInputs), MemberType = typeof(Data))]