diff --git a/src/OpenTelemetry/Internal/SelfDiagnosticsConfigParser.cs b/src/OpenTelemetry/Internal/SelfDiagnosticsConfigParser.cs index 13ba5fc4df7..abdcef84e0d 100644 --- a/src/OpenTelemetry/Internal/SelfDiagnosticsConfigParser.cs +++ b/src/OpenTelemetry/Internal/SelfDiagnosticsConfigParser.cs @@ -8,7 +8,10 @@ namespace OpenTelemetry.Internal; -internal sealed class SelfDiagnosticsConfigParser +/// +/// Parses the self-diagnostics configuration file. +/// +internal sealed partial class SelfDiagnosticsConfigParser { public const string ConfigFileName = "OTEL_DIAGNOSTICS.json"; private const int FileSizeLowerLimit = 1024; // Lower limit for log file size in KB: 1MB @@ -19,17 +22,20 @@ internal sealed class SelfDiagnosticsConfigParser /// private const int ConfigBufferSize = 4 * 1024; - private static readonly Regex LogDirectoryRegex = new( - @"""LogDirectory""\s*:\s*""(?.*?)""", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private const string LogDirectoryRegexPattern = @"""LogDirectory""\s*:\s*""(?.*?)"""; + private const string FileSizeRegexPattern = @"""FileSize""\s*:\s*(?\d+)"; + private const string LogLevelRegexPattern = @"""LogLevel""\s*:\s*""(?.*?)"""; + private const string FormatMessageRegexPattern = @"""FormatMessage""\s*:\s*(?:""(?.*?)""|(?true|false))"; - private static readonly Regex FileSizeRegex = new( - @"""FileSize""\s*:\s*(?\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); +#if !NET + private static readonly Regex LogDirectoryRegex = new(LogDirectoryRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); - private static readonly Regex LogLevelRegex = new( - @"""LogLevel""\s*:\s*""(?.*?)""", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static readonly Regex FileSizeRegex = new(FileSizeRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); - private static readonly Regex FormatMessageRegex = new( - @"""FormatMessage""\s*:\s*(?:""(?.*?)""|(?true|false))", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static readonly Regex LogLevelRegex = new(LogLevelRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); + + private static readonly Regex FormatMessageRegex = new(FormatMessageRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); +#endif // This class is called in SelfDiagnosticsConfigRefresher.UpdateMemoryMappedFileFromConfiguration // in both main thread and the worker thread. @@ -128,7 +134,7 @@ internal static bool TryParseLogDirectory( string configJson, out string logDirectory) { - var logDirectoryResult = LogDirectoryRegex.Match(configJson); + var logDirectoryResult = GetLogDirectoryRegex().Match(configJson); logDirectory = logDirectoryResult.Groups["LogDirectory"].Value; return logDirectoryResult.Success && !string.IsNullOrWhiteSpace(logDirectory); } @@ -136,7 +142,7 @@ internal static bool TryParseLogDirectory( internal static bool TryParseFileSize(string configJson, out int fileSizeInKB) { fileSizeInKB = 0; - var fileSizeResult = FileSizeRegex.Match(configJson); + var fileSizeResult = GetFileSizeRegex().Match(configJson); return fileSizeResult.Success && int.TryParse(fileSizeResult.Groups["FileSize"].Value, out fileSizeInKB); } @@ -145,7 +151,7 @@ internal static bool TryParseLogLevel( [NotNullWhen(true)] out string? logLevel) { - var logLevelResult = LogLevelRegex.Match(configJson); + var logLevelResult = GetLogLevelRegex().Match(configJson); logLevel = logLevelResult.Groups["LogLevel"].Value; return logLevelResult.Success && !string.IsNullOrWhiteSpace(logLevel); } @@ -153,7 +159,7 @@ internal static bool TryParseLogLevel( internal static bool TryParseFormatMessage(string configJson, out bool formatMessage) { formatMessage = false; - var formatMessageResult = FormatMessageRegex.Match(configJson); + var formatMessageResult = GetFormatMessageRegex().Match(configJson); if (formatMessageResult.Success) { var formatMessageValue = formatMessageResult.Groups["FormatMessage"].Value; @@ -162,4 +168,26 @@ internal static bool TryParseFormatMessage(string configJson, out bool formatMes return true; } + +#if NET + [GeneratedRegex(LogDirectoryRegexPattern, RegexOptions.IgnoreCase)] + private static partial Regex GetLogDirectoryRegex(); + + [GeneratedRegex(FileSizeRegexPattern, RegexOptions.IgnoreCase)] + private static partial Regex GetFileSizeRegex(); + + [GeneratedRegex(LogLevelRegexPattern, RegexOptions.IgnoreCase)] + private static partial Regex GetLogLevelRegex(); + + [GeneratedRegex(FormatMessageRegexPattern, RegexOptions.IgnoreCase)] + private static partial Regex GetFormatMessageRegex(); +#else + private static Regex GetLogDirectoryRegex() => LogDirectoryRegex; + + private static Regex GetFileSizeRegex() => FileSizeRegex; + + private static Regex GetLogLevelRegex() => LogLevelRegex; + + private static Regex GetFormatMessageRegex() => FormatMessageRegex; +#endif } diff --git a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs index 11084ec7f0d..c29bf3238ae 100644 --- a/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs +++ b/src/OpenTelemetry/Metrics/Builder/MeterProviderBuilderSdk.cs @@ -13,11 +13,12 @@ namespace OpenTelemetry.Metrics; /// /// Stores state used to build a . /// -internal sealed class MeterProviderBuilderSdk : MeterProviderBuilder, IMeterProviderBuilder +internal sealed partial class MeterProviderBuilderSdk : MeterProviderBuilder, IMeterProviderBuilder { public const int DefaultMetricLimit = 1000; public const int DefaultCardinalityLimit = 2000; private const string DefaultInstrumentationVersion = "1.0.0.0"; + private const string InstrumentNameRegexPattern = @"^[a-z][a-z0-9-._/]{0,254}$"; private readonly IServiceProvider serviceProvider; private MeterProviderSdk? meterProvider; @@ -32,10 +33,9 @@ public MeterProviderBuilderSdk(IServiceProvider serviceProvider) // fields. See: https://github.com/dotnet/runtime/issues/11571. // Customers: This is not guaranteed to work forever. We may change this // mechanism in the future do this at your own risk. - public static Regex InstrumentNameRegex { get; set; } = new( - @"^[a-z][a-z0-9-._/]{0,254}$", RegexOptions.IgnoreCase | RegexOptions.Compiled); + public static Regex InstrumentNameRegex { get; set; } = GetInstrumentNameRegex(); - public List Instrumentation { get; } = new(); + public List Instrumentation { get; } = []; public ResourceBuilder? ResourceBuilder { get; private set; } @@ -43,11 +43,11 @@ public MeterProviderBuilderSdk(IServiceProvider serviceProvider) public MeterProvider? Provider => this.meterProvider; - public List Readers { get; } = new(); + public List Readers { get; } = []; - public List MeterSources { get; } = new(); + public List MeterSources { get; } = []; - public List> ViewConfigs { get; } = new(); + public List> ViewConfigs { get; } = []; public int MetricLimit { get; private set; } = DefaultMetricLimit; @@ -60,14 +60,7 @@ public MeterProviderBuilderSdk(IServiceProvider serviceProvider) /// The instrument name. /// Boolean indicating if the instrument is valid. public static bool IsValidInstrumentName(string instrumentName) - { - if (string.IsNullOrWhiteSpace(instrumentName)) - { - return false; - } - - return InstrumentNameRegex.IsMatch(instrumentName); - } + => !string.IsNullOrWhiteSpace(instrumentName) && InstrumentNameRegex.IsMatch(instrumentName); /// /// Returns whether the given custom view name is valid according to the specification. @@ -75,16 +68,9 @@ public static bool IsValidInstrumentName(string instrumentName) /// See specification: . /// The view name. /// Boolean indicating if the instrument is valid. - public static bool IsValidViewName(string customViewName) - { - // Only validate the view name in case it's not null. In case it's null, the view name will be the instrument name as per the spec. - if (customViewName == null) - { - return true; - } - - return InstrumentNameRegex.IsMatch(customViewName); - } + public static bool IsValidViewName(string customViewName) => + /* Only validate the view name in case it's not null. In case it's null, the view name will be the instrument name as per the spec. */ + customViewName == null || InstrumentNameRegex.IsMatch(customViewName); public void RegisterProvider(MeterProviderSdk meterProvider) { @@ -208,13 +194,18 @@ public MeterProviderBuilder ConfigureBuilder(Action configure) - { - throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created."); - } + => throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created."); MeterProviderBuilder IDeferredMeterProviderBuilder.Configure(Action configure) => this.ConfigureBuilder(configure); +#if NET + [GeneratedRegex(InstrumentNameRegexPattern, RegexOptions.IgnoreCase)] + private static partial Regex GetInstrumentNameRegex(); +#else + private static Regex GetInstrumentNameRegex() => new(InstrumentNameRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); +#endif + internal readonly struct InstrumentationRegistration { public readonly string Name;