diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 00000000..405c47fe --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,9 @@ +{ + "features": { + "ghcr.io/devcontainers/features/dotnet:2.5.0": { + "version": "2.5.0", + "resolved": "ghcr.io/devcontainers/features/dotnet@sha256:0fc16547ed4db6d7ff2a9f5981d2b93eb314e568affb9958029ad794f1f9a093", + "integrity": "sha256:0fc16547ed4db6d7ff2a9f5981d2b93eb314e568affb9958029ad794f1f9a093" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ef4cdaf3..38d50b28 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,12 @@ { "name": "Exceptionless.Net", - "image": "mcr.microsoft.com/vscode/devcontainers/dotnetcore:latest", + "image": "mcr.microsoft.com/devcontainers/dotnet:2.2.2-10.0-noble", + "features": { + "ghcr.io/devcontainers/features/dotnet:2.5.0": { + "version": "10.0" + } + }, "extensions": [ "ms-dotnettools.csharp", "streetsidesoftware.code-spell-checker", diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3de28d27..493751cb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,3 +10,24 @@ updates: semver-major-days: 7 semver-minor-days: 7 semver-patch-days: 7 + +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + cooldown: + default-days: 7 + +- package-ecosystem: devcontainers + directory: "/" + schedule: + interval: weekly + cooldown: + default-days: 7 + +- package-ecosystem: dotnet-sdk + directory: "/" + schedule: + interval: daily + cooldown: + default-days: 1 diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index dd6677c7..69d9c91c 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -3,16 +3,19 @@ on: [push, pull_request] env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 +permissions: + contents: read jobs: build: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@v6 with: global-json-file: global.json - name: Build Reason @@ -20,7 +23,7 @@ jobs: - name: Build Version shell: bash run: | - dotnet tool install --global minver-cli --version 6.0.0 + dotnet tool install --global minver-cli --version 7.0.0 version=$(minver --tag-prefix v) echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV - name: Build diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml index 83852de2..79562b59 100644 --- a/.github/workflows/build-osx.yml +++ b/.github/workflows/build-osx.yml @@ -3,16 +3,19 @@ on: [push, pull_request] env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 +permissions: + contents: read jobs: build: runs-on: macOS-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@v6 with: global-json-file: global.json - name: Build Reason @@ -20,7 +23,7 @@ jobs: - name: Build Version shell: bash run: | - dotnet tool install --global minver-cli --version 6.0.0 + dotnet tool install --global minver-cli --version 7.0.0 version=$(minver --tag-prefix v) echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV - name: Build diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 3efed70e..0c083e72 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -3,16 +3,20 @@ on: [push, pull_request] env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 +permissions: + contents: read + packages: write jobs: build: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 + persist-credentials: false - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@v6 with: global-json-file: global.json - name: Build Reason @@ -20,7 +24,7 @@ jobs: - name: Build Version shell: bash run: | - dotnet tool install --global minver-cli --version 6.0.0 + dotnet tool install --global minver-cli --version 7.0.0 version=$(minver --tag-prefix v) echo "MINVERVERSIONOVERRIDE=$version" >> $GITHUB_ENV - name: Build @@ -30,27 +34,24 @@ jobs: - name: Package if: github.event_name != 'pull_request' run: dotnet pack --configuration Release --no-build Exceptionless.Net.Windows.slnx - - name: Install GitHub Package Tool - if: github.event_name != 'pull_request' - run: dotnet tool install gpr -g - name: Publish CI Packages shell: bash if: github.event_name != 'pull_request' run: | - for package in $(find -name "*.nupkg" | grep "minver" -v); do + while IFS= read -r -d '' package; do echo "${0##*/}": Pushing $package... # GitHub - gpr push $package -k ${{ secrets.GITHUB_TOKEN }} || true + dotnet nuget push "$package" --source https://nuget.pkg.github.com/Exceptionless/index.json --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate || true # Feedz (remove once GitHub supports anonymous access) - dotnet nuget push $package --source https://f.feedz.io/exceptionless/exceptionless/nuget --api-key ${{ secrets.FEEDZ_KEY }} --skip-duplicate - done + dotnet nuget push "$package" --source https://f.feedz.io/exceptionless/exceptionless/nuget --api-key ${{ secrets.FEEDZ_KEY }} --skip-duplicate + done < <(find . -name '*.nupkg' ! -path '*minver*' -print0) - name: Publish Release Packages shell: bash if: startsWith(github.ref, 'refs/tags/v') run: | - for package in $(find -name "*.nupkg" | grep "minver" -v); do + while IFS= read -r -d '' package; do echo "${0##*/}": Pushing $package... - dotnet nuget push $package --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_KEY }} --skip-duplicate - done + dotnet nuget push "$package" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_KEY }} --skip-duplicate + done < <(find . -name '*.nupkg' ! -path '*minver*' -print0) diff --git a/build/common.props b/build/common.props index 904a13ee..73381537 100644 --- a/build/common.props +++ b/build/common.props @@ -41,7 +41,7 @@ - + diff --git a/global.json b/global.json index 1e7fdfa9..61bcbdd7 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.100", + "version": "10.0.400", "rollForward": "latestMinor" } } diff --git a/samples/Exceptionless.SampleBlazorWebAssemblyApp/Exceptionless.SampleBlazorWebAssemblyApp.csproj b/samples/Exceptionless.SampleBlazorWebAssemblyApp/Exceptionless.SampleBlazorWebAssemblyApp.csproj index 62ed9c0c..7a75ff24 100644 --- a/samples/Exceptionless.SampleBlazorWebAssemblyApp/Exceptionless.SampleBlazorWebAssemblyApp.csproj +++ b/samples/Exceptionless.SampleBlazorWebAssemblyApp/Exceptionless.SampleBlazorWebAssemblyApp.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/Exceptionless.SampleLambda/Exceptionless.SampleLambda.csproj b/samples/Exceptionless.SampleLambda/Exceptionless.SampleLambda.csproj index 3cab80e0..b4fe70dc 100644 --- a/samples/Exceptionless.SampleLambda/Exceptionless.SampleLambda.csproj +++ b/samples/Exceptionless.SampleLambda/Exceptionless.SampleLambda.csproj @@ -8,8 +8,8 @@ true - - + + diff --git a/samples/Exceptionless.SampleLambdaAspNetCore/Exceptionless.SampleLambdaAspNetCore.csproj b/samples/Exceptionless.SampleLambdaAspNetCore/Exceptionless.SampleLambdaAspNetCore.csproj index fb9f477f..e1705570 100644 --- a/samples/Exceptionless.SampleLambdaAspNetCore/Exceptionless.SampleLambdaAspNetCore.csproj +++ b/samples/Exceptionless.SampleLambdaAspNetCore/Exceptionless.SampleLambdaAspNetCore.csproj @@ -5,8 +5,8 @@ Lambda - - + + diff --git a/src/Exceptionless/Exceptionless.csproj b/src/Exceptionless/Exceptionless.csproj index 21fc7e0d..3fe942bf 100644 --- a/src/Exceptionless/Exceptionless.csproj +++ b/src/Exceptionless/Exceptionless.csproj @@ -34,12 +34,12 @@ - + - + diff --git a/src/Exceptionless/Models/Collections/SettingsDictionary.cs b/src/Exceptionless/Models/Collections/SettingsDictionary.cs index c67ac38e..7bc18c1f 100644 --- a/src/Exceptionless/Models/Collections/SettingsDictionary.cs +++ b/src/Exceptionless/Models/Collections/SettingsDictionary.cs @@ -158,25 +158,6 @@ protected override void OnChanged(ChangedEventArgs> LogLevel value; _minLogLevels.TryRemove(logger, out value); } -} - - foreach (var eventType in _eventTypes) { - if (eventType.Key == null || !_typeSourceEnabled.TryGetValue(eventType.Key, out var sourceDictionary)) - continue; - - if (!args.Item.Key.StartsWith(eventType.Value)) - continue; - - var sourceKeysToRemove = new List(); - foreach (string key in sourceDictionary.Keys) { - if (key.IsPatternMatch(args.Item.Key.Substring(eventType.Value.Length))) - sourceKeysToRemove.Add(key); - } - - foreach (var logger in sourceKeysToRemove) { - bool value; - sourceDictionary.TryRemove(logger, out value); - } } base.OnChanged(args); @@ -202,17 +183,10 @@ public LogLevel GetMinLogLevel(string source) { return minLogLevel; } - private readonly ConcurrentDictionary> _typeSourceEnabled = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); - public bool GetTypeAndSourceEnabled(string type, string source) { if (type == null) return true; - if (source != null && _typeSourceEnabled.TryGetValue(type, out var sourceDictionary)) { - if (sourceDictionary.TryGetValue(source, out bool sourceEnabled)) - return sourceEnabled; - } - return GetTypeAndSourceSetting(type, source, "true").ToBoolean(true); } @@ -222,16 +196,7 @@ private string GetTypeAndSourceSetting(string type, string source, string defaul if (type == null) return defaultValue; - string sourcePrefix; - if (!_typeSourceEnabled.TryGetValue(type, out var sourceDictionary)) { - sourceDictionary = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - _typeSourceEnabled.TryAdd(type, sourceDictionary); - sourcePrefix = "@@" + type + ":"; - - _eventTypes.TryAdd(type, sourcePrefix); - } else { - sourcePrefix = _eventTypes[type]; - } + string sourcePrefix = _eventTypes.GetOrAdd(type, eventType => "@@" + eventType + ":"); // check for exact source match if (TryGetValue(sourcePrefix + source, out string settingValue)) @@ -271,4 +236,4 @@ public static class KnownKeys { public const string LogLevelPrefix = "@@log:"; } } -} \ No newline at end of file +} diff --git a/src/Platforms/Exceptionless.Extensions.Hosting/Exceptionless.Extensions.Hosting.csproj b/src/Platforms/Exceptionless.Extensions.Hosting/Exceptionless.Extensions.Hosting.csproj index 471209f8..7993c4b1 100644 --- a/src/Platforms/Exceptionless.Extensions.Hosting/Exceptionless.Extensions.Hosting.csproj +++ b/src/Platforms/Exceptionless.Extensions.Hosting/Exceptionless.Extensions.Hosting.csproj @@ -15,15 +15,15 @@ - + - + - + diff --git a/src/Platforms/Exceptionless.Extensions.Logging/Exceptionless.Extensions.Logging.csproj b/src/Platforms/Exceptionless.Extensions.Logging/Exceptionless.Extensions.Logging.csproj index 71c28a68..61794fa0 100644 --- a/src/Platforms/Exceptionless.Extensions.Logging/Exceptionless.Extensions.Logging.csproj +++ b/src/Platforms/Exceptionless.Extensions.Logging/Exceptionless.Extensions.Logging.csproj @@ -15,15 +15,15 @@ - + - + - + diff --git a/src/Platforms/Exceptionless.Log4net/Exceptionless.Log4net.csproj b/src/Platforms/Exceptionless.Log4net/Exceptionless.Log4net.csproj index b9c23c6c..5d768a2f 100644 --- a/src/Platforms/Exceptionless.Log4net/Exceptionless.Log4net.csproj +++ b/src/Platforms/Exceptionless.Log4net/Exceptionless.Log4net.csproj @@ -25,7 +25,7 @@ - + diff --git a/src/Platforms/Exceptionless.MessagePack/Exceptionless.MessagePack.csproj b/src/Platforms/Exceptionless.MessagePack/Exceptionless.MessagePack.csproj index b0c47148..b06c9fbb 100644 --- a/src/Platforms/Exceptionless.MessagePack/Exceptionless.MessagePack.csproj +++ b/src/Platforms/Exceptionless.MessagePack/Exceptionless.MessagePack.csproj @@ -25,6 +25,6 @@ - + diff --git a/src/Platforms/Exceptionless.NLog/Exceptionless.NLog.csproj b/src/Platforms/Exceptionless.NLog/Exceptionless.NLog.csproj index 0cef187c..47620cd4 100644 --- a/src/Platforms/Exceptionless.NLog/Exceptionless.NLog.csproj +++ b/src/Platforms/Exceptionless.NLog/Exceptionless.NLog.csproj @@ -25,7 +25,7 @@ - + diff --git a/test/Exceptionless.MessagePack.Tests/Exceptionless.MessagePack.Tests.csproj b/test/Exceptionless.MessagePack.Tests/Exceptionless.MessagePack.Tests.csproj index f30633be..596d794d 100644 --- a/test/Exceptionless.MessagePack.Tests/Exceptionless.MessagePack.Tests.csproj +++ b/test/Exceptionless.MessagePack.Tests/Exceptionless.MessagePack.Tests.csproj @@ -17,9 +17,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Exceptionless.TestHarness/Exceptionless.TestHarness.csproj b/test/Exceptionless.TestHarness/Exceptionless.TestHarness.csproj index e54a4a95..2db77af8 100644 --- a/test/Exceptionless.TestHarness/Exceptionless.TestHarness.csproj +++ b/test/Exceptionless.TestHarness/Exceptionless.TestHarness.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/Exceptionless.Tests/Configuration/ConfigurationTests.cs b/test/Exceptionless.Tests/Configuration/ConfigurationTests.cs index d369f64f..fa7ad195 100644 --- a/test/Exceptionless.Tests/Configuration/ConfigurationTests.cs +++ b/test/Exceptionless.Tests/Configuration/ConfigurationTests.cs @@ -166,21 +166,41 @@ public void CanGetSettingsMultithreaded() { [Fact] public void CanGetLogSettingsMultithreaded() { - var settings = new SettingsDictionary { - { "@@log:*", "Info" }, - { "@@log:Source1", "Trace" }, - { "@@log:Source2", "Debug" }, - { "@@log:Source3", "Info" }, - { "@@log:Source4", "Info" } - }; - - var result = Parallel.For(0, 100, index => { - var level = settings.GetMinLogLevel("Source1"); - _writer.WriteLine("Source1 log level: {0}", level); - }); + for (int attempt = 0; attempt < 1000; attempt++) { + var settings = new SettingsDictionary { + { "@@log:*", "Info" }, + { "@@log:Source1", "Trace" }, + { "@@log:Source2", "Debug" } + }; + + Parallel.For(0, 100, index => { + Assert.Equal(LogLevel.Trace, settings.GetMinLogLevel("Source1")); + Assert.Equal(LogLevel.Debug, settings.GetMinLogLevel("Source2")); + Assert.Equal(LogLevel.Info, settings.GetMinLogLevel("Other")); + }); + } + } - while (!result.IsCompleted) - Thread.Yield(); + [Theory] + [InlineData("usage")] + [InlineData("error")] + public void CanGetEventSettingsMultithreaded(string type) { + for (int attempt = 0; attempt < 1000; attempt++) { + var settings = new SettingsDictionary { + { "@@" + type + ":*", "true" }, + { "@@" + type + ":Source1", "false" } + }; + + Parallel.For(0, 100, index => { + Assert.False(settings.GetTypeAndSourceEnabled(type, "Source1")); + Assert.True(settings.GetTypeAndSourceEnabled(type, "Other")); + }); + + settings["@@" + type + ":Source1"] = "true"; + Assert.True(settings.GetTypeAndSourceEnabled(type, "Source1")); + settings["@@" + type + ":*"] = "false"; + Assert.False(settings.GetTypeAndSourceEnabled(type, "Other")); + } } [Fact] diff --git a/test/Exceptionless.Tests/Exceptionless.Tests.csproj b/test/Exceptionless.Tests/Exceptionless.Tests.csproj index e1c0134d..9f9428df 100644 --- a/test/Exceptionless.Tests/Exceptionless.Tests.csproj +++ b/test/Exceptionless.Tests/Exceptionless.Tests.csproj @@ -39,11 +39,11 @@ - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -61,4 +61,4 @@ PreserveNewest - \ No newline at end of file + diff --git a/test/Exceptionless.Tests/Properties/AssemblyInfo.cs b/test/Exceptionless.Tests/Properties/AssemblyInfo.cs index 3c360368..8b3d919d 100644 --- a/test/Exceptionless.Tests/Properties/AssemblyInfo.cs +++ b/test/Exceptionless.Tests/Properties/AssemblyInfo.cs @@ -1,3 +1,4 @@ -using Xunit; +using Xunit.Sdk; +using Xunit.v3; -[assembly: CollectionBehavior(DisableTestParallelization = true, MaxParallelThreads = 1)] \ No newline at end of file +[assembly: Parallelization(Mode = ParallelMode.None)]