diff --git a/.gitattributes b/.gitattributes index a14b362463..c674496dd8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,7 @@ *.cs text=auto eol=lf diff=csharp *.sln text=auto eol=crlf *.sh eol=lf +*.ps1 eol=lf CHANGELOG.md merge=union diff --git a/.github/actions/buildnative/action.yml b/.github/actions/buildnative/action.yml index 6bc15606d0..ed0a7792ad 100644 --- a/.github/actions/buildnative/action.yml +++ b/.github/actions/buildnative/action.yml @@ -9,26 +9,39 @@ runs: shell: bash run: echo "JAVA_HOME_11=$JAVA_HOME_11_X64" >> $GITHUB_ENV + - uses: actions/cache@v3 + id: cache-c + with: + path: lib/sentrysupplemental/bin + key: supplemental-c-${{ runner.os }}-${{ hashFiles('lib/sentrysupplemental/*.*') }} + - name: Install Ninja + if: ${{ steps.cache-c.outputs.cache-hit != 'true' }} shell: bash run: ${{ runner.os == 'macOS' && 'brew install ninja' || runner.os == 'Windows' && 'choco install ninja' || 'sudo apt-get update && sudo apt-get install ninja-build' }} - name: Build C Project - if: runner.os == 'Linux' || runner.os == 'macOS' + if: ${{ steps.cache-c.outputs.cache-hit != 'true' && (runner.os == 'Linux' || runner.os == 'macOS') }} shell: bash run: lib/sentrysupplemental/build.sh - name: Build C Project - if: runner.os == 'Windows' + if: ${{ steps.cache-c.outputs.cache-hit != 'true' && runner.os == 'Windows' }} shell: cmd run: lib\sentrysupplemental\build.cmd + - uses: actions/cache@v3 + id: cache-android + with: + path: lib/sentry-android-supplemental/bin + key: supplemental-android-${{ runner.os }}-${{ hashFiles('lib/sentry-android-supplemental/*.*') }} + - name: Build Java Project - if: runner.os == 'Linux' || runner.os == 'macOS' + if: ${{ steps.cache-android.outputs.cache-hit != 'true' && runner.os == 'Linux' || runner.os == 'macOS' }} shell: bash run: lib/sentry-android-supplemental/build.sh - name: Build Java Project - if: runner.os == 'Windows' + if: ${{ steps.cache-android.outputs.cache-hit != 'true' && runner.os == 'Windows' }} shell: cmd run: lib\sentry-android-supplemental\build.cmd diff --git a/.github/actions/environment/action.yml b/.github/actions/environment/action.yml index 095ff89560..a9ce261c08 100644 --- a/.github/actions/environment/action.yml +++ b/.github/actions/environment/action.yml @@ -17,38 +17,21 @@ runs: distribution: 'temurin' java-version: '11' - # .NET 3.1 has been removed from all OS due to EOL - # https://github.com/actions/runner-images/issues/7667 - - name: Install .NET 3.1 SDK + # .NET 6 and .NET 8 are not built-in with macos-13 + - name: Install .NET SDK uses: actions/setup-dotnet@v3 with: - dotnet-version: 3.1.x - - - name: Install .NET 7 SDK - uses: actions/setup-dotnet@v3 - with: - dotnet-version: 7.0.203 # switch back to 7.x.x after resolving the below Tizen issue. - - # Workaround for Tizen issue - # See https://github.com/dotnet/sdk/issues/33192 - - name: Pin to .NET SDK 7.0.203 - run: dotnet new globaljson --sdk-version 7.0.203 --force - shell: bash + dotnet-version: | + 6.0.x + 7.0.x + 8.0.x - name: Install .NET Workloads shell: bash run: > dotnet workload install \ maui-android \ - ${{ runner.os == 'macOS' && 'maui-ios maui-maccatalyst maui-windows maui-tizen' || '' }} \ + ${{ runner.os == 'macOS' && 'maui-ios maui-maccatalyst maui-windows' || '' }} \ ${{ runner.os == 'Windows' && 'maui-windows' || '' }} \ - --temp-dir "${{ runner.temp }}" --from-rollback-file rollback.json \ + --temp-dir "${{ runner.temp }}" \ --skip-sign-check - - # We build Sentry.Maui for every supported MAUI target so we can access platform-specific features. - # That includes Tizen. We don't need the entire Tizen SDK, but we do need the base Tizen workload. - # Though we could install it on all runners, we really only need it when building and packing for NuGet, which we do on macOS only. - - name: Install Tizen Workload - if: runner.os == 'macOS' - shell: bash - run: "curl -sSL https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.sh | sudo bash" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 53d360977e..618e883bba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,16 +6,45 @@ on: - main - release/* pull_request: + paths-ignore: + - '**.md' jobs: + build-sentry-native: + name: sentry-native (${{ matrix.os }}) + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu, windows, macos] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: git submodule update --init modules/sentry-native + + - uses: actions/cache@v3 + id: cache + with: + path: src/Sentry/Platforms/Native/sentry-native + key: sentry-native-${{ runner.os }}-${{ hashFiles('scripts/build-sentry-native.ps1') }}-${{ hashFiles('.git/modules/modules/sentry-native/HEAD') }} + enableCrossOsArchive: true + + - run: scripts/build-sentry-native.ps1 + if: steps.cache.outputs.cache-hit != 'true' + shell: pwsh + build: - name: ${{ matrix.os }} + needs: build-sentry-native + name: .NET (${{ matrix.os }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + # Pinning `macos-13` because Microsoft.iOS 16.4 requires Xcode 14.3 which is only built-in in 13 + os: [ubuntu-latest, windows-latest, macos-13] steps: - name: Cancel Previous Runs @@ -29,9 +58,34 @@ jobs: # We use macOS for the final publishing build so we we get all the iOS/macCatalyst targets in the packages - name: Set Environment Variables - if: startsWith(matrix.os, 'macos') && startsWith(github.ref_name, 'release/') + if: startsWith(matrix.os, 'macos') run: echo "CI_PUBLISHING_BUILD=true" >> $GITHUB_ENV + - name: Download sentry-native (Linux) + if: ${{ (env.CI_PUBLISHING_BUILD == 'true') || (runner.os == 'Linux') }} + uses: actions/cache/restore@v3 + with: + path: src/Sentry/Platforms/Native/sentry-native + key: sentry-native-Linux-${{ hashFiles('scripts/build-sentry-native.ps1') }}-${{ hashFiles('.git/modules/modules/sentry-native/HEAD') }} + fail-on-cache-miss: true + + - name: Download sentry-native (macOS) + if: ${{ (env.CI_PUBLISHING_BUILD == 'true') || (runner.os == 'macOS') }} + uses: actions/cache/restore@v3 + with: + path: src/Sentry/Platforms/Native/sentry-native + key: sentry-native-macOS-${{ hashFiles('scripts/build-sentry-native.ps1') }}-${{ hashFiles('.git/modules/modules/sentry-native/HEAD') }} + fail-on-cache-miss: true + + - name: Download sentry-native (Windows) + if: ${{ (env.CI_PUBLISHING_BUILD == 'true') || (runner.os == 'Windows') }} + uses: actions/cache/restore@v3 + with: + path: src/Sentry/Platforms/Native/sentry-native + key: sentry-native-Windows-${{ hashFiles('scripts/build-sentry-native.ps1') }}-${{ hashFiles('.git/modules/modules/sentry-native/HEAD') }} + fail-on-cache-miss: true + enableCrossOsArchive: true + - name: Setup Environment uses: ./.github/actions/environment @@ -42,28 +96,20 @@ jobs: if: runner.os == 'macOS' uses: ./.github/actions/buildcocoasdk + # Only switch to newer xcode after building the Cocoa SDK so that it can keep IPHONEOS_DEPLOYMENT_TARGET=11.0 + - run: sudo xcode-select -s /Applications/Xcode_15.0.1.app + if: startsWith(matrix.os, 'macos') + - name: Restore .NET Dependencies run: dotnet restore Sentry-CI-Build-${{ runner.os }}.slnf --nologo - - name: Build (for non-release branch) - if: env.CI_PUBLISHING_BUILD != 'true' - run: dotnet build Sentry-CI-Build-${{ runner.os }}.slnf -c Release --no-restore --nologo - - - name: Build (for release branch) - if: env.CI_PUBLISHING_BUILD == 'true' - run: dotnet build Sentry-CI-Build-${{ runner.os }}.slnf -c Release --no-restore --nologo -p:CopyLocalLockFileAssemblies=true - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + - name: Build + run: dotnet build Sentry-CI-Build-${{ runner.os }}.slnf -c Release --no-restore --nologo -flp:logfile=build.log -p:CopyLocalLockFileAssemblies=true - name: Test run: dotnet test Sentry-CI-Build-${{ runner.os }}.slnf -c Release --no-build --nologo -l GitHubActions -l "trx;LogFilePrefix=testresults_${{ runner.os }}" - - name: Test symbol upload - uses: getsentry/github-workflows/sentry-cli/integration-test/@v2 - with: - path: test - - - name: Upload Verify Results + - name: Upload build and test outputs if: failure() uses: actions/upload-artifact@v3 with: @@ -72,19 +118,57 @@ jobs: # To save time and disk space, we only create and archive the Nuget packages when we're actually releasing. - - name: Create Nuget Packages (release branch only) + - name: Create Nuget Packages if: env.CI_PUBLISHING_BUILD == 'true' run: dotnet pack Sentry-CI-Build-${{ runner.os }}.slnf -c Release --no-build --nologo - - name: Archive Nuget Packages (release branch only) + - name: Archive Nuget Packages if: env.CI_PUBLISHING_BUILD == 'true' uses: actions/upload-artifact@v3 with: name: ${{ github.sha }} if-no-files-found: error path: | - ${{ github.workspace }}/src/**/Release/*.nupkg - ${{ github.workspace }}/src/**/Release/*.snupkg + src/**/Release/*.nupkg + src/**/Release/*.snupkg + + integration-test: + needs: build + name: Integration test (${{ matrix.os }}) + runs-on: ${{ matrix.os }}-latest + + strategy: + fail-fast: false + matrix: + os: [ubuntu, windows, macos] + + steps: + - uses: actions/checkout@v4 + with: + # We only check out what is absolutely necessary to reduce a chance of local files impacting + # integration tests, e.g. Directory.Build.props, nuget.config, ... + sparse-checkout: | + Directory.Build.props + integration-test + + - name: Fetch Nuget Packages + uses: actions/download-artifact@v3 + with: + name: ${{ github.sha }} + path: src + + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: | + 7.0.x + 8.0.x + + - run: dotnet workload install android maui-android + + - name: Test + uses: getsentry/github-workflows/sentry-cli/integration-test/@v2 + with: + path: integration-test test-solution-filters: runs-on: ubuntu-latest diff --git a/.github/workflows/device-tests-android.yml b/.github/workflows/device-tests-android.yml index ab2a24dcf1..0197641e47 100644 --- a/.github/workflows/device-tests-android.yml +++ b/.github/workflows/device-tests-android.yml @@ -6,6 +6,8 @@ on: - main - release/* pull_request: + paths-ignore: + - '**.md' jobs: build: @@ -26,27 +28,24 @@ jobs: - name: Set Java Version uses: actions/setup-java@v3 with: - distribution: 'temurin' - java-version: '11' + distribution: "temurin" + java-version: "11" + + - name: Setup Environment + uses: ./.github/actions/environment - name: Build Native Dependencies uses: ./.github/actions/buildnative - - name: Install .NET Workloads - run: dotnet workload install maui-android --temp-dir "${{ runner.temp }}" --from-rollback-file rollback.json - - - name: Restore .NET Dependencies - run: dotnet restore test/Sentry.Maui.Device.TestApp --nologo - - name: Build Android Test App - run: dotnet build test/Sentry.Maui.Device.TestApp -c Release -f net7.0-android --no-restore --nologo + run: pwsh ./scripts/device-test.ps1 android -Build - name: Upload Android Test App uses: actions/upload-artifact@v3 with: name: device-test-android if-no-files-found: error - path: test/Sentry.Maui.Device.TestApp/bin/Release/net7.0-android/io.sentry.dotnet.maui.device.testapp-Signed.apk + path: test/Sentry.Maui.Device.TestApp/bin/Release/net7.0-android/android-x64/io.sentry.dotnet.maui.device.testapp-Signed.apk android: needs: [build] @@ -64,13 +63,12 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 steps: - # See https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/ - name: Enable KVM group perms run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm - name: Checkout uses: actions/checkout@v4 @@ -81,9 +79,6 @@ jobs: name: device-test-android path: bin - - name: Install XHarness - run: dotnet tool install Microsoft.DotNet.XHarness.CLI --global --version "1.*-*" - - name: Setup Gradle uses: gradle/gradle-build-action@87a9a15658c426a54dd469d4fc7dc1a73ca9d4a6 # pin@v2 @@ -127,12 +122,7 @@ jobs: disk-size: 4096M emulator-options: -no-snapshot-save -no-window -accel on -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false - script: xharness android test --output-directory=./test_output --app=bin/io.sentry.dotnet.maui.device.testapp-Signed.apk --package-name=io.sentry.dotnet.maui.device.testapp - - - name: Create Test Report - if: success() || failure() - run: scripts/parse-xunit2-xml.ps1 ./test_output/TestResults.xml | Out-File $env:GITHUB_STEP_SUMMARY - shell: pwsh + script: pwsh scripts/device-test.ps1 android -Run - name: Upload results if: success() || failure() diff --git a/.github/workflows/device-tests-ios.yml b/.github/workflows/device-tests-ios.yml index 30ac87dba7..241c70be38 100644 --- a/.github/workflows/device-tests-ios.yml +++ b/.github/workflows/device-tests-ios.yml @@ -6,10 +6,13 @@ on: - main - release/* pull_request: + paths-ignore: + - '**.md' jobs: build: - runs-on: macos-latest + # Pinning `macos-13` because Microsoft.iOS 16.4 requires Xcode 14.3 which is only built-in in 13 + runs-on: macos-13 env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 @@ -28,14 +31,11 @@ jobs: - name: Build Cocoa SDK uses: ./.github/actions/buildcocoasdk - - name: Install .NET Workloads - run: dotnet workload install maui-ios --temp-dir "${{ runner.temp }}" --from-rollback-file rollback.json - - - name: Restore .NET Dependencies - run: dotnet restore test/Sentry.Maui.Device.TestApp --nologo + - name: Setup Environment + uses: ./.github/actions/environment - name: Build iOS Test App - run: dotnet build test/Sentry.Maui.Device.TestApp -c Release -f net7.0-ios --no-restore --nologo + run: pwsh ./scripts/device-test.ps1 ios -Build - name: Upload iOS Test App uses: actions/upload-artifact@v3 @@ -54,7 +54,6 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: 1 steps: - - name: Checkout uses: actions/checkout@v4 @@ -64,33 +63,14 @@ jobs: name: device-test-ios path: bin/Sentry.Maui.Device.TestApp.app - - name: Install XHarness - run: dotnet tool install Microsoft.DotNet.XHarness.CLI --global --version "1.*-*" - - name: Run Tests id: first-run - shell: bash +e {0} - run: > - xharness apple test \ - --app=bin/Sentry.Maui.Device.TestApp.app \ - --target=ios-simulator-64 \ - --launch-timeout=00:10:00 \ - --output-directory=./test_output \ - ; export exitcode=$? ; echo "exitcode=$exitcode" >> "$GITHUB_OUTPUT" + continue-on-error: true + run: pwsh scripts/device-test.ps1 ios -Run - name: Retry Tests (if previous failed to run) - if: steps.first-run.outputs.exitcode > 1 - run: > - xharness apple test \ - --app=bin/Sentry.Maui.Device.TestApp.app \ - --target=ios-simulator-64 \ - --launch-timeout=00:10:00 \ - --output-directory=./test_output - - - name: Create Test Report - if: success() || failure() - run: scripts/parse-xunit2-xml.ps1 @(gci ./test_output/*.xml)[0].FullName | Out-File $env:GITHUB_STEP_SUMMARY - shell: pwsh + if: steps.first-run.outcome == 'failure' + run: pwsh scripts/device-test.ps1 ios -Run - name: Upload results if: success() || failure() diff --git a/.github/workflows/update-deps.yml b/.github/workflows/update-deps.yml index 49ee809654..45ef93876b 100644 --- a/.github/workflows/update-deps.yml +++ b/.github/workflows/update-deps.yml @@ -3,7 +3,7 @@ name: Update Dependencies on: # Run every day. schedule: - - cron: '0 3 * * *' + - cron: "0 3 * * *" # Allow a manual trigger to be able to run the update when there are new dependencies or after a PR merge to resolve CHANGELOG conflicts. workflow_dispatch: @@ -18,6 +18,8 @@ jobs: path: modules/sentry-cocoa - name: Java SDK path: scripts/update-java.ps1 + - name: Native SDK + path: modules/sentry-native - name: CLI path: scripts/update-cli.ps1 uses: getsentry/github-workflows/.github/workflows/updater.yml@v2 diff --git a/.github/workflows/vulnerabilities.yml b/.github/workflows/vulnerabilities.yml index 028e6cd2fc..279e3d390d 100644 --- a/.github/workflows/vulnerabilities.yml +++ b/.github/workflows/vulnerabilities.yml @@ -2,9 +2,10 @@ name: List vulnerable packages on: workflow_dispatch: - schedule: - - cron: "0 0 * * *" # once a day - pull_request: + # Currently broken on .net 8, see https://github.com/NuGet/Home/issues/12954 + # schedule: + # - cron: "0 0 * * *" # once a day + # pull_request: jobs: list-vulnerable-packages: diff --git a/.gitignore b/.gitignore index 0dfb27249d..2df028d874 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ mono_crash.*.json test_output/ test/**/*.apk /tools/ +*.log diff --git a/.gitmodules b/.gitmodules index bf84229f5c..172d270909 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "modules/perfview"] path = modules/perfview url = https://github.com/getsentry/perfview.git +[submodule "modules/sentry-native"] + path = modules/sentry-native + url = https://github.com/getsentry/sentry-native.git diff --git a/.vscode/settings.json b/.vscode/settings.json index 47a8ff1f7f..1425c69a44 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "omnisharp.useModernNet": true + "omnisharp.useModernNet": true, + "dotnet.defaultSolution": "Sentry.sln" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c3b6822ab..6895b5a07a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,178 @@ ## Unreleased +## 4.0.0-beta.2 + +### Fixes + +- Android native symbol upload ([#2876](https://github.com/getsentry/sentry-dotnet/pull/2876)) +- Sentry.Serilog no longer throws if a disabled DSN is provided when initializing Sentry via the Serilog integration ([#2883](https://github.com/getsentry/sentry-dotnet/pull/2883)) + +### .NET target frameworks changes + +**Dropped netstandard2.0 support for Sentry.AspNetCore** ([#2807](https://github.com/getsentry/sentry-dotnet/pull/2807)) + +### API breaking Changes + +#### Changed APIs + +- ISpanTracer has been renamed back again to ISpan, to make it easier to upgrade from v3.x to v4.x ([#2870](https://github.com/getsentry/sentry-dotnet/pull/2870)) + +## 4.0.0-beta.1 + +### Features + +- `Sentry.Profiling` is now packaged to be uploaded to nuget.org ([#2800](https://github.com/getsentry/sentry-dotnet/pull/2800)) + +## 4.0.0-beta.0 + +### Fixes + +- Don't add WinUI exception integration on mobile platforms ([#2821](https://github.com/getsentry/sentry-dotnet/pull/2821)) +- `Transactions` are now getting enriched by the client instead of the hub ([#2838](https://github.com/getsentry/sentry-dotnet/pull/2838)) + +### API breaking Changes + +#### Removed APIs + +- A number of `[Obsolete]` options have been removed ([#2841](https://github.com/getsentry/sentry-dotnet/pull/2841)) + - `BeforeSend` - use `SetBeforeSend` instead. + - `BeforeSendTransaction` - use `SetBeforeSendTransaction` instead. + - `BeforeBreadcrumb` - use `SetBeforeBreadcrumb` instead. + - `CreateHttpClientHandler` - use `CreateHttpMessageHandler` instead. + - `ReportAssemblies` - use `ReportAssembliesMode` instead. + - `KeepAggregateException` - this property is no longer used and has no replacement. + - `DisableTaskUnobservedTaskExceptionCapture` method has been renamed to `DisableUnobservedTaskExceptionCapture`. + - `DebugDiagnosticLogger` - use `TraceDiagnosticLogger` instead. +- A number of iOS/Android-specific `[Obsolete]` options have been removed ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) + - `Distribution` - use `SentryOptions.Distribution` instead. + - `EnableAutoPerformanceTracking` - use `SetBeforeSendTransaction` instead. + - `EnableCoreDataTracking` - use `EnableCoreDataTracing` instead. + - `EnableFileIOTracking` - use `EnableFileIOTracing` instead. + - `EnableOutOfMemoryTracking` - use `EnableWatchdogTerminationTracking` instead. + - `EnableUIViewControllerTracking` - use `EnableUIViewControllerTracing` instead. + - `StitchAsyncCode` - no longer available. + - `ProfilingTracesInterval` - no longer available. + - `ProfilingEnabled` - use `ProfilesSampleRate` instead. +- Obsolete `SystemClock` constructor removed, use `SystemClock.Clock` instead. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) +- Obsolete `Runtime.Clone()` removed, this shouldn't have been public in the past and has no replacement. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) +- Obsolete `SentryException.Data` removed, use `SentryException.Mechanism.Data` instead. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) +- Obsolete `AssemblyExtensions` removed, this shouldn't have been public in the past and has no replacement. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) +- Obsolete `SentryDatabaseLogging.UseBreadcrumbs()` removed, it is called automatically and has no replacement. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) +- Obsolete `Scope.GetSpan()` removed, use `Span` property instead. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856)) +- Obsolete `IUserFactory` removed, use `ISentryUserFactory` instead. ([#2856](https://github.com/getsentry/sentry-dotnet/pull/2856), [#2840](https://github.com/getsentry/sentry-dotnet/pull/2840)) + +#### Changed APIs + +- `DebugImage` and `DebugMeta` moved to `Sentry.Protocol` namespace. ([#2815](https://github.com/getsentry/sentry-dotnet/pull/2815)) +- `SentryClient.Dispose` is no longer obsolete ([#2842](https://github.com/getsentry/sentry-dotnet/pull/2842)) + +## 4.0.0-alpha.0 + +This release brings support for .NET 8 Native AOT publishing and cleans up some of the old APIs that have outlived their use. + +Additionally, we're dropping support for some of the old target frameworks, please check this [GitHub Discussion](https://github.com/getsentry/sentry-dotnet/discussions/2776) for details why. + +### .NET target frameworks changes + +- **Replace support for .NET Framework 4.6.1 with 4.6.2** ([#2786](https://github.com/getsentry/sentry-dotnet/pull/2786)) + + .NET Framework 4.6.1 was announced in Nov 30, 2015. And went out of support over a year ago, on Apr 26, 2022. + +- **Replace support for .NET 6 on mobile (e.g: `net6.0-android`) with .NET 7** ([#2624](https://github.com/getsentry/sentry-dotnet/pull/2604)) + + .NET 6 on mobile is out of support since May 2023 and with .NET 8, it's no longer possible to build .NET 6 Mobile specific targets. + For that reason, we're moving the mobile specific TFMs from `net6.0-platform` to `net7.0-platform`. + + Mobile apps still work on .NET 6 will pull the `Sentry` .NET 6, which offers the .NET-only features, + without native/platform specific bindings and SDKs. See [this ticket for more details](https://github.com/getsentry/sentry-dotnet/issues/2623). + +- **Drop .NET Core 3.1 and .NET 5 support** ([#2787](https://github.com/getsentry/sentry-dotnet/pull/2787)) + +- **Drop Tizen support** ([#2734](https://github.com/getsentry/sentry-dotnet/pull/2734)) + +### API breaking Changes + +- Setting `SentryOptions.Dsn` to `null` now throws `ArgumentNullException` during initialization. ([#2655](https://github.com/getsentry/sentry-dotnet/pull/2655)) +- Enable `CaptureFailedRequests` by default ([#2688](https://github.com/getsentry/sentry-dotnet/pull/2688)) + +#### Removed APIs + +- `IHasMeasurements` has been removed, use `ISpanData` instead. ([#2659](https://github.com/getsentry/sentry-dotnet/pull/2659)) +- `IHasBreadcrumbs` has been removed, use `IEventLike` instead. ([#2670](https://github.com/getsentry/sentry-dotnet/pull/2670)) +- `ISpanContext` has been removed, use `ITraceContext` instead. ([#2668](https://github.com/getsentry/sentry-dotnet/pull/2668)) +- `IHasTransactionNameSource` has been removed, use `ITransactionContext` instead. ([#2654](https://github.com/getsentry/sentry-dotnet/pull/2654)) +- ([#2694](https://github.com/getsentry/sentry-dotnet/pull/2694)) +- Unused `StackFrame.InstructionOffset` has been removed. ([#2691](https://github.com/getsentry/sentry-dotnet/pull/2691)) +- Unused `Scope.Platform` property has been removed. ([#2695](https://github.com/getsentry/sentry-dotnet/pull/2695)) +- Obsolete setter `Sentry.PlatformAbstractions.Runtime.Identifier` has been removed ([2764](https://github.com/getsentry/sentry-dotnet/pull/2764)) +- `Sentry.Values` is now internal as it is never exposed in the public API ([#2771](https://github.com/getsentry/sentry-dotnet/pull/2771)) +- `TracePropagationTarget` class has been removed, use the `SubstringOrRegexPattern` class instead. ([#2763](https://github.com/getsentry/sentry-dotnet/pull/2763)) + +#### Changed APIs + +- `WithScope` and `WithScopeAsync` methods have been removed. We have discovered that these methods didn't work correctly in certain desktop contexts, especially when using a global scope. ([#2717](https://github.com/getsentry/sentry-dotnet/pull/2717)) + + Replace your usage of `WithScope` with overloads of `Capture*` methods: + + - `SentrySdk.CaptureEvent(SentryEvent @event, Action scopeCallback)` + - `SentrySdk.CaptureMessage(string message, Action scopeCallback)` + - `SentrySdk.CaptureException(Exception exception, Action scopeCallback)` + + ```c# + // Before + SentrySdk.WithScope(scope => + { + scope.SetTag("key", "value"); + SentrySdk.CaptureEvent(new SentryEvent()); + }); + + // After + SentrySdk.CaptureEvent(new SentryEvent(), scope => + { + // Configure your scope here + scope.SetTag("key", "value"); + }); + ``` + +- `ISentryClient.CaptureEvent` overloads have been replaced by a single method accepting optional `Hint` and `Scope` parameters. You will need to pass `hint` as a named parameter from code that calls `CaptureEvent` without passing a `scope` argument. ([#2749](https://github.com/getsentry/sentry-dotnet/pull/2749)) +- `ISpan` and `ITransaction` have been renamed to `ISpanTracer` and `ITransactionTracer`. You will need to update any references to these interfaces in your code to use the new interface names ([#2731](https://github.com/getsentry/sentry-dotnet/pull/2731)) +- `TransactionContext` and `SpanContext` constructors were updated. If you're constructing instances of these classes, you will need to adjust the order in which you pass parameters to these. ([#2694](https://github.com/getsentry/sentry-dotnet/pull/2694), [#2696](https://github.com/getsentry/sentry-dotnet/pull/2696)) +- The `DiagnosticLogger` signature for `LogError` and `LogFatal` changed to take the `exception` as the first parameter. That way it does no longer get mixed up with the TArgs. The `DiagnosticLogger` now also received an overload for `LogError` and `LogFatal` that accepts a message only. ([#2715](https://github.com/getsentry/sentry-dotnet/pull/2715)) +- `Distribution` added to `IEventLike`. ([#2660](https://github.com/getsentry/sentry-dotnet/pull/2660)) +- `StackFrame`'s `ImageAddress`, `InstructionAddress` and `FunctionId` changed to `long?`. ([#2691](https://github.com/getsentry/sentry-dotnet/pull/2691)) +- `DebugImage.ImageAddress` changed to `long?`. ([#2725](https://github.com/getsentry/sentry-dotnet/pull/2725)) +- Contexts now inherits from `IDictionary` rather than `ConcurrentDictionary`. The specific dictionary being used is an implementation detail. ([#2729](https://github.com/getsentry/sentry-dotnet/pull/2729)) +- Transaction names for ASP.NET Core are now consistently named `HTTP-VERB /path` (e.g. `GET /home`). Previously the leading forward slash was missing for some endpoints. ([#2808](https://github.com/getsentry/sentry-dotnet/pull/2808)) + +### Features + +#### Native AOT + +Native AOT publishing support for .NET 8 has been added to Sentry for the following platforms: + +- Windows +- Linux +- macOS +- Mac Catalyst +- iOS + +There are some functional differences when publishing Native AOT: + +- `StackTraceMode.Enhanced` is ignored because it's not available when publishing Native AOT. The mechanism to generate these enhanced stack traces relies heavily on reflection which isn't compatible with trimming. +- Reflection cannot be leveraged for JSON Serialization and you may need to use `SentryOptions.AddJsonSerializerContext` to supply a serialization context for types that you'd like to send to Sentry (e.g. in the `Span.Context`). ([#2732](https://github.com/getsentry/sentry-dotnet/pull/2732), [#2793](https://github.com/getsentry/sentry-dotnet/pull/2793)) +- WinUI applications: when publishing Native AOT, Sentry isn't able to automatically register an unhandled exception handler because that relies on reflection. You'll need to [register the unhandled event handler manually](https://github.com/getsentry/sentry-dotnet/issues/2778) instead. + ### Dependencies +- Upgraded to NLog version 5. ([#2697](https://github.com/getsentry/sentry-dotnet/pull/2697)) +- Integrate `sentry-native` as a static library in Native AOT builds to enable symbolication. ([#2704](https://github.com/getsentry/sentry-dotnet/pull/2704)) + - Bump CLI from v2.21.5 to v2.22.2 ([#2901](https://github.com/getsentry/sentry-dotnet/pull/2901)) - [changelog](https://github.com/getsentry/sentry-cli/blob/master/CHANGELOG.md#2222) - [diff](https://github.com/getsentry/sentry-cli/compare/2.21.5...2.22.2) + ## 3.41.2 ### Fixes @@ -96,8 +262,8 @@ ### Features -- Reduced the memory footprint of `SpanId` by refactoring the ID generation ([2619](https://github.com/getsentry/sentry-dotnet/pull/2619)) -- Reduced the memory footprint of `SpanTracer` by initializing the tags lazily ([2636](https://github.com/getsentry/sentry-dotnet/pull/2636)) +- Reduced the memory footprint of `SpanId` by refactoring the ID generation ([#2619](https://github.com/getsentry/sentry-dotnet/pull/2619)) +- Reduced the memory footprint of `SpanTracer` by initializing the tags lazily ([#2636](https://github.com/getsentry/sentry-dotnet/pull/2636)) - Added distributed tracing without performance for Azure Function Workers ([#2630](https://github.com/getsentry/sentry-dotnet/pull/2630)) - The SDK now provides and overload of `ContinueTrace` that accepts headers as `string` ([#2601](https://github.com/getsentry/sentry-dotnet/pull/2601)) - Sentry tracing middleware now gets configured automatically ([#2602](https://github.com/getsentry/sentry-dotnet/pull/2602)) @@ -164,7 +330,7 @@ - Bump Cocoa SDK from v8.9.5 to v8.10.0 ([#2546](https://github.com/getsentry/sentry-dotnet/pull/2546), [#2550](https://github.com/getsentry/sentry-dotnet/pull/2550)) - [changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md#8100) - [diff](https://github.com/getsentry/sentry-cocoa/compare/8.9.5...8.10.0) -- Bump gradle/gradle-build-action from 2.7.0 to 2.7.1 ([2564](https://github.com/getsentry/sentry-dotnet/pull/2564)) +- Bump gradle/gradle-build-action from 2.7.0 to 2.7.1 ([#2564](https://github.com/getsentry/sentry-dotnet/pull/2564)) - [diff](https://github.com/gradle/gradle-build-action/compare/v2.7.0...v2.7.1) ## 3.35.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8b56f48e3..68b0da0501 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,20 +16,23 @@ For big feature it's advised to raise an issue to discuss it first. * The latest versions of the following .NET SDKs: - [.NET 7.0](https://dotnet.microsoft.com/download/dotnet/7.0) - [.NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0) - - [.NET Core 3.1](https://dotnet.microsoft.com/download/dotnet/3.1) - *Technically, you only need the full SDK install for the latest version (7.0). If you like, you can install the smaller ASP.NET Core Runtime packages for .NET 6.0 and .NET Core 3.1. However, installing the full SDKs will also give you the runtimes.* + *Technically, you only need the full SDK install for the latest version (7.0). If you like, you can install the smaller ASP.NET Core Runtime packages for .NET 6.0 . However, installing the full SDKs will also give you the runtimes.* *If using an M1 ("Apple silicon") processor, read [the special instructions below](#special-instructions-for-apple-silicon-cpus).* -* On Windows: [.NET Framework](https://dotnet.microsoft.com/download/dotnet-framework) 4.6.2 or higher. +* On Windows: + - [.NET Framework](https://dotnet.microsoft.com/download/dotnet-framework) 4.6.2 or higher. + - You'll need `CMake` somewhere on your PATH. If you don't already have this, one way to get it is to install the [C++ CMake tools for Windows](https://learn.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=msvc-170#installation) - `Sentry.DiagnosticSource.IntegrationTests.csproj` uses [SQL LocalDb](https://docs.microsoft.com/sql/database-engine/configure-windows/sql-server-express-localdb) - [download SQL LocalDB 2019](https://download.microsoft.com/download/7/c/1/7c14e92e-bdcb-4f89-b7cf-93543e7112d1/SqlLocalDB.msi). To avoid running these tests, unload `Sentry.DiagnosticSource.IntegrationTests.csproj` from the solution. -* On macOS/Linux: [Mono 6 or higher](https://www.mono-project.com/download/stable) to run the unit tests on the `net4x` targets. +* On macOS/Linux + - [Mono 6 or higher](https://www.mono-project.com/download/stable) to run the unit tests on the `net4x` targets. + - Install `CMake` using your favourite package manager (e.g. `brew install cmake`) ## .NET MAUI Requirements -To build any of `Sentry.Maui`, `Sentry.Maui.Tests`, or `Sentry.Samples.Maui`, you'll need to have .NET SDK 6.0.400 or greater installed, and have installed the MAUI workloads installed, either through Visual Studio setup, or by running `dotnet workload restore` (or `dotnet workload install maui`) from the Sentry source code root directory. -You may also need other platform dependencies. +To build any of `Sentry.Maui`, `Sentry.Maui.Tests`, or `Sentry.Samples.Maui`, you'll need to have .NET SDK 7.0.400 or greater installed, and have installed the MAUI workloads installed, either through Visual Studio setup, or by running `dotnet workload restore` (or `dotnet workload install maui`) from the Sentry source code root directory. +You may also need other platform dependencies. See https://docs.microsoft.com/dotnet/maui/ for details. JetBrains also have a great blog post if you're developing on a Mac: https://blog.jetbrains.com/dotnet/2022/05/25/macos-environment-setup-for-maui-development/ @@ -47,11 +50,11 @@ Although the files in `/src/Sentry/Platforms/` are part of the `Sentry` project, These `*.props` files are used to add platform-specific files, such as references to the binding projects for each native SDK (which provide .NET wrappers around native Android or Cocoa functions). -Also note `/Directory.Build.targets` contains some [convention based rules](https://github.com/getsentry/sentry-dotnet/blob/b1bfe1efc04eb4c911a85f1cf4cd2e5a176d7c8a/Directory.Build.targets#L17-L35) to exclude code that is not relevant for the target platform. Developers using Visual Studio will need to enable `Show All Files` in order to be able to see these files, when working with the solution. +Also note `/Directory.Build.targets` contains some [convention based rules](https://github.com/getsentry/sentry-dotnet/blob/b1bfe1efc04eb4c911a85f1cf4cd2e5a176d7c8a/Directory.Build.targets#L17-L35) to exclude code that is not relevant for the target platform. Developers using Visual Studio will need to enable `Show All Files` in order to be able to see these files, when working with the solution. ## Solution Filters -Most contributors will rarely need to load Sentry.sln. The repository contains various solution filters that will be more practical for day to day tasks. +Most contributors will rarely need to load Sentry.sln. The repository contains various solution filters that will be more practical for day to day tasks. These solution filters get generated automatically by `/scripts/generate-solution-filters.ps1` so, although you can certainly create your own solution filters and manage these how you wish, don't try to modify any of the `*.slnf` files that are committed to source control. Instead, changes to these can be made by modifying `/scripts/generate-solution-filters-config.yml` and re-running the script that generates these. @@ -70,8 +73,6 @@ and commit the `verify` files that were changed. Apple Silicon processors (such as the "M1") are arm64 processosr. While .NET 6 and higher run natively on this arm64 under macOS, previous versions are only built for x64. To get everything working correctly take the following steps: - Always install the arm64 release of .NET 6 and 7, through the normal process described above. -- Always install the x64 release of .NET Core 3.1 (it is not avaialable for arm64). - - If prompted, you will need to allow Apple's [Rosetta](https://support.apple.com/HT211861) to be installed. If you have previously done this for another app, you won't be prompted again. If you are only running `dotnet test Sentry.sln` on the command line, you don't need to do anything else. @@ -83,9 +84,8 @@ When the .NET Core CLI executable path is set to `/usr/local/share/dotnet/dotnet - However, you will only be able to debug and run unit tests in Rider using the arm64 versions of the .NET runtimes you have installed. When the .NET Core CLI executable path is set to `/usr/local/share/dotnet/x64/dotnet`, that's an x64 version of the .NET SDK. -- You will need to switch to this if you need to debug or run unit tests for .NET Core 3.1. -- Only targets which you have x64 SDKs will work when this is selected. Thus, you *might* want to also install x64 versions of the newer .NET 6 and 7 SDKs, which would allow you to run tests for all target frameworks together. -- Keep in mind that x64 is always slower and consumes more battery, as it runs through emulation. Thus you should use this mode only when needed. +- .NET Core 3.1 and older are only 64 bits but are **no longer supoported by this repository** as of version 4.0.0 of the SDK. You shouldn't need to have x64 version installed to contribute. +- Keep in mind that x64 is always slower and consumes more battery, as it runs through emulation. Note that the MSBuild version should always be `17.0` but will change paths based on whether you have selected an arm64 or x64 SDK. If Rider auto-detects an older MSBuild, change it manually to 17.0. @@ -134,3 +134,15 @@ pwsh ./scripts/accept-verifier-changes.ps1 ``` You may need to run this multiple times because `dotnet test` stops after a certain number of failures. + +## Integration tests + +Directory [./integration-test](./integration-test/) contains [Pester](https://pester.dev/)-based integration tests. +These tests create sample apps with `dotnet new` and run against local nuget packages (.nuget files). +In CI, these packages are expected to be present, while locally, scripts will run `nuget pack` automatically. + +### Running integration tests locally + +You can run individual tests either via Pester integration (e.g. in VS Code), or from command line: `./integration-test/cli.Tests.ps1`. Consult Pester docs for details on how to write tests. + +Because these tests rely on a Sentry server mock (`Invoke-SentryServer`) from , you need to check out [getsentry/github-workflows](https://github.com/getsentry/github-workflows) as a sibling directory next to your `getsentry/sentry-dotnet` checkout. diff --git a/Directory.Build.props b/Directory.Build.props index 1e9713fc28..9f6480640e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,8 +1,8 @@ - 3.41.2 - 11 + 4.0.0-beta.2 + 12 true $(MSBuildThisFileDirectory).assets\Sentry.snk true @@ -27,7 +27,6 @@ true true true - true - - false - - @@ -67,9 +61,6 @@ true - - true - @@ -78,19 +69,11 @@ BeforeTargets="_ComputePublishLocation" Condition="'$(OutputType)' == 'Exe' And ('$(TargetPlatformIdentifier)' == 'ios' Or '$(TargetPlatformIdentifier)' == 'maccatalyst')"> - + - - - - diff --git a/GlobalUsings.cs b/GlobalUsings.cs index 297e6f2656..38f2d5e988 100644 --- a/GlobalUsings.cs +++ b/GlobalUsings.cs @@ -13,6 +13,7 @@ global using System.IO.MemoryMappedFiles; global using System.Net; global using System.Net.Http.Headers; +global using System.Net.Http; global using System.Net.NetworkInformation; global using System.Net.Sockets; global using System.Reflection; diff --git a/README.md b/README.md index 7e699b102e..c3197ee487 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ Sentry SDK for .NET Sentry offers other integrations that are not part of this repository: -* [Sentry.Minidump](https://github.com/getsentry/sentry-dotnet-minidump): Capture Minidumps on Windows, macOS and Linux * [Sentry.Unity](https://github.com/getsentry/sentry-unity): Unity integrations * [Sentry.Xamarin](https://github.com/getsentry/sentry-xamarin): Xamarin native and Xamarin.Forms integrations @@ -47,8 +46,6 @@ Each NuGet package in the table above has its custom view of the docs. Click on Sentry has extensive documentation for its SDKs on [https://docs.sentry.io](https://docs.sentry.io/platforms/dotnet/). -Additionally, our [.NET API reference docs](https://getsentry.github.io/sentry-dotnet/index.html) are generated and deployed on each merge to main. - ### Samples **Consider taking a look at the _[samples](https://github.com/getsentry/sentry-dotnet/tree/main/samples)_ directory for different types of apps and example usages of the SDK.** @@ -58,38 +55,7 @@ Looking for more samples? Check out [this repository](https://github.com/getsent ### Talks * On.NET [Error monitoring with Sentry for .NET MAUI](https://www.youtube.com/watch?v=8YmEC4iKD2I) -* .NET Conf [focus on MAUI](https://www.youtube.com/watch?v=RW3hiukVXZQ&list=PLdo4fOcmZ0oWePZU3W162NJ9vcXqgpMVc) - -## Compatibility - -The packages target **.NET Standard 2.0** and **.NET Framework 4.6.1**. -They also include targets such as **.NET 5**, **.NET 6** and platform-specific targets where appropriate. -That means [they are compatible with](https://docs.microsoft.com/dotnet/standard/net-standard) the following versions _or newer_: - -* .NET 5.0 -* .NET Core 2.0 -* .NET Framework 4.6.1 -* Mono 5.4 -* Xamarin.Android 8.0 -* Xamarin.iOS 10.14 -* Xamarin.Mac 3.8 -* Universal Windows Platform 10.0.16299 - -Of those, we run our unit and integration tests against the following: - -* .NET 7 on Windows, macOS and Linux -* .NET 6 on Windows, macOS and Linux -* .NET Core 3.1 on Windows, macOS and Linux -* .NET Framework 4.8 on Windows -* Mono 6.12 on macOS and Linux - -### Sentry Protocol - -For more details, please: **refer to the [documentation](https://getsentry.github.io/sentry-dotnet/index.html)** - -### Legacy frameworks - -Sentry's [Raven SDK](https://github.com/getsentry/raven-csharp/) is still available, and recommended for use with .NET Framework 3.5 to 4.6.0. +* .NET Conf [focus on MAUI](https://www.youtube.com/watch?v=RW3hiukVXZQ&list=PLdo4fOcmZ0oWePZU3W162NJ9vcXqgpMVc) ## Resources * [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/dotnet/) diff --git a/Sentry.sln.DotSettings b/Sentry.sln.DotSettings index 817e3366d3..d2e08fed81 100644 --- a/Sentry.sln.DotSettings +++ b/Sentry.sln.DotSettings @@ -1,5 +1,9 @@  + IO + OS + QL + UI True True True - True \ No newline at end of file + True diff --git a/benchmarks/Directory.Build.props b/benchmarks/Directory.Build.props index de624983bc..8b67868af9 100644 --- a/benchmarks/Directory.Build.props +++ b/benchmarks/Directory.Build.props @@ -4,7 +4,6 @@ - false false diff --git a/benchmarks/Sentry.Benchmarks/StackFrameBenchmarks.cs b/benchmarks/Sentry.Benchmarks/StackFrameBenchmarks.cs index 840ac42b99..6797013c45 100644 --- a/benchmarks/Sentry.Benchmarks/StackFrameBenchmarks.cs +++ b/benchmarks/Sentry.Benchmarks/StackFrameBenchmarks.cs @@ -145,7 +145,7 @@ public void ConfigureAppFrame() Module ="Sentry.Extensions.Profiling" }, new SentryStackFrame() { - Function ="SamplingTransactionProfiler.Start(class Sentry.ITransaction) {QuickJitted}", + Function ="SamplingTransactionProfiler.Start(class Sentry.ITransactionTracer) {QuickJitted}", Module ="Sentry.Extensions.Profiling" }, new SentryStackFrame() { diff --git a/build.cmd b/build.cmd index 8ae96e27aa..01c0cea7e6 100644 --- a/build.cmd +++ b/build.cmd @@ -1,3 +1,2 @@ -set UseSentryCLI=false dotnet build Sentry.sln -c Release dotnet test Sentry.sln -c Release --no-build diff --git a/build.sh b/build.sh index fdead9b9f3..01c0cea7e6 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,2 @@ -export UseSentryCLI=false dotnet build Sentry.sln -c Release dotnet test Sentry.sln -c Release --no-build diff --git a/global.json b/global.json index 3a95bf88f8..60b4c0250d 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "7.0.100", + "version": "8.0.100", "rollForward": "latestMinor", "allowPrerelease": false } -} +} \ No newline at end of file diff --git a/integration-test/.gitignore b/integration-test/.gitignore new file mode 100644 index 0000000000..4f6392daad --- /dev/null +++ b/integration-test/.gitignore @@ -0,0 +1,2 @@ +*-app +packages diff --git a/integration-test/Directory.Build.props b/integration-test/Directory.Build.props new file mode 100644 index 0000000000..701aaea379 --- /dev/null +++ b/integration-test/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/integration-test/Directory.Build.targets b/integration-test/Directory.Build.targets new file mode 100644 index 0000000000..09c9320b2a --- /dev/null +++ b/integration-test/Directory.Build.targets @@ -0,0 +1,3 @@ + + + diff --git a/integration-test/cli.Tests.ps1 b/integration-test/cli.Tests.ps1 new file mode 100644 index 0000000000..8645b0afed --- /dev/null +++ b/integration-test/cli.Tests.ps1 @@ -0,0 +1,181 @@ +# This file contains test cases for https://pester.dev/ +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +. $PSScriptRoot/common.ps1 + +Describe 'Console apps () - normal build' -ForEach @( + @{ framework = "net8.0" } +) { + BeforeAll { + DotnetNew 'console' 'console-app' $framework + } + + BeforeEach { + Remove-Item "./console-app/bin/Release/$framework/*.src.zip" -ErrorAction SilentlyContinue + } + + It "uploads symbols and sources" { + $result = RunDotnetWithSentryCLI 'build' 'console-app' $True $True $framework + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @('console-app.pdb') + $result.ScriptOutput | Should -AnyElementMatch 'Found 1 debug information file \(1 with embedded sources\)' + $result.ScriptOutput | Should -AnyElementMatch 'Resolved source code for 0 debug information files' + } + + It "uploads symbols" { + $result = RunDotnetWithSentryCLI 'build' 'console-app' $True $False $framework + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @('console-app.pdb') + $result.ScriptOutput | Should -AnyElementMatch 'Found 1 debug information file \(1 with embedded sources\)' + } + + It "uploads sources" { + $result = RunDotnetWithSentryCLI 'build' 'console-app' $False $True $framework + $result.ScriptOutput | Should -AnyElementMatch 'Skipping embedded source file: .*/console-app/Program.cs' + $result.UploadedDebugFiles() | Should -BeNullOrEmpty + } + + It "uploads nothing when disabled" { + $result = RunDotnetWithSentryCLI 'build' 'console-app' $False $False $framework + $result.UploadedDebugFiles() | Should -BeNullOrEmpty + } +} + +Describe 'Console apps () - native AOT publish' -ForEach @( + @{ framework = "net8.0" } +) { + BeforeAll { + DotnetNew 'console' 'console-app' $framework + } + + BeforeEach { + Remove-Item "./console-app/bin/Release/$framework/publish" -Recurse -ErrorAction SilentlyContinue + } + + It "uploads symbols and sources" { + $result = RunDotnetWithSentryCLI 'publish' 'console-app' $True $True $framework + $result.ScriptOutput | Should -AnyElementMatch "Preparing upload to Sentry for project 'console-app'" + if ($IsWindows) + { + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @("console-app.pdb") + $result.ScriptOutput | Should -AnyElementMatch 'Found 1 debug information file' + $result.ScriptOutput | Should -AnyElementMatch 'Resolved source code for 1 debug information file' + } + else + { + # On macOS, only the dwarf is uploaded from dSYM so it has the same name as the actual executable. + $debugExtension = $IsLinux ? '.dbg' : '' + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be (@( + 'console-app', "console-app$debugExtension") | Sort-Object -Unique) + $result.ScriptOutput | Should -AnyElementMatch 'Found 2 debug information files' + $result.ScriptOutput | Should -AnyElementMatch 'Resolved source code for 1 debug information file' + } + } + + It "uploads symbols" { + $result = RunDotnetWithSentryCLI 'publish' 'console-app' $True $False $framework + $result.ScriptOutput | Should -AnyElementMatch "Preparing upload to Sentry for project 'console-app'" + if ($IsWindows) + { + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @("console-app.pdb") + $result.ScriptOutput | Should -AnyElementMatch 'Found 1 debug information file' + } + else + { + # On macOS, only the dwarf is uploaded from dSYM so it has the same name as the actual executable. + $debugExtension = $IsLinux ? '.dbg' : '' + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be (@( + 'console-app', "console-app$debugExtension") | Sort-Object -Unique) + $result.ScriptOutput | Should -AnyElementMatch 'Found 2 debug information files' + } + } + + It "uploads sources" { + $result = RunDotnetWithSentryCLI 'publish' 'console-app' $False $True $framework + $result.ScriptOutput | Should -AnyElementMatch "Preparing upload to Sentry for project 'console-app'" + $sourceBundle = 'console-app.src.zip' + if ($IsMacOS) + { + $sourceBundle = 'console-app.src.zip' + } + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @($sourceBundle) + } + + It "uploads nothing when disabled" { + $result = RunDotnetWithSentryCLI 'publish' 'console-app' $False $False $framework + $result.UploadedDebugFiles() | Should -BeNullOrEmpty + } +} + +# TODO creating a sample app with `dotnet new` currently fails in CI on all platforms with: +# 'error: NU1100: Unable to resolve 'Microsoft.Extensions.Http (>= 6.0.0)' for 'net7.0-android33.0'. PackageSourceMapping is enabled, the following source(s) were not considered: integration-test.' +# Tracking issue: https://github.com/getsentry/sentry-dotnet/issues/2809 +Describe 'MAUI' -ForEach @( + @{ framework = "net7.0" } +) -Skip:$true { + BeforeAll { + RegisterLocalPackage 'Sentry.Android.AssemblyReader' + RegisterLocalPackage 'Sentry.Bindings.Android' + RegisterLocalPackage 'Sentry.Extensions.Logging' + RegisterLocalPackage 'Sentry.Maui' + if ($IsMacOS) + { + RegisterLocalPackage 'Sentry.Bindings.Cocoa' + } + + $name = 'maui-app' + DotnetNew 'maui' $name $framework + + # Workaround for the missing "ios" workload on Linux, see https://github.com/dotnet/maui/pull/18580 + $tfs = $IsMacos ? "$framework-android;$framework-ios;$framework-maccatalyst" : "$framework-android" + (Get-Content $name/$name.csproj) -replace '[^<]+', "$tfs" | Set-Content $name/$name.csproj + + dotnet remove $name/$name.csproj package 'Microsoft.Extensions.Logging.Debug' | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to remove package" + } + + if (Test-Path env:CI) + { + dotnet workload restore $name/$name.csproj | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to restore workloads." + } + } + + AddPackageReference $name 'Sentry.Maui' + } + + It "uploads symbols and sources for an Android build" { + $result = RunDotnetWithSentryCLI 'build' 'maui-app' $True $True "$framework-android" + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( + 'libsentry-android.so', + 'libsentry.so', + 'libsentrysupplemental.so', + 'libxamarin-app.so', + 'maui-app.pdb' + ) + $result.ScriptOutput | Should -AnyElementMatch 'Found 1 debug information file \(1 with embedded sources\)' + } + + It "uploads symbols and sources for an iOS build" -Skip:(!$IsMacOS) { + $result = RunDotnetWithSentryCLI 'build' 'maui-app' $True $True "$framework-ios" + $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( + 'libmono-component-debugger.dylib', + 'libmono-component-diagnostics_tracing.dylib', + 'libmono-component-hot_reload.dylib', + 'libmonosgen-2.0.dylib', + 'libSystem.IO.Compression.Native.dylib', + 'libSystem.Native.dylib', + 'libSystem.Net.Security.Native.dylib', + 'libSystem.Security.Cryptography.Native.Apple.dylib', + 'libxamarin-dotnet-debug.dylib', + 'libxamarin-dotnet.dylib', + 'maui-app', + 'maui-app.pdb', + 'Sentry' + ) + $nonZeroNumberRegex = '[1-9][0-9]*'; + $result.ScriptOutput | Should -AnyElementMatch "Found $nonZeroNumberRegex debug information files \($nonZeroNumberRegex with embedded sources\)" + } +} diff --git a/integration-test/common.ps1 b/integration-test/common.ps1 new file mode 100644 index 0000000000..ce25c66b45 --- /dev/null +++ b/integration-test/common.ps1 @@ -0,0 +1,199 @@ +# So that this works in VS Code testing integration. Otherwise the script is run within its directory. + +# In CI, the module is loaded automatically +if (!(Test-Path env:CI )) +{ + Import-Module $PSScriptRoot/../../github-workflows/sentry-cli/integration-test/action.psm1 -Force +} + +function ShouldAnyElementMatch ($ActualValue, [string]$ExpectedValue, [switch] $Negate, [string] $Because) +{ + <# + .SYNOPSIS + Asserts whether any item in the collection matches the expected value + .EXAMPLE + 'foo','bar','foobar' | Should -AnyElementMatch 'oob' + + This should pass because 'oob' is a substring of 'foobar'. + #> + + $filtered = $ActualValue | Where-Object { $_ -match $ExpectedValue } + [bool] $succeeded = @($filtered).Count -gt 0 + if ($Negate) { $succeeded = -not $succeeded } + + if (-not $succeeded) + { + if ($Negate) + { + $failureMessage = "Expected string '$ExpectedValue' to match no elements in collection @($($ActualValue -join ', '))$(if($Because) { " because $Because"})." + } + else + { + $failureMessage = "Expected string '$ExpectedValue' to match any element in collection @($($ActualValue -join ', '))$(if($Because) { " because $Because"})." + } + } + else + { + $failureMessage = $null + } + + return [pscustomobject]@{ + Succeeded = $succeeded + FailureMessage = $failureMessage + } +} + +BeforeDiscovery { + Add-ShouldOperator -Name AnyElementMatch ` + -InternalName 'ShouldAnyElementMatch' ` + -Test ${function:ShouldAnyElementMatch} ` + -SupportsArrayInput +} + +AfterAll { + Pop-Location +} + +BeforeAll { + Push-Location $PSScriptRoot + $env:SENTRY_LOG_LEVEL = 'debug'; + + function GetSentryPackageVersion() + { + (Select-Xml -Path "$PSScriptRoot/../Directory.Build.props" -XPath "/Project/PropertyGroup/Version").Node.InnerText + } + + function RegisterLocalPackage([string] $name) + { + $packageVersion = GetSentryPackageVersion + $packagePath = "$PSScriptRoot/../src/$name/bin/Release/$name.$packageVersion.nupkg" + if (-not (Test-Path env:CI)) + { + Write-Host "Packaging $name, expected output path: $packagePath" + dotnet pack "$PSScriptRoot/../src/$name" -c Release --nologo -p:Version=$packageVersion -p:IsPackable=true | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to package $name." + } + } + Write-Host "Using package $packagePath - $((Get-Item $packagePath).Length) bytes" + + dotnet nuget push $packagePath --source integration-test | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to add package $name to a local nuget source." + } + + # We need to remove the package from cache or it won't re resolved properly + Remove-Item -Path ~/.nuget/packages/$name/$packageVersion -Recurse -Force -ErrorAction SilentlyContinue + } + + Remove-Item -Path "$PSScriptRoot/packages" -Recurse -Force -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Path "$PSScriptRoot/packages" | Out-Null + RegisterLocalPackage 'Sentry' + + function RunDotnetWithSentryCLI([string] $action, [string]$project, [bool]$Symbols, [bool]$Sources, [string]$TargetFramework) + { + $rootDir = $PSScriptRoot + + $result = Invoke-SentryServer { + Param([string]$url) + Write-Host "::group::${action}ing $project" + try + { + dotnet $action $project -flp:logfile=build.log ` + -c Release ` + --nologo ` + --framework $TargetFramework ` + /p:SentryUploadSymbols=$Symbols ` + /p:SentryUploadSources=$Sources ` + /p:SentryOrg=org ` + /p:SentryProject=project ` + /p:SentryUrl=$url ` + /p:SentryAuthToken=dummy ` + | ForEach-Object { + if ($_ -match "^Time Elapsed ") + { + "Time Elapsed [value removed]" + } + elseif ($_ -match "\[[0-9/]+\]") + { + # Skip lines like `[102/103] Sentry.Samples.Maui.dll -> Sentry.Samples.Maui.dll.so` + } + else + { + "$_".Replace('\', '/').Replace($rootDir, '') + } + } + | ForEach-Object { + Write-Host " $_" + $_ + } + } + finally + { + Write-Host "::endgroup::" + } + } + + if ($action -eq "build") + { + $result.ScriptOutput | Should -Contain 'Build succeeded.' + } + elseif ($action -eq "publish") + { + $result.ScriptOutput | Should -AnyElementMatch "$((Get-Item $project).Basename) -> .*$project/bin/Release/$TargetFramework/.*/publish" + } + $result.ScriptOutput | Should -Not -AnyElementMatch "Preparing upload to Sentry for project 'Sentry'" + $result.HasErrors() | Should -BeFalse + $result + } + + function AddPackageReference([string] $projectPath, [string] $package) + { + Push-Location $projectPath + try + { + dotnet restore | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to restore the test app project." + } + + $packageVersion = GetSentryPackageVersion + dotnet add package $package --source $PSScriptRoot/packages --version $packageVersion --no-restore | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to add package dependency to the test app project." + } + } + finally + { + Pop-Location + } + } + function DotnetNew([string] $type, [string] $name, [string] $framework) + { + Remove-Item -Path $name -Recurse -Force -ErrorAction SilentlyContinue + dotnet new $type --output $name --framework $framework | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to create the test app '$name' from template '$type'." + } + + if ($type -eq 'console') + { + AddPackageReference $name 'Sentry' + if (!$IsMacOS -or $framework -eq 'net8.0') + { + @" + + + true + + +"@ | Out-File $name/Directory.Build.props + } + } + } +} diff --git a/integration-test/net4-console/Program.cs b/integration-test/net4-console/Program.cs new file mode 100644 index 0000000000..3d0664eb99 --- /dev/null +++ b/integration-test/net4-console/Program.cs @@ -0,0 +1,22 @@ +using Sentry; +using Sentry.Extensibility; +using Sentry.Protocol.Envelopes; + +// Initialize the Sentry SDK. (It is not necessary to dispose it.) +SentrySdk.Init(options => +{ + options.Dsn = "http://key@127.0.0.1:9999/123"; + options.Debug = true; + options.Transport = new FakeTransport(); +}); + +throw new ApplicationException("Something happened!"); + +internal class FakeTransport : ITransport +{ + public virtual Task SendEnvelopeAsync(Envelope envelope, CancellationToken cancellationToken = default) + { + envelope.Serialize(Console.OpenStandardOutput(), null); + return Task.CompletedTask; + } +} diff --git a/integration-test/net4-console/console-app.csproj b/integration-test/net4-console/console-app.csproj new file mode 100644 index 0000000000..a6c56df241 --- /dev/null +++ b/integration-test/net4-console/console-app.csproj @@ -0,0 +1,12 @@ + + + + Exe + net462 + console_app + enable + 10.0 + true + + + diff --git a/integration-test/nuget.config b/integration-test/nuget.config new file mode 100644 index 0000000000..aacaa1ba84 --- /dev/null +++ b/integration-test/nuget.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/integration-test/runtime.Tests.ps1 b/integration-test/runtime.Tests.ps1 new file mode 100644 index 0000000000..bdd79d0ed4 --- /dev/null +++ b/integration-test/runtime.Tests.ps1 @@ -0,0 +1,138 @@ +# This file contains test cases for https://pester.dev/ +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' +. $PSScriptRoot/common.ps1 + +Describe 'Console app NativeAOT ()' -ForEach @( + @{ framework = "net8.0" } +) { + BeforeAll { + $path = './console-app' + DotnetNew 'console' $path $framework + @" +using Sentry; +using Sentry.Extensibility; +using Sentry.Protocol.Envelopes; + +// Initialize the Sentry SDK. (It is not necessary to dispose it.) +SentrySdk.Init(options => +{ + options.Dsn = "http://key@127.0.0.1:9999/123"; + options.Debug = true; + options.Transport = new FakeTransport(); +}); + +throw new ApplicationException("Something happened!"); + +internal class FakeTransport : ITransport +{ + public virtual Task SendEnvelopeAsync(Envelope envelope, CancellationToken cancellationToken = default) + { + envelope.Serialize(Console.OpenStandardOutput(), null); + return Task.CompletedTask; + } +} +"@ | Out-File $path/Program.cs + + # Publish once, then run the executable in actual tests. + dotnet publish console-app -c Release --nologo --framework $framework | ForEach-Object { Write-Host $_ } + if ($LASTEXITCODE -ne 0) + { + throw "Failed to publish the test app project." + } + + function getConsoleAppPath() + { + if ($IsMacOS) + { + $arch = $(uname -m) -eq 'arm64' ? 'arm64' : 'x64' + return "./console-app/bin/Release/$framework/osx-$arch/publish/console-app" + } + elseif ($IsWindows) + { + return "./console-app/bin/Release/$framework/win-x64/publish/console-app.exe" + } + else + { + return "./console-app/bin/Release/$framework/linux-x64/publish/console-app" + } + } + + function runConsoleApp([bool]$IsAOT = $true) + { + $executable = $IsAOT ? { & (getConsoleAppPath) } : { dotnet run --project $path -c Release --framework $framework } + Write-Host "::group::Executing $executable" + try + { + $executable.Invoke() | ForEach-Object { + Write-Host " $_" + $_ + } + } + finally + { + Write-Host "::endgroup::" + } + } + } + + It "sends native debug images" { + runConsoleApp | Should -AnyElementMatch '"debug_meta":{"images":\[{"type":"(pe|elf|macho)","image_addr":"0x[a-f0-9]+","image_size":[0-9]+,"debug_id":"[a-f0-9\-]+"' + } + + It "sends stack trace native addresses" { + runConsoleApp | Should -AnyElementMatch '"stacktrace":{"frames":\[{"image_addr":"0x[a-f0-9]+","instruction_addr":"0x[a-f0-9]+"}' + } + + It "publish directory contains expected files" { + $path = getConsoleAppPath + Test-Path $path | Should -BeTrue + $items = Get-ChildItem -Path (Get-Item $path).DirectoryName + $exeExtension = $IsWindows ? '.exe' : '' + $debugExtension = $IsWindows ? '.pdb' : $IsMacOS ? '.dSYM' : '.dbg' + $items | ForEach-Object { $_.Name } | Sort-Object -Unique | Should -Be (@( + "console-app$exeExtension", "console-app$debugExtension") | Sort-Object -Unique) + } + + It "'dotnet publish' produces an app that's recognized as AOT by Sentry" { + runConsoleApp | Should -AnyElementMatch 'This looks like a NativeAOT application build.' + } + + It "'dotnet run' produces an app that's recognized as JIT by Sentry" { + runConsoleApp $false | Should -AnyElementMatch 'This looks like a standard JIT/AOT application build.' + } +} + +# This ensures we don't have a regression for https://github.com/getsentry/sentry-dotnet/issues/2825 +Describe 'Console app regression (missing System.Reflection.Metadata)' { + AfterAll { + dotnet remove ./net4-console/console-app.csproj package Sentry + } + + It "Ensure System.Reflection.Metadata is not missing" { + $path = './net4-console' + Remove-Item -Recurse -Force -Path @("$path/bin", "$path/obj") -ErrorAction SilentlyContinue + AddPackageReference $path 'Sentry' + + function runConsoleApp() + { + $executable = { dotnet run --project $path -c Release } + Write-Host "::group::Executing $executable" + try + { + $executable.Invoke() | ForEach-Object { + Write-Host " $_" + $_ + } + } + finally + { + Write-Host "::endgroup::" + } + } + + $output = runConsoleApp + $output | Should -Not -AnyElementMatch 'Could not load file or assembly.' + $output | Should -AnyElementMatch '"exception":{"values":\[{"type":"System.ApplicationException","value":"Something happened!"' + } +} diff --git a/modules/Ben.Demystifier b/modules/Ben.Demystifier index 6e72aa45b9..dfdee44890 160000 --- a/modules/Ben.Demystifier +++ b/modules/Ben.Demystifier @@ -1 +1 @@ -Subproject commit 6e72aa45b9fdca99ba94e811204cbb7cb2fd5220 +Subproject commit dfdee448905e7685e56c6231768ea70ac2b20052 diff --git a/modules/sentry-native b/modules/sentry-native new file mode 160000 index 0000000000..79899a808a --- /dev/null +++ b/modules/sentry-native @@ -0,0 +1 @@ +Subproject commit 79899a808a4675a66db6b76a144cecea954506ea diff --git a/nuget.config b/nuget.config index 1324752ebc..48792e6dcb 100644 --- a/nuget.config +++ b/nuget.config @@ -1,4 +1,4 @@ - + diff --git a/rollback.json b/rollback.json deleted file mode 100644 index 50c1de33bf..0000000000 --- a/rollback.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "microsoft.net.sdk.ios": "16.2.2054/7.0.100", - "microsoft.net.sdk.maccatalyst": "16.2.2054/7.0.100" -} diff --git a/samples/Directory.Build.props b/samples/Directory.Build.props index 59e07989bb..349e13dfb6 100644 --- a/samples/Directory.Build.props +++ b/samples/Directory.Build.props @@ -6,11 +6,6 @@ false - - - false - - + + + + diff --git a/samples/Sentry.Samples.Android/MainActivity.cs b/samples/Sentry.Samples.Android/MainActivity.cs index 07baaf96f8..5ff22be72e 100644 --- a/samples/Sentry.Samples.Android/MainActivity.cs +++ b/samples/Sentry.Samples.Android/MainActivity.cs @@ -1,4 +1,3 @@ -#pragma warning disable CS0618 namespace Sentry.Samples.Android; [Activity(Label = "@string/app_name", MainLauncher = true)] @@ -50,12 +49,18 @@ protected override void OnCreate(Bundle? savedInstanceState) throwUnhandledException.Click += (s, a) => throw new Exception("Unhandled"); var throwJavaException = (Button)base.FindViewById(Resource.Id.throwJavaException)!; +#pragma warning disable CS0618 throwJavaException.Click += (s, a) => SentrySdk.CauseCrash(CrashType.Java); +#pragma warning restore CS0618 var throwJavaExceptionBackgroundThread = (Button)base.FindViewById(Resource.Id.throwJavaExceptionBackgroundThread)!; +#pragma warning disable CS0618 throwJavaExceptionBackgroundThread.Click += (s, a) => SentrySdk.CauseCrash(CrashType.JavaBackgroundThread); +#pragma warning restore CS0618 var crashInC = (Button)base.FindViewById(Resource.Id.crashInC)!; +#pragma warning disable CS0618 crashInC.Click += (s, a) => SentrySdk.CauseCrash(CrashType.Native); +#pragma warning restore CS0618 } } diff --git a/samples/Sentry.Samples.Android/Sentry.Samples.Android.csproj b/samples/Sentry.Samples.Android/Sentry.Samples.Android.csproj index 6c9f343359..ff57a2e864 100644 --- a/samples/Sentry.Samples.Android/Sentry.Samples.Android.csproj +++ b/samples/Sentry.Samples.Android/Sentry.Samples.Android.csproj @@ -1,6 +1,6 @@ - net7.0-android + net8.0-android 21 Exe enable diff --git a/samples/Sentry.Samples.Console.Basic/Sentry.Samples.Console.Basic.csproj b/samples/Sentry.Samples.Console.Basic/Sentry.Samples.Console.Basic.csproj index fd327d2f31..d18447279a 100644 --- a/samples/Sentry.Samples.Console.Basic/Sentry.Samples.Console.Basic.csproj +++ b/samples/Sentry.Samples.Console.Basic/Sentry.Samples.Console.Basic.csproj @@ -2,9 +2,10 @@ Exe - net6.0 enable enable + net8.0;net6.0;net462 + true @@ -23,11 +24,10 @@ true - false + true diff --git a/samples/Sentry.Samples.Console.Customized/README.md b/samples/Sentry.Samples.Console.Customized/README.md index 9ef732bd74..f97f899421 100644 --- a/samples/Sentry.Samples.Console.Customized/README.md +++ b/samples/Sentry.Samples.Console.Customized/README.md @@ -1,11 +1,3 @@ ## Running the sample Before running this sample make sure you add your own `DSN` to `Program.cs`. Get your `DSN` at [sentry.io](sentry.io). - -### Running with .NET Core: - -dotnet run -c Release -f netcoreapp2.1 - -### Running with .NET Framework or Mono - -dotnet run -c Release -f net472 diff --git a/samples/Sentry.Samples.EntityFramework/Sentry.Samples.EntityFramework.csproj b/samples/Sentry.Samples.EntityFramework/Sentry.Samples.EntityFramework.csproj index 2fb9a07109..b1fcad204b 100644 --- a/samples/Sentry.Samples.EntityFramework/Sentry.Samples.EntityFramework.csproj +++ b/samples/Sentry.Samples.EntityFramework/Sentry.Samples.EntityFramework.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net8.0 diff --git a/samples/Sentry.Samples.Google.Cloud.Functions/Sentry.Samples.Google.Cloud.Functions.csproj b/samples/Sentry.Samples.Google.Cloud.Functions/Sentry.Samples.Google.Cloud.Functions.csproj index d0c9c3f682..0863b01fdc 100644 --- a/samples/Sentry.Samples.Google.Cloud.Functions/Sentry.Samples.Google.Cloud.Functions.csproj +++ b/samples/Sentry.Samples.Google.Cloud.Functions/Sentry.Samples.Google.Cloud.Functions.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/Sentry.Samples.GraphQL.Client.Http/Sentry.Samples.GraphQL.Client.Http.csproj b/samples/Sentry.Samples.GraphQL.Client.Http/Sentry.Samples.GraphQL.Client.Http.csproj index f43ebd3f05..28af485e3b 100644 --- a/samples/Sentry.Samples.GraphQL.Client.Http/Sentry.Samples.GraphQL.Client.Http.csproj +++ b/samples/Sentry.Samples.GraphQL.Client.Http/Sentry.Samples.GraphQL.Client.Http.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable enable diff --git a/samples/Sentry.Samples.GraphQL.Server/Sentry.Samples.GraphQL.Server.csproj b/samples/Sentry.Samples.GraphQL.Server/Sentry.Samples.GraphQL.Server.csproj index 50c1172173..2b3cf5a6ea 100644 --- a/samples/Sentry.Samples.GraphQL.Server/Sentry.Samples.GraphQL.Server.csproj +++ b/samples/Sentry.Samples.GraphQL.Server/Sentry.Samples.GraphQL.Server.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/samples/Sentry.Samples.Ios/AppDelegate.cs b/samples/Sentry.Samples.Ios/AppDelegate.cs index 2fed4085f2..39f319624f 100644 --- a/samples/Sentry.Samples.Ios/AppDelegate.cs +++ b/samples/Sentry.Samples.Ios/AppDelegate.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS0618 - namespace Sentry.Samples.Ios; [Register("AppDelegate")] diff --git a/samples/Sentry.Samples.Ios/Info.plist b/samples/Sentry.Samples.Ios/Info.plist index 6401028ad0..fb0738075a 100644 --- a/samples/Sentry.Samples.Ios/Info.plist +++ b/samples/Sentry.Samples.Ios/Info.plist @@ -9,7 +9,7 @@ CFBundleShortVersionString 1.0 MinimumOSVersion - 10.0 + 11.0 CFBundleVersion 1.0 LSRequiresIPhoneOS diff --git a/samples/Sentry.Samples.Ios/Sentry.Samples.Ios.csproj b/samples/Sentry.Samples.Ios/Sentry.Samples.Ios.csproj index 3bc26b013f..8126655549 100644 --- a/samples/Sentry.Samples.Ios/Sentry.Samples.Ios.csproj +++ b/samples/Sentry.Samples.Ios/Sentry.Samples.Ios.csproj @@ -1,11 +1,13 @@ - net7.0-ios + net8.0-ios Exe enable true - 10.0 + 11.0 + true + true - - $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) - - - iossimulator-arm64 - - diff --git a/samples/Sentry.Samples.MacCatalyst/AppDelegate.cs b/samples/Sentry.Samples.MacCatalyst/AppDelegate.cs index 94c79107f8..7a87593aee 100644 --- a/samples/Sentry.Samples.MacCatalyst/AppDelegate.cs +++ b/samples/Sentry.Samples.MacCatalyst/AppDelegate.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS0618 - namespace Sentry.Samples.MacCatalyst; [Register ("AppDelegate")] diff --git a/samples/Sentry.Samples.MacCatalyst/Sentry.Samples.MacCatalyst.csproj b/samples/Sentry.Samples.MacCatalyst/Sentry.Samples.MacCatalyst.csproj index 1ccbf6ea9e..4dd38c17ca 100644 --- a/samples/Sentry.Samples.MacCatalyst/Sentry.Samples.MacCatalyst.csproj +++ b/samples/Sentry.Samples.MacCatalyst/Sentry.Samples.MacCatalyst.csproj @@ -1,10 +1,11 @@ - net7.0-maccatalyst + net8.0-maccatalyst Exe enable true 14.2 + true - net7.0-android - $(TargetFrameworks);net7.0-windows10.0.19041.0 - $(TargetFrameworks);net7.0-ios;net7.0-maccatalyst + net8.0-android + $(TargetFrameworks);net8.0-windows10.0.19041.0 + $(TargetFrameworks);net8.0-ios;net8.0-maccatalyst Exe Sentry.Samples.Maui true + true true enable false + true Sentry.Samples.Maui @@ -27,11 +29,11 @@ 1.0 1 - 10.0 + 11.0 13.1 21.0 10.0.17763.0 - 10.0.17763.0 + 10.0.17763.0 @@ -80,6 +92,7 @@ + diff --git a/samples/Sentry.Samples.NLog/Sentry.Samples.NLog.csproj b/samples/Sentry.Samples.NLog/Sentry.Samples.NLog.csproj index 203f645468..bd23bcf5b8 100644 --- a/samples/Sentry.Samples.NLog/Sentry.Samples.NLog.csproj +++ b/samples/Sentry.Samples.NLog/Sentry.Samples.NLog.csproj @@ -6,7 +6,7 @@ - + true diff --git a/samples/Sentry.Samples.OpenTelemetry.AspNetCore/FakeAuthHandler.cs b/samples/Sentry.Samples.OpenTelemetry.AspNetCore/FakeAuthHandler.cs index 5404e2dcfb..e88f603370 100644 --- a/samples/Sentry.Samples.OpenTelemetry.AspNetCore/FakeAuthHandler.cs +++ b/samples/Sentry.Samples.OpenTelemetry.AspNetCore/FakeAuthHandler.cs @@ -14,8 +14,7 @@ public class FakeAuthHandler : AuthenticationHandler options, ILoggerFactory logger, - UrlEncoder encoder, - ISystemClock clock) : base(options, logger, encoder, clock) + UrlEncoder encoder) : base(options, logger, encoder) { } diff --git a/samples/Sentry.Samples.OpenTelemetry.AspNetCore/Sentry.Samples.OpenTelemetry.AspNetCore.csproj b/samples/Sentry.Samples.OpenTelemetry.AspNetCore/Sentry.Samples.OpenTelemetry.AspNetCore.csproj index 0c32d2ffce..e2f0d0f360 100644 --- a/samples/Sentry.Samples.OpenTelemetry.AspNetCore/Sentry.Samples.OpenTelemetry.AspNetCore.csproj +++ b/samples/Sentry.Samples.OpenTelemetry.AspNetCore/Sentry.Samples.OpenTelemetry.AspNetCore.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable diff --git a/scripts/build-sentry-cocoa.sh b/scripts/build-sentry-cocoa.sh index b3f25c4d42..afe19d1170 100755 --- a/scripts/build-sentry-cocoa.sh +++ b/scripts/build-sentry-cocoa.sh @@ -10,7 +10,6 @@ rm -rf Carthage sdks=$(xcodebuild -showsdks) ios_sdk=$(echo "$sdks" | awk '/iOS SDKs/{getline; print $NF}') ios_simulator_sdk=$(echo "$sdks" | awk '/iOS Simulator SDKs/{getline; print $NF}') -macos_sdk=$(echo "$sdks" | awk '/macOS SDKs/{getline; print $NF}') # Note - We keep the build output in separate directories so that .NET # bundles iOS with net6.0-ios and Mac Catalyst with net6.0-maccatalyst. diff --git a/scripts/build-sentry-native.ps1 b/scripts/build-sentry-native.ps1 new file mode 100644 index 0000000000..c58395b85d --- /dev/null +++ b/scripts/build-sentry-native.ps1 @@ -0,0 +1,77 @@ +param([switch] $Clean) +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +Push-Location $PSScriptRoot/.. +try +{ + $submodule = 'modules/sentry-native' + $outDir = 'src/Sentry/Platforms/Native/sentry-native' + $buildDir = "$submodule/build" + $actualBuildDir = $buildDir + + $additionalArgs = @() + $libPrefix = 'lib' + $libExtension = '.a' + if ($IsMacOS) + { + $outDir += '/osx' + $additionalArgs += @('-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64') + $additionalArgs += @('-D', 'CMAKE_OSX_DEPLOYMENT_TARGET=12.0') + } + elseif ($IsWindows) + { + $outDir += '/win-x64' + $additionalArgs += @('-C', 'src/Sentry/Platforms/Native/windows-config.cmake') + $actualBuildDir = "$buildDir/RelWithDebInfo" + $libPrefix = '' + $libExtension = '.lib' + } + elseif ($IsLinux) + { + $outDir += '/linux-x64' + } + else + { + throw "Unsupported platform" + } + + git submodule update --init --recursive $submodule + + if ($Clean) + { + rm -rf $buildDir + } + + cmake ` + -S $submodule ` + -B $buildDir ` + -D CMAKE_BUILD_TYPE=RelWithDebInfo ` + -D SENTRY_SDK_NAME=sentry.native.dotnet ` + -D SENTRY_BUILD_SHARED_LIBS=0 ` + -D SENTRY_BACKEND=none ` + -D SENTRY_TRANSPORT=none ` + $additionalArgs + + cmake ` + --build $buildDir ` + --target sentry ` + --config RelWithDebInfo ` + --parallel + + $srcFile = "$actualBuildDir/${libPrefix}sentry$libExtension" + $outFile = "$outDir/${libPrefix}sentry-native$libExtension" + + # New-Item creates the directory if it doesn't exist. + New-Item -ItemType File -Path $outFile -Force | Out-Null + + Write-Host "Copying $srcFile to $outFile" + Copy-Item -Force -Path $srcFile -Destination $outFile + + # Touch the file to mark it as up-to-date for MSBuild + (Get-Item $outFile).LastWriteTime = Get-Date +} +finally +{ + Pop-Location +} diff --git a/scripts/device-test.ps1 b/scripts/device-test.ps1 new file mode 100644 index 0000000000..75de2c4373 --- /dev/null +++ b/scripts/device-test.ps1 @@ -0,0 +1,85 @@ +param( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [ValidateSet('android', 'ios')] # TODO , 'maccatalyst' + [String] $Platform, + + [Switch] $Build, + [Switch] $Run +) + +Set-StrictMode -Version latest +$ErrorActionPreference = "Stop" + +if (!$Build -and !$Run) +{ + $Build = $true + $Run = $true +} +$CI = Test-Path env:CI + +Push-Location $PSScriptRoot/.. +try +{ + $tfm = 'net7.0-' + $arch = $(uname -m) -eq 'arm64' ? 'arm64' : 'x64' + if ($Platform -eq 'android') + { + $tfm += 'android' + $group = 'android' + $buildDir = $CI ? 'bin' : "test/Sentry.Maui.Device.TestApp/bin/Release/$tfm/android-$arch" + $arguments = @( + '--app', "$buildDir/io.sentry.dotnet.maui.device.testapp-Signed.apk", + '--package-name', 'io.sentry.dotnet.maui.device.testapp' + ) + } + elseif ($Platform -eq 'ios') + { + $tfm += 'ios' + $group = 'apple' + $buildDir = $CI ? 'bin' : "test/Sentry.Maui.Device.TestApp/bin/Release/$tfm/iossimulator-$arch" + $arguments = @( + '--app', "$buildDir/Sentry.Maui.Device.TestApp.app", + '--target', 'ios-simulator-64', + '--launch-timeout', '00:10:00' + ) + } + + if ($Build) + { + dotnet build -f $tfm -c Release test/Sentry.Maui.Device.TestApp + if ($LASTEXITCODE -ne 0) + { + throw "Failed to build Sentry.Maui.Device.TestApp" + } + } + + if ($Run) + { + if (!(Get-Command xharness -ErrorAction SilentlyContinue)) + { + Push-Location ($CI ? $env:RUNNER_TEMP : $IsWindows ? $env:TMP : $IsMacos ? $env:TMPDIR : '/temp') + dotnet tool install Microsoft.DotNet.XHarness.CLI --global --version "1.*-*" ` + --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json + Pop-Location + } + + Remove-Item -Recurse -Force test_output -ErrorAction SilentlyContinue + try + { + xharness $group test $arguments --output-directory=test_output + if ($LASTEXITCODE -ne 0) + { + throw "xharness run failed with non-zero exit code" + } + } + finally + { + scripts/parse-xunit2-xml.ps1 ./test_output/TestResults.xml | Out-File $env:GITHUB_STEP_SUMMARY + } + } +} +finally +{ + Pop-Location +} diff --git a/scripts/generate-cocoa-bindings.ps1 b/scripts/generate-cocoa-bindings.ps1 index daf36d9221..a49124802f 100644 --- a/scripts/generate-cocoa-bindings.ps1 +++ b/scripts/generate-cocoa-bindings.ps1 @@ -7,27 +7,43 @@ $BindingsPath = "$RootPath/src/Sentry.Bindings.Cocoa" $BackupPath = "$BindingsPath/obj/_unpatched" # Ensure running on macOS -if (!$IsMacOS) { +if (!$IsMacOS) +{ Write-Error 'Bindings generation can only be performed on macOS.' ` -CategoryActivity Error -ErrorAction Stop } # Ensure Objective Sharpie is installed -if (!(Get-Command sharpie -ErrorAction SilentlyContinue)) { - Write-Output 'Objective Sharpie not found. Attempting to install via Homebrew.' +if (!(Get-Command sharpie -ErrorAction SilentlyContinue)) +{ + Write-Output 'Objective Sharpie not found. Attempting to install via Homebrew.' brew install --cask objectivesharpie + + if (!(Get-Command sharpie -ErrorAction SilentlyContinue)) + { + Write-Error 'Could not install Objective Sharpie automatically. Try installing from https://aka.ms/objective-sharpie manually.' + } } -if (!(Get-Command sharpie -ErrorAction SilentlyContinue)) { - Write-Error 'Could not install Objective Sharpie automatically. Try installing from https://aka.ms/objective-sharpie manually.' ` - -CategoryActivity Error -ErrorAction Stop + +# Ensure Xamarin is installed (or sharpie won't produce expected output). +if (!(Test-Path '/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/64bits/iOS/Xamarin.iOS.dll')) +{ + Write-Output 'Xamarin.iOS not found. Attempting to install via Homebrew.' + brew install --cask xamarin-ios + + if (!(Test-Path '/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/64bits/iOS/Xamarin.iOS.dll')) + { + Write-Error 'Xamarin.iOS not found. Try installing manually from: https://learn.microsoft.com/en-us/xamarin/ios/get-started/installation/.' + } } # Get iPhone SDK version $iPhoneSdkVersion = sharpie xcode -sdks | grep -o -m 1 'iphoneos\S*' +Write-Output "iPhoneSdkVersion: $iPhoneSdkVersion" # Generate bindings Write-Output 'Generating bindings with Objective Sharpie.' -sharpie bind -sdk $iPhoneSdkVersion -quiet ` +sharpie bind -sdk $iPhoneSdkVersion ` -scope "$CocoaSdkPath/Carthage/Headers" ` "$CocoaSdkPath/Carthage/Headers/Sentry.h" ` "$CocoaSdkPath/Carthage/Headers/PrivateSentrySDKOnly.h" ` @@ -35,7 +51,8 @@ sharpie bind -sdk $iPhoneSdkVersion -quiet ` -c -Wno-objc-property-no-attribute # Ensure backup path exists -if (!(Test-Path $BackupPath)) { +if (!(Test-Path $BackupPath)) +{ New-Item -ItemType Directory -Path $BackupPath | Out-Null } @@ -122,7 +139,7 @@ $Text = $Text -replace '(?ms)@protocol (SentrySerializable|SentrySpan).+?\[Proto $Text = $Text -replace 'interface SentrySpan\b', "[BaseType (typeof(NSObject))]`n`$&" # Fix string constants -$Text = $Text -replace 'byte\[\] SentryVersionString', "[return: PlainString]`n NSString SentryVersionString" +$Text = $Text -replace 'byte\[\] SentryVersionString', "[PlainString]`n NSString SentryVersionString" $Text = $Text -replace '(?m)(.*\n){2}^\s{4}NSString k.+?\n\n?', '' $Text = $Text -replace '(?m)(.*\n){4}^partial interface Constants\n{\n}\n', '' $Text = $Text -replace '\[Verify \(ConstantsInterfaceAssociation\)\]\n', '' @@ -156,6 +173,9 @@ $Text = $Text -replace '([\[,] )iOS \(', '$1Introduced (PlatformName.iOS, ' # Make interface partial if we need to access private APIs. Other parts will be defined in PrivateApiDefinitions.cs $Text = $Text -replace '(?m)^interface SentryScope', 'partial $&' +# Prefix SentryBreadcrumb.Serialize and SentryScope.Serialize with new (since these hide the base method) +$Text = $Text -replace '(?m)(^\s*\/\/[^\r\n]*$\s*\[Export \("serialize"\)\]$\s*)(NSDictionary)', '${1}new $2' + # Add header and output file $Text = "$Header`n`n$Text" $Text | Out-File "$BindingsPath/$File" diff --git a/scripts/generate-solution-filters-config.yaml b/scripts/generate-solution-filters-config.yaml index 451ad4dc7a..80900ec608 100644 --- a/scripts/generate-solution-filters-config.yaml +++ b/scripts/generate-solution-filters-config.yaml @@ -3,7 +3,12 @@ # the *.slnf solution filters for the Sentry solution. ################################################################ -defaultSolution: Sentry.sln +coreSolution: Sentry.sln +# We don't maintain the buildSolutions manually... these are just +# copies of Sentry.sln that are used to set certain build +# properties when using solution filters that are based on these +buildSolutions: + - Sentry.NoMobile.sln groupConfigs: allProjects: @@ -135,7 +140,8 @@ filterConfigs: - "samples/**/*Maui.csproj" - "src/**/Sentry.csproj" - "src/**/*Android*.csproj" - - "src/**/*Bindings*.csproj" + - "src/**/*Bindings.Android.csproj" + - "src/**/*Bindings.Cocoa.csproj" - "src/**/Sentry.Extensions.Logging.csproj" - "src/**/Sentry.Maui.csproj" - "test/**/Sentry.Android.AssemblyReader.Tests.csproj" diff --git a/scripts/generate-solution-filters.ps1 b/scripts/generate-solution-filters.ps1 index 9c7bf9fb45..6ba5501807 100644 --- a/scripts/generate-solution-filters.ps1 +++ b/scripts/generate-solution-filters.ps1 @@ -124,7 +124,7 @@ foreach ($filter in $config.filterConfigs) } else { - $config.defaultSolution + $config.coreSolution } $content = "{ `"solution`": { @@ -160,7 +160,9 @@ foreach ($filter in $config.filterConfigs) Write-Debug "Created $outputPath" } -# Update solution files from Sentry.sln -$source = Join-Path $repoRoot "Sentry.sln" -$destination = Join-Path $repoRoot "Sentry.NoMobile.sln" -Copy-Item -Path $source -Destination $destination -Force +# Copy the Core solution to each of the required build solutions +$source = Join-Path $repoRoot $config.coreSolution +foreach ($buildSolution in $config.buildSolutions) { + $destination = Join-Path $repoRoot $buildSolution + Copy-Item -Path $source -Destination $destination -Force +} diff --git a/scripts/run-android-tests.cmd b/scripts/run-android-tests.cmd deleted file mode 100644 index e125fd9c64..0000000000 --- a/scripts/run-android-tests.cmd +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -setlocal - -pushd %~dp0 - -where xharness >nul 2>nul -if %ERRORLEVEL% NEQ 0 dotnet tool install Microsoft.DotNet.XHarness.CLI --global --version "1.*-*" - -dotnet build -f net6.0-android ..\test\Sentry.Maui.Device.TestApp -if %ERRORLEVEL% NEQ 0 goto end - -if exist ..\test_output rmdir /q /s ..\test_output -xharness android test ^ - --app=..\test\Sentry.Maui.Device.TestApp\bin\Debug\net6.0-android\io.sentry.dotnet.maui.device.testapp-Signed.apk ^ - --package-name=io.sentry.dotnet.maui.device.testapp ^ - --output-directory=..\test_output - -:end -popd diff --git a/scripts/run-android-tests.sh b/scripts/run-android-tests.sh deleted file mode 100755 index 2fd0de634e..0000000000 --- a/scripts/run-android-tests.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -pushd "$(dirname "$0")" > /dev/null - -if ! command -v xharness &> /dev/null -then - dotnet tool install Microsoft.DotNet.XHarness.CLI --global --version "1.*-*" -fi - -dotnet build -f net7.0-android ../test/Sentry.Maui.Device.TestApp - -if [ $? -eq 0 ] -then - rm -rf ../test_output - xharness android test \ - --app=../test/Sentry.Maui.Device.TestApp/bin/Debug/net7.0-android/io.sentry.dotnet.maui.device.testapp-Signed.apk \ - --package-name=io.sentry.dotnet.maui.device.testapp \ - --output-directory=../test_output -fi - -popd > /dev/null diff --git a/scripts/run-ios-tests.sh b/scripts/run-ios-tests.sh deleted file mode 100755 index fae3196435..0000000000 --- a/scripts/run-ios-tests.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -pushd "$(dirname "$0")" > /dev/null - -if ! command -v xharness &> /dev/null -then - dotnet tool install Microsoft.DotNet.XHarness.CLI --global --version "1.*-*" -fi - -dotnet build -f net7.0-ios ../test/Sentry.Maui.Device.TestApp - -if [ $? -eq 0 ] -then - [ "$(arch)" == "arm64" ] && ARCH="arm64" || ARCH="x64" - rm -rf ../test_output - xharness apple test \ - --app=../test/Sentry.Maui.Device.TestApp/bin/Debug/net7.0-ios/iossimulator-$ARCH/Sentry.Maui.Device.TestApp.app \ - --target=ios-simulator-64 \ - --output-directory=../test_output -fi - -popd > /dev/null diff --git a/src/Directory.Build.props b/src/Directory.Build.props index a8e22854c2..74cda5ab08 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -35,6 +35,16 @@ $(MSBuildThisFileDirectory)CodeAnalysis.ruleset + + + + true + + $(MSBuildThisFileDirectory)..\CHANGELOG.md @@ -53,7 +63,6 @@ - diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 7320fc0101..7ffee328bd 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -3,7 +3,7 @@ - + enable diff --git a/src/Sentry.AspNet/HttpContextExtensions.cs b/src/Sentry.AspNet/HttpContextExtensions.cs index 6d0466caa1..8312729986 100644 --- a/src/Sentry.AspNet/HttpContextExtensions.cs +++ b/src/Sentry.AspNet/HttpContextExtensions.cs @@ -26,7 +26,7 @@ public static class HttpContextExtensions } catch (Exception ex) { - options?.LogError("Invalid Sentry trace header '{0}'.", ex, value); + options?.LogError(ex, "Invalid Sentry trace header '{0}'.", value); return null; } } @@ -50,7 +50,7 @@ public static class HttpContextExtensions } catch (Exception ex) { - options?.LogError("Invalid baggage header '{0}'.", ex, value); + options?.LogError(ex, "Invalid baggage header '{0}'.", value); return null; } } @@ -77,7 +77,7 @@ public static void StartOrContinueTrace(this HttpContext httpContext) /// /// Starts a new Sentry transaction that encompasses the currently executing HTTP request. /// - public static ITransaction StartSentryTransaction(this HttpContext httpContext) + public static ITransactionTracer StartSentryTransaction(this HttpContext httpContext) { var method = httpContext.Request.HttpMethod; var path = httpContext.Request.Path; diff --git a/src/Sentry.AspNet/Sentry.AspNet.csproj b/src/Sentry.AspNet/Sentry.AspNet.csproj index 58aaa712ba..17e56584de 100644 --- a/src/Sentry.AspNet/Sentry.AspNet.csproj +++ b/src/Sentry.AspNet/Sentry.AspNet.csproj @@ -1,7 +1,7 @@ - net461 + net462 $(PackageTags);AspNet;MVC Official ASP.NET integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. diff --git a/src/Sentry.AspNetCore.Grpc/Sentry.AspNetCore.Grpc.csproj b/src/Sentry.AspNetCore.Grpc/Sentry.AspNetCore.Grpc.csproj index cc14bb5f3f..4fdafcee61 100644 --- a/src/Sentry.AspNetCore.Grpc/Sentry.AspNetCore.Grpc.csproj +++ b/src/Sentry.AspNetCore.Grpc/Sentry.AspNetCore.Grpc.csproj @@ -1,7 +1,7 @@ - net6.0;net5.0;netcoreapp3.0 + net6.0 $(PackageTags);AspNetCore;gRPC Official ASP.NET Core gRPC integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. diff --git a/src/Sentry.AspNetCore/ApplicationBuilderExtensions.cs b/src/Sentry.AspNetCore/ApplicationBuilderExtensions.cs index 3f8b5510d0..52b6433db1 100644 --- a/src/Sentry.AspNetCore/ApplicationBuilderExtensions.cs +++ b/src/Sentry.AspNetCore/ApplicationBuilderExtensions.cs @@ -1,8 +1,4 @@ -#if NETSTANDARD2_0 -using IHostApplicationLifetime = Microsoft.AspNetCore.Hosting.IApplicationLifetime; -#else using Microsoft.Extensions.Hosting; -#endif using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/Sentry.AspNetCore/BindableSentryAspNetCoreOptions.cs b/src/Sentry.AspNetCore/BindableSentryAspNetCoreOptions.cs new file mode 100644 index 0000000000..35cac5b05e --- /dev/null +++ b/src/Sentry.AspNetCore/BindableSentryAspNetCoreOptions.cs @@ -0,0 +1,34 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Sentry.Extensibility; +using Sentry.Extensions.Logging; + +#if NETSTANDARD2_0 +using IWebHostEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment; +#else +using Microsoft.Extensions.Hosting; +#endif + +namespace Sentry.AspNetCore; + +/// +internal class BindableSentryAspNetCoreOptions : BindableSentryLoggingOptions +{ + public bool? IncludeActivityData { get; set; } + public RequestSize? MaxRequestBodySize { get; set; } + public bool? FlushOnCompletedRequest { get; set; } + public bool? FlushBeforeRequestCompleted { get; set; } + public bool? AdjustStandardEnvironmentNameCasing { get; set; } + public bool? AutoRegisterTracing { get; set; } + + public void ApplyTo(SentryAspNetCoreOptions options) + { + base.ApplyTo(options); + options.IncludeActivityData = IncludeActivityData ?? options.IncludeActivityData; + options.MaxRequestBodySize = MaxRequestBodySize ?? options.MaxRequestBodySize; + options.FlushOnCompletedRequest = FlushOnCompletedRequest ?? options.FlushOnCompletedRequest; + options.FlushBeforeRequestCompleted = FlushBeforeRequestCompleted ?? options.FlushBeforeRequestCompleted; + options.AdjustStandardEnvironmentNameCasing = AdjustStandardEnvironmentNameCasing ?? options.AdjustStandardEnvironmentNameCasing; + options.AutoRegisterTracing = AutoRegisterTracing ?? options.AutoRegisterTracing; + } +} diff --git a/src/Sentry.AspNetCore/DefaultUserFactory.cs b/src/Sentry.AspNetCore/DefaultUserFactory.cs index df56b5baa4..2d760e72f1 100644 --- a/src/Sentry.AspNetCore/DefaultUserFactory.cs +++ b/src/Sentry.AspNetCore/DefaultUserFactory.cs @@ -2,9 +2,7 @@ namespace Sentry.AspNetCore; -#pragma warning disable CS0618 -internal class DefaultUserFactory : IUserFactory, ISentryUserFactory -#pragma warning restore CS0618 +internal class DefaultUserFactory : ISentryUserFactory { private readonly IHttpContextAccessor? _httpContextAccessor; diff --git a/src/Sentry.AspNetCore/Extensions/DependencyInjection/ServiceCollectionExtensions.cs b/src/Sentry.AspNetCore/Extensions/DependencyInjection/ServiceCollectionExtensions.cs index 98c9415c6b..2b9166646b 100644 --- a/src/Sentry.AspNetCore/Extensions/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Sentry.AspNetCore/Extensions/DependencyInjection/ServiceCollectionExtensions.cs @@ -23,9 +23,6 @@ public static ISentryBuilder AddSentry(this IServiceCollection services) services.AddSingleton(); services.AddHttpContextAccessor(); -#pragma warning disable CS0618 - services.TryAddSingleton(); -#pragma warning restore CS0618 services.TryAddSingleton(); services diff --git a/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs b/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs index 8f51a8576a..d82a9bf04a 100644 --- a/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs +++ b/src/Sentry.AspNetCore/Extensions/HttpContextExtensions.cs @@ -2,9 +2,7 @@ using Microsoft.AspNetCore.Routing; using Sentry.Extensibility; -#if !NETSTANDARD2_0 using Microsoft.AspNetCore.Http.Features; -#endif namespace Sentry.AspNetCore.Extensions; @@ -12,7 +10,6 @@ internal static class HttpContextExtensions { internal static string? TryGetRouteTemplate(this HttpContext context) { -#if !NETSTANDARD2_0 // endpoint routing is only supported after ASP.NET Core 3.0 // Requires .UseRouting()/.UseEndpoints() var endpoint = context.Features.Get()?.Endpoint as RouteEndpoint; var routePattern = endpoint?.RoutePattern.RawText; @@ -23,7 +20,7 @@ internal static class HttpContextExtensions { return formattedRoute; } -#endif + // Fallback for legacy .UseMvc(). // Note: GetRouteData can return null on netstandard2 return (context.GetRouteData() is { } routeData) @@ -60,11 +57,11 @@ internal static class HttpContextExtensions try { - return SentryTraceHeader.Parse(value); + return SentryTraceHeader.Parse(value!); } catch (Exception ex) { - options?.LogError("Invalid Sentry trace header '{0}'.", ex, value); + options?.LogError(ex, "Invalid Sentry trace header '{0}'.", value); return null; } } @@ -84,11 +81,11 @@ internal static class HttpContextExtensions try { - return BaggageHeader.TryParse(value, onlySentry: true); + return BaggageHeader.TryParse(value!, onlySentry: true); } catch (Exception ex) { - options?.LogError("Invalid baggage header '{0}'.", ex, value); + options?.LogError(ex, "Invalid baggage header '{0}'.", value); return null; } } diff --git a/src/Sentry.AspNetCore/IUserFactory.cs b/src/Sentry.AspNetCore/IUserFactory.cs deleted file mode 100644 index 32d5a09f9c..0000000000 --- a/src/Sentry.AspNetCore/IUserFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace Sentry.AspNetCore; - -/// -/// Sentry User Factory -/// -[Obsolete("This interface is tightly coupled to AspNetCore and will be removed in version 4.0.0. Please consider using ISentryUserFactory with IHttpContextAccessor instead.")] -public interface IUserFactory -{ - /// - /// Creates a from the - /// - /// The HttpContext where the user resides - /// The protocol user - User? Create(HttpContext context); -} diff --git a/src/Sentry.AspNetCore/RouteUtils.cs b/src/Sentry.AspNetCore/RouteUtils.cs index 90bd231448..33754ca24a 100644 --- a/src/Sentry.AspNetCore/RouteUtils.cs +++ b/src/Sentry.AspNetCore/RouteUtils.cs @@ -35,7 +35,9 @@ internal static class RouteUtils builder.Append(routePattern); } - return builder.ToString(); + // Force a leading slash (if there isn't already one present) + var url = builder.ToString(); + return url.Length >0 && url[0] == '/' ? url : $"/{url}"; } // Internal for testing. diff --git a/src/Sentry.AspNetCore/ScopeExtensions.cs b/src/Sentry.AspNetCore/ScopeExtensions.cs index 10249aa492..a8e33677a7 100644 --- a/src/Sentry.AspNetCore/ScopeExtensions.cs +++ b/src/Sentry.AspNetCore/ScopeExtensions.cs @@ -38,10 +38,8 @@ public static void Populate(this Scope scope, HttpContext context, SentryAspNetC if (options.SendDefaultPii && !scope.HasUser()) { -#pragma warning disable CS0618 - var userFactory = context.RequestServices.GetService(); - var user = userFactory?.Create(context); -#pragma warning restore CS0618 + var userFactory = context.RequestServices.GetService(); + var user = userFactory?.Create(); if (user != null) { @@ -64,7 +62,7 @@ public static void Populate(this Scope scope, HttpContext context, SentryAspNetC } catch (Exception e) { - options.LogError("Failed to extract body.", e); + options.LogError(e, "Failed to extract body."); } SetEnv(scope, context, options); @@ -142,7 +140,7 @@ private static void SetEnv(Scope scope, HttpContext context, SentryAspNetCoreOpt continue; } - scope.Request.Headers[requestHeader.Key] = requestHeader.Value; + scope.Request.Headers[requestHeader.Key] = requestHeader.Value!; if (requestHeader.Key == HeaderNames.Cookie) { @@ -163,7 +161,7 @@ private static void SetEnv(Scope scope, HttpContext context, SentryAspNetCoreOpt if (context.Response.Headers.TryGetValue("Server", out var server)) { - scope.Request.Env["SERVER_SOFTWARE"] = server; + scope.Request.Env["SERVER_SOFTWARE"] = server!; } } diff --git a/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj b/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj index a63694bb01..22e4a40824 100644 --- a/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj +++ b/src/Sentry.AspNetCore/Sentry.AspNetCore.csproj @@ -1,31 +1,23 @@  - net6.0;net5.0;netcoreapp3.0;netstandard2.0 + net8.0;net6.0 $(PackageTags);AspNetCore;MVC Official ASP.NET Core integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. + + true + true + + + - - - - - - - - - - - - - - - - + + diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreOptions.cs b/src/Sentry.AspNetCore/SentryAspNetCoreOptions.cs index 2ee73c5b7f..0ea06a680f 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreOptions.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreOptions.cs @@ -3,12 +3,7 @@ using Microsoft.AspNetCore.Http; using Sentry.Extensibility; using Sentry.Extensions.Logging; - -#if NETSTANDARD2_0 -using IWebHostEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment; -#else using Microsoft.Extensions.Hosting; -#endif namespace Sentry.AspNetCore; diff --git a/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs b/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs index f235b7540e..1055237cd1 100644 --- a/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs +++ b/src/Sentry.AspNetCore/SentryAspNetCoreOptionsSetup.cs @@ -1,18 +1,16 @@ +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging.Configuration; using Microsoft.Extensions.Options; using Sentry.Extensions.Logging; -#if NETSTANDARD2_0 -using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment; -#else using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IWebHostEnvironment; -#endif namespace Sentry.AspNetCore; /// /// Sets up ASP.NET Core option for Sentry. /// +#if NETSTANDARD2_0 public class SentryAspNetCoreOptionsSetup : ConfigureFromConfigurationOptions { /// @@ -24,24 +22,59 @@ public SentryAspNetCoreOptionsSetup( { } + /// + /// Configures the . + /// + public override void Configure(SentryAspNetCoreOptions options) + { + base.Configure(options); + options.AddDiagnosticSourceIntegration(); + options.DeduplicateUnhandledException(); + } +} + +#else +public class SentryAspNetCoreOptionsSetup : IConfigureOptions +{ + private readonly IConfiguration _config; + /// /// Creates a new instance of . /// - [Obsolete("Use constructor with no IHostingEnvironment")] - public SentryAspNetCoreOptionsSetup( - ILoggerProviderConfiguration providerConfiguration, - IHostingEnvironment hostingEnvironment) - : base(providerConfiguration.Configuration) + public SentryAspNetCoreOptionsSetup(ILoggerProviderConfiguration providerConfiguration) + : this(providerConfiguration.Configuration) { } + /// + /// Creates a new instance of . + /// + internal SentryAspNetCoreOptionsSetup(IConfiguration config) + { + ArgumentNullException.ThrowIfNull(config); + _config = config; + } + /// /// Configures the . /// - public override void Configure(SentryAspNetCoreOptions options) + public void Configure(SentryAspNetCoreOptions options) { - base.Configure(options); + ArgumentNullException.ThrowIfNull(options); + var bindable = new BindableSentryAspNetCoreOptions(); + _config.Bind(bindable); + bindable.ApplyTo(options); + + options.DeduplicateUnhandledException(); + } +} +#endif + +internal static class SentryAspNetCoreOptionsExtensions +{ + internal static void DeduplicateUnhandledException(this SentryAspNetCoreOptions options) + { options.AddLogEntryFilter((category, _, eventId, _) // https://github.com/aspnet/KestrelHttpServer/blob/0aff4a0440c2f393c0b98e9046a8e66e30a56cb0/src/Kestrel.Core/Internal/Infrastructure/KestrelTrace.cs#L33 // 13 = Application unhandled exception, which is captured by the middleware so the LogError of kestrel ends up as a duplicate with less info @@ -50,9 +83,5 @@ public override void Configure(SentryAspNetCoreOptions options) category, "Microsoft.AspNetCore.Server.Kestrel", StringComparison.Ordinal)); - -#if NETSTANDARD2_0 - options.AddDiagnosticSourceIntegration(); -#endif } } diff --git a/src/Sentry.AspNetCore/SentryMiddleware.cs b/src/Sentry.AspNetCore/SentryMiddleware.cs index ed83eb8f72..f674b24d6a 100644 --- a/src/Sentry.AspNetCore/SentryMiddleware.cs +++ b/src/Sentry.AspNetCore/SentryMiddleware.cs @@ -1,9 +1,5 @@ using Microsoft.AspNetCore.Diagnostics; -#if NETSTANDARD2_0 -using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment; -#else using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IWebHostEnvironment; -#endif using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/Sentry.AspNetCore/SentryTracingMiddleware.cs b/src/Sentry.AspNetCore/SentryTracingMiddleware.cs index 4ee4532b1d..7cefd8af55 100644 --- a/src/Sentry.AspNetCore/SentryTracingMiddleware.cs +++ b/src/Sentry.AspNetCore/SentryTracingMiddleware.cs @@ -27,7 +27,7 @@ public SentryTracingMiddleware( _options = options.Value; } - private ITransaction? TryStartTransaction(HttpContext context) + private ITransactionTracer? TryStartTransaction(HttpContext context) { if (context.Request.Method == HttpMethod.Options.Method) { @@ -90,7 +90,7 @@ public SentryTracingMiddleware( } catch (Exception ex) { - _options.LogError("Failed to start transaction.", ex); + _options.LogError(ex, "Failed to start transaction."); return null; } } diff --git a/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs b/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs index 66b2e1055a..2278f61a01 100644 --- a/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs +++ b/src/Sentry.AspNetCore/SentryTunnelMiddleware.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; +using Sentry.Internal.Extensions; namespace Sentry.AspNetCore; @@ -29,10 +30,14 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next) var request = context.Request; if (request.Method == "OPTIONS") { - headers.Add("Access-Control-Allow-Origin", new[] { (string)request.Headers["Origin"] }); - headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" }); - headers.Add("Access-Control-Allow-Methods", new[] { "POST, OPTIONS" }); - headers.Add("Access-Control-Allow-Credentials", new[] { "true" }); + if (request.Headers.TryGetValue("Origin", out var origin) && !string.IsNullOrEmpty(origin)) + { + headers.Append("Access-Control-Allow-Origin", (string)origin!); + } + + headers.Append("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + headers.Append("Access-Control-Allow-Methods", "POST, OPTIONS"); + headers.Append("Access-Control-Allow-Credentials", "true"); response.StatusCode = 200; return; } @@ -66,7 +71,14 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next) try { +#if NETSTANDARD2_0 var headerJson = JsonSerializer.Deserialize>(header); +#else + var headerJson = JsonSerializer.Deserialize( + header, + SentryJsonContext.Default.DictionaryStringObject + ); +#endif if (headerJson == null) { response.StatusCode = StatusCodes.Status400BadRequest; diff --git a/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs b/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs index ee83bf9560..931da5bcf2 100644 --- a/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs +++ b/src/Sentry.AspNetCore/SentryWebHostBuilderExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Configuration; @@ -83,8 +84,13 @@ public static IWebHostBuilder UseSentry( logging.AddConfiguration(); var section = context.Configuration.GetSection("Sentry"); +#if NETSTANDARD2_0 _ = logging.Services.Configure(section); - +#else + _ = logging.Services.AddSingleton>(_ => + new SentryAspNetCoreOptionsSetup(section) + ); +#endif _ = logging.Services .AddSingleton, SentryAspNetCoreOptionsSetup>(); _ = logging.Services.AddSingleton(); diff --git a/src/Sentry.Azure.Functions.Worker/HttpRequestDataExtensions.cs b/src/Sentry.Azure.Functions.Worker/HttpRequestDataExtensions.cs index 168dad89cf..194e8dcd6f 100644 --- a/src/Sentry.Azure.Functions.Worker/HttpRequestDataExtensions.cs +++ b/src/Sentry.Azure.Functions.Worker/HttpRequestDataExtensions.cs @@ -25,7 +25,7 @@ internal static class HttpRequestDataExtensions } catch (Exception ex) { - logger?.LogError("Invalid Sentry trace header '{0}'.", ex, traceHeaderValue); + logger?.LogError(ex, "Invalid Sentry trace header '{0}'.", traceHeaderValue); return null; } } @@ -53,7 +53,7 @@ internal static class HttpRequestDataExtensions } catch (Exception ex) { - logger?.LogError("Invalid baggage header '{0}'.", ex, baggageValue); + logger?.LogError(ex, "Invalid baggage header '{0}'.", baggageValue); return null; } } diff --git a/src/Sentry.Azure.Functions.Worker/Sentry.Azure.Functions.Worker.csproj b/src/Sentry.Azure.Functions.Worker/Sentry.Azure.Functions.Worker.csproj index 96ba7b4cc4..6d2be7ab2b 100644 --- a/src/Sentry.Azure.Functions.Worker/Sentry.Azure.Functions.Worker.csproj +++ b/src/Sentry.Azure.Functions.Worker/Sentry.Azure.Functions.Worker.csproj @@ -1,7 +1,7 @@ - net6.0;netstandard2.0 + net8.0;net6.0;netstandard2.0 $(PackageTags);Azure;Functions;Worker Official Azure Functions Worker SDK integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. diff --git a/src/Sentry.Bindings.Android/Sentry.Bindings.Android.csproj b/src/Sentry.Bindings.Android/Sentry.Bindings.Android.csproj index e72cd60526..862538a3bd 100644 --- a/src/Sentry.Bindings.Android/Sentry.Bindings.Android.csproj +++ b/src/Sentry.Bindings.Android/Sentry.Bindings.Android.csproj @@ -1,6 +1,6 @@ - net6.0-android + net7.0-android $(NoWarn);BG8605;BG8606 6.34.0 diff --git a/src/Sentry.Bindings.Android/Transforms/Metadata.xml b/src/Sentry.Bindings.Android/Transforms/Metadata.xml index 5eb4fdec60..cce1774c37 100644 --- a/src/Sentry.Bindings.Android/Transforms/Metadata.xml +++ b/src/Sentry.Bindings.Android/Transforms/Metadata.xml @@ -26,7 +26,8 @@ Sentry.JavaSdk.Android.Ndk Sentry.JavaSdk.Android.Supplemental Sentry.JavaSdk.Cache - Sentry.JavaSdk.ClientReport + + Sentry.JavaSdk.ClientReports Sentry.JavaSdk.Config Sentry.JavaSdk.Exception Sentry.JavaSdk.Hints diff --git a/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs b/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs index cf00679207..1a3ca18413 100644 --- a/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs +++ b/src/Sentry.Bindings.Cocoa/ApiDefinitions.cs @@ -20,7 +20,7 @@ partial interface Constants // extern const unsigned char[] SentryVersionString; [Field ("SentryVersionString", "__Internal")] - [return: PlainString] + [PlainString] NSString SentryVersionString { get; } } @@ -151,7 +151,7 @@ interface SentryBreadcrumb : SentrySerializable // -(NSDictionary * _Nonnull)serialize; [Export ("serialize")] - NSDictionary Serialize(); + new NSDictionary Serialize(); // -(BOOL)isEqualToBreadcrumb:(SentryBreadcrumb * _Nonnull)breadcrumb; [Export ("isEqualToBreadcrumb:")] @@ -1802,7 +1802,7 @@ partial interface SentryScope : SentrySerializable // -(NSDictionary * _Nonnull)serialize; [Export ("serialize")] - NSDictionary Serialize(); + new NSDictionary Serialize(); // -(void)setContextValue:(NSDictionary * _Nonnull)value forKey:(NSString * _Nonnull)key __attribute__((swift_name("setContext(value:key:)"))); [Export ("setContextValue:forKey:")] diff --git a/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj b/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj index 33d67537bb..773c19feee 100644 --- a/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj +++ b/src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj @@ -1,9 +1,9 @@ - net6.0-ios;net6.0-maccatalyst - net6.0-ios - net6.0-maccatalyst + net7.0-ios;net7.0-maccatalyst + net7.0-ios + net7.0-maccatalyst true true .NET Bindings for the Sentry Cocoa SDK @@ -45,7 +45,7 @@ - diff --git a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFCommandDiagnosticSourceHelper.cs b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFCommandDiagnosticSourceHelper.cs index 1d600b7365..14d67caf69 100644 --- a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFCommandDiagnosticSourceHelper.cs +++ b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFCommandDiagnosticSourceHelper.cs @@ -24,7 +24,7 @@ private static void SetCommandId(ISpan span, Guid? commandId) private static Guid? TryGetCommandId(ISpan span) => span.Extra.TryGetValue(EFKeys.DbCommandId); - protected override ISpan? GetSpanReference(ITransaction transaction, object? diagnosticSourceValue) + protected override ISpan? GetSpanReference(ITransactionTracer transaction, object? diagnosticSourceValue) { if (GetCommandId(diagnosticSourceValue) is { } commandId) { diff --git a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFConnectionDiagnosticSourceHelper.cs b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFConnectionDiagnosticSourceHelper.cs index 61bff526d9..50ac30fb65 100644 --- a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFConnectionDiagnosticSourceHelper.cs +++ b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFConnectionDiagnosticSourceHelper.cs @@ -13,7 +13,7 @@ internal EFConnectionDiagnosticSourceHelper(IHub hub, SentryOptions options) : b protected override string? GetDescription(object? diagnosticSourceValue) => GetDatabaseName(diagnosticSourceValue); - protected override ISpan? GetSpanReference(ITransaction transaction, object? diagnosticSourceValue) + protected override ISpan? GetSpanReference(ITransactionTracer transaction, object? diagnosticSourceValue) { if (GetConnectionId(diagnosticSourceValue) is { } connectionId) { diff --git a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFDiagnosticSourceHelper.cs b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFDiagnosticSourceHelper.cs index 48dcfc2eef..9dcf190e6b 100644 --- a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFDiagnosticSourceHelper.cs +++ b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFDiagnosticSourceHelper.cs @@ -6,7 +6,7 @@ namespace Sentry.Internal.DiagnosticSource; internal abstract class EFDiagnosticSourceHelper { protected SentryOptions Options { get; } - protected ITransaction? Transaction { get; } + protected ITransactionTracer? Transaction { get; } protected abstract string Operation { get; } protected abstract string? GetDescription(object? diagnosticSourceValue); @@ -140,7 +140,7 @@ protected void LogTransactionSpans() return str?[(str.IndexOf('\n') + 1)..]; } - protected abstract ISpan? GetSpanReference(ITransaction transaction, object? diagnosticSourceValue); + protected abstract ISpan? GetSpanReference(ITransactionTracer transaction, object? diagnosticSourceValue); protected abstract void SetSpanReference(ISpan span, object? diagnosticSourceValue); } diff --git a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFQueryCompilerDiagnosticSourceHelper.cs b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFQueryCompilerDiagnosticSourceHelper.cs index c056ab0da0..db0aae4929 100644 --- a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFQueryCompilerDiagnosticSourceHelper.cs +++ b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/EFQueryCompilerDiagnosticSourceHelper.cs @@ -13,7 +13,7 @@ internal EFQueryCompilerDiagnosticSourceHelper(IHub hub, SentryOptions options) /// /// We don't have a correlation id for compiled query events. We just return the first unfinished query compile span. /// - protected override ISpan? GetSpanReference(ITransaction transaction, object? diagnosticSourceValue) => + protected override ISpan? GetSpanReference(ITransactionTracer transaction, object? diagnosticSourceValue) => transaction.Spans .FirstOrDefault(span => !span.IsFinished && span.Operation == Operation); protected override void SetSpanReference(ISpan span, object? diagnosticSourceValue) diff --git a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentryEFCoreListener.cs b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentryEFCoreListener.cs index 626c5a6f7c..2ce93bb10f 100644 --- a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentryEFCoreListener.cs +++ b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentryEFCoreListener.cs @@ -88,7 +88,7 @@ public void OnNext(KeyValuePair value) } catch (Exception ex) { - _options.LogError("Failed to intercept EF Core event.", ex); + _options.LogError(ex, "Failed to intercept EF Core event."); } } } diff --git a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentrySqlListener.cs b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentrySqlListener.cs index 6ad3a6dce2..3bd90b9a46 100644 --- a/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentrySqlListener.cs +++ b/src/Sentry.DiagnosticSource/Internal/DiagnosticSource/SentrySqlListener.cs @@ -124,7 +124,7 @@ private void AddSpan(string operation, object? value) } } - private static ISpan? TryGetConnectionSpan(ITransaction transaction, Guid? connectionId) => + private static ISpan? TryGetConnectionSpan(ITransactionTracer transaction, Guid? connectionId) => connectionId == null ? null : transaction.Spans @@ -132,7 +132,7 @@ private void AddSpan(string operation, object? value) span is {IsFinished: false, Operation: "db.connection"} && TryGetConnectionId(span) == connectionId); - private static ISpan? TryGetQuerySpan(ITransaction transaction, Guid? operationId) => + private static ISpan? TryGetQuerySpan(ITransactionTracer transaction, Guid? operationId) => operationId == null ? null : transaction.Spans.FirstOrDefault(span => TryGetOperationId(span) == operationId); @@ -244,7 +244,7 @@ when GetSpan(SentrySqlSpanType.Connection, kvp.Value) is { } closeSpan: } catch (Exception ex) { - _options.LogError("Failed to intercept SQL event.", ex); + _options.LogError(ex, "Failed to intercept SQL event."); } } diff --git a/src/Sentry.DiagnosticSource/Sentry.DiagnosticSource.csproj b/src/Sentry.DiagnosticSource/Sentry.DiagnosticSource.csproj index 75ccb002d1..2bb043f837 100644 --- a/src/Sentry.DiagnosticSource/Sentry.DiagnosticSource.csproj +++ b/src/Sentry.DiagnosticSource/Sentry.DiagnosticSource.csproj @@ -1,7 +1,7 @@  - netstandard2.1;netstandard2.0;net461 + netstandard2.1;netstandard2.0;net462 $(PackageTags);Logging;Microsoft.Extensions.Logging Official Diagnostic.Listener integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. Note: This package is not needed when using Sentry with .NET Core 3 or higher. diff --git a/src/Sentry.EntityFramework/ErrorProcessors/DbConcurrencyExceptionProcessor.cs b/src/Sentry.EntityFramework/ErrorProcessors/DbConcurrencyExceptionProcessor.cs index 0269d2e989..4495350bda 100644 --- a/src/Sentry.EntityFramework/ErrorProcessors/DbConcurrencyExceptionProcessor.cs +++ b/src/Sentry.EntityFramework/ErrorProcessors/DbConcurrencyExceptionProcessor.cs @@ -11,6 +11,9 @@ public class DbConcurrencyExceptionProcessor : SentryEventExceptionProcessor - net461;netstandard2.1 + net462;netstandard2.1 Official Entity Framework 6 integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. $(PackageTags);EntityFramework;EF;EF6 @@ -21,7 +21,7 @@ - + diff --git a/src/Sentry.EntityFramework/SentryDatabaseLogging.cs b/src/Sentry.EntityFramework/SentryDatabaseLogging.cs index 4861c0b864..c61ff996d2 100644 --- a/src/Sentry.EntityFramework/SentryDatabaseLogging.cs +++ b/src/Sentry.EntityFramework/SentryDatabaseLogging.cs @@ -3,19 +3,10 @@ namespace Sentry.EntityFramework; /// /// Sentry Database Logger /// -public static class SentryDatabaseLogging +internal static class SentryDatabaseLogging { private static int Init; - /// - /// Adds an instance of to - /// This is a static setup call, so make sure you only call it once for each instance you want to register globally - /// - /// Query Logger. - [Obsolete("This method is called automatically by options.AddEntityFramework. This method will be removed in future versions.")] - public static SentryCommandInterceptor? UseBreadcrumbs(IQueryLogger? logger = null) - => UseBreadcrumbs(logger, true); - internal static SentryCommandInterceptor? UseBreadcrumbs( IQueryLogger? queryLogger = null, bool initOnce = true, diff --git a/src/Sentry.EntityFramework/SentryOptionsExtensions.cs b/src/Sentry.EntityFramework/SentryOptionsExtensions.cs index 2a60009ecd..eaad142dcc 100644 --- a/src/Sentry.EntityFramework/SentryOptionsExtensions.cs +++ b/src/Sentry.EntityFramework/SentryOptionsExtensions.cs @@ -28,7 +28,7 @@ public static SentryOptions AddEntityFramework(this SentryOptions sentryOptions) catch (Exception e) { sentryOptions.DiagnosticLogger? - .LogError("Failed to configure EF breadcrumbs. Make sure to init Sentry before EF.", e); + .LogError(e, "Failed to configure EF breadcrumbs. Make sure to init Sentry before EF."); } dbIntegration = new DbInterceptionIntegration(); diff --git a/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs b/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs new file mode 100644 index 0000000000..c38d922644 --- /dev/null +++ b/src/Sentry.Extensions.Logging/BindableSentryLoggingOptions.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Logging; + +namespace Sentry.Extensions.Logging; + +/// +internal class BindableSentryLoggingOptions : BindableSentryOptions +{ + public LogLevel? MinimumBreadcrumbLevel { get; set; } + public LogLevel? MinimumEventLevel { get; set; } + public bool? InitializeSdk { get; set; } + + public void ApplyTo(SentryLoggingOptions options) + { + base.ApplyTo(options); + options.MinimumBreadcrumbLevel = MinimumBreadcrumbLevel ?? options.MinimumBreadcrumbLevel; + options.MinimumEventLevel = MinimumEventLevel ?? options.MinimumEventLevel; + options.InitializeSdk = InitializeSdk?? options.InitializeSdk; + } +} diff --git a/src/Sentry.Extensions.Logging/Sentry.Extensions.Logging.csproj b/src/Sentry.Extensions.Logging/Sentry.Extensions.Logging.csproj index ed10785340..e416c0ab12 100644 --- a/src/Sentry.Extensions.Logging/Sentry.Extensions.Logging.csproj +++ b/src/Sentry.Extensions.Logging/Sentry.Extensions.Logging.csproj @@ -1,11 +1,16 @@  - net6.0;net5.0;netcoreapp3.0;netstandard2.0 + net8.0;net6.0;netstandard2.0 $(PackageTags);Logging;Microsoft.Extensions.Logging Official Microsoft.Extensions.Logging integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. + + true + true + + @@ -15,21 +20,17 @@ - - - - - - - - - - + + + + + + diff --git a/src/Sentry.Extensions.Logging/SentryLogger.cs b/src/Sentry.Extensions.Logging/SentryLogger.cs index 284a5c371b..6e91e40fc0 100644 --- a/src/Sentry.Extensions.Logging/SentryLogger.cs +++ b/src/Sentry.Extensions.Logging/SentryLogger.cs @@ -23,7 +23,12 @@ internal SentryLogger( _hub = hub; } +#if NET8_0_OR_GREATER + public IDisposable BeginScope(TState state) where TState : notnull + => _hub.PushScope(state); +#else public IDisposable BeginScope(TState state) => _hub.PushScope(state); +#endif public bool IsEnabled(LogLevel logLevel) => _hub.IsEnabled diff --git a/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs b/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs index a53656f5c0..b220d936b5 100644 --- a/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs +++ b/src/Sentry.Extensions.Logging/SentryLoggingOptionsSetup.cs @@ -1,3 +1,30 @@ +#if NET6_0_OR_GREATER +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging.Configuration; +using Microsoft.Extensions.Options; + +namespace Sentry.Extensions.Logging; + +internal class SentryLoggingOptionsSetup : IConfigureOptions +{ + private readonly IConfiguration _config; + + public SentryLoggingOptionsSetup(ILoggerProviderConfiguration config) + { + ArgumentNullException.ThrowIfNull(config); + _config = config.Configuration; + } + + public void Configure(SentryLoggingOptions options) + { + ArgumentNullException.ThrowIfNull(options); + + var bindable = new BindableSentryLoggingOptions(); + _config.Bind(bindable); + bindable.ApplyTo(options); + } +} +#else using Microsoft.Extensions.Logging.Configuration; using Microsoft.Extensions.Options; @@ -10,3 +37,4 @@ public SentryLoggingOptionsSetup( : base(providerConfiguration.Configuration) { } } +#endif diff --git a/src/Sentry.Google.Cloud.Functions/Sentry.Google.Cloud.Functions.csproj b/src/Sentry.Google.Cloud.Functions/Sentry.Google.Cloud.Functions.csproj index 0c58b954d4..043a4a8d2c 100644 --- a/src/Sentry.Google.Cloud.Functions/Sentry.Google.Cloud.Functions.csproj +++ b/src/Sentry.Google.Cloud.Functions/Sentry.Google.Cloud.Functions.csproj @@ -1,14 +1,14 @@ - net6.0;net5.0;netcoreapp3.1 + net6.0 $(PackageTags);GCP;Google Cloud Functions Official Google Cloud Functions integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. - + diff --git a/src/Sentry.Log4Net/Sentry.Log4Net.csproj b/src/Sentry.Log4Net/Sentry.Log4Net.csproj index 0063ee57a0..aebe69096e 100644 --- a/src/Sentry.Log4Net/Sentry.Log4Net.csproj +++ b/src/Sentry.Log4Net/Sentry.Log4Net.csproj @@ -1,7 +1,7 @@  - netstandard2.1;netstandard2.0;net461 + netstandard2.0;net462 $(PackageTags);Logging;log4net Official log4net integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. true diff --git a/src/Sentry.Log4Net/SentryAppender.cs b/src/Sentry.Log4Net/SentryAppender.cs index a8e954dfe8..bdc1785ab3 100644 --- a/src/Sentry.Log4Net/SentryAppender.cs +++ b/src/Sentry.Log4Net/SentryAppender.cs @@ -93,7 +93,7 @@ protected override void Append(LoggingEvent loggingEvent) var level = loggingEvent.ToBreadcrumbLevel(); IDictionary data = GetLoggingEventProperties(loggingEvent) .Where(kvp => kvp.Value != null) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value!.ToString()); + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value!.ToString() ?? ""); _hub.AddBreadcrumb(message, category, type: null, data, level ?? default); return; diff --git a/src/Sentry.Maui/Internal/MauiDeviceData.cs b/src/Sentry.Maui/Internal/MauiDeviceData.cs index 377feccff3..71a7fdd78a 100644 --- a/src/Sentry.Maui/Internal/MauiDeviceData.cs +++ b/src/Sentry.Maui/Internal/MauiDeviceData.cs @@ -112,7 +112,7 @@ public static void ApplyMauiDeviceData(this Device device, IDiagnosticLogger? lo catch (Exception ex) { // Log, but swallow the exception so we can continue sending events - logger?.LogError("Error getting MAUI device information.", ex); + logger?.LogError(ex, "Error getting MAUI device information."); } } } diff --git a/src/Sentry.Maui/Internal/MauiEventsBinder.cs b/src/Sentry.Maui/Internal/MauiEventsBinder.cs index a51398b8dc..9e3a095b18 100644 --- a/src/Sentry.Maui/Internal/MauiEventsBinder.cs +++ b/src/Sentry.Maui/Internal/MauiEventsBinder.cs @@ -143,7 +143,7 @@ public void BindReflectedEvents(BindableObject bindableObject, bool includeExpli catch (Exception ex) { // Don't throw if we can't bind the event handler - _options.DiagnosticLogger?.LogError("Couldn't bind to {0}.{1}", ex, type.Name, eventInfo.Name); + _options.DiagnosticLogger?.LogError(ex, "Couldn't bind to {0}.{1}", type.Name, eventInfo.Name); } } } diff --git a/src/Sentry.Maui/Internal/MauiOsData.cs b/src/Sentry.Maui/Internal/MauiOsData.cs index e49759ee5f..642444b799 100644 --- a/src/Sentry.Maui/Internal/MauiOsData.cs +++ b/src/Sentry.Maui/Internal/MauiOsData.cs @@ -40,7 +40,7 @@ public static void ApplyMauiOsData(this OperatingSystem os, IDiagnosticLogger? l catch (Exception ex) { // Log, but swallow the exception so we can continue sending events - logger?.LogError("Error getting MAUI OS information.", ex); + logger?.LogError(ex, "Error getting MAUI OS information."); } } } diff --git a/src/Sentry.Maui/Sentry.Maui.csproj b/src/Sentry.Maui/Sentry.Maui.csproj index 86b8e2371d..6eba15bacd 100644 --- a/src/Sentry.Maui/Sentry.Maui.csproj +++ b/src/Sentry.Maui/Sentry.Maui.csproj @@ -6,14 +6,11 @@ Target net6.0 so we can run unit tests on platform-neutral code. Target other platforms so we can include platform-specific code, and bundle native SDKs. --> - net6.0 - $(TargetFrameworks);net6.0-android - $(TargetFrameworks);net6.0-ios - $(TargetFrameworks);net6.0-maccatalyst - $(TargetFrameworks);net6.0-windows10.0.19041.0 - - - $(TargetFrameworks);net6.0-tizen + net7.0 + $(TargetFrameworks);net7.0-android + $(TargetFrameworks);net7.0-ios + $(TargetFrameworks);net7.0-maccatalyst + $(TargetFrameworks);net7.0-windows10.0.19041.0 - net6.0 + net8.0;net6.0 $(PackageTags);Profiling;Diagnostic - - false Performance profiling support for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. + + true + + - - + + + + @@ -20,4 +24,17 @@ + + + + + + + + + + true + lib\$(TargetFramework) + + diff --git a/src/Sentry.Serilog/Sentry.Serilog.csproj b/src/Sentry.Serilog/Sentry.Serilog.csproj index d6ce1133a6..4e2b63e861 100644 --- a/src/Sentry.Serilog/Sentry.Serilog.csproj +++ b/src/Sentry.Serilog/Sentry.Serilog.csproj @@ -1,12 +1,16 @@  - net6.0;net5.0;netstandard2.1;netstandard2.0;net461 + net8.0;net6.0;netstandard2.1;netstandard2.0;net462 $(PackageTags);Logging;Serilog Official Serilog integration for Sentry - Open-source error tracking that helps developers monitor and fix crashes in real time. true + + true + + @@ -23,11 +27,11 @@ - + - + diff --git a/src/Sentry.Serilog/SentrySinkExtensions.cs b/src/Sentry.Serilog/SentrySinkExtensions.cs index ac400cba01..a3d17fdfd4 100644 --- a/src/Sentry.Serilog/SentrySinkExtensions.cs +++ b/src/Sentry.Serilog/SentrySinkExtensions.cs @@ -1,4 +1,5 @@ // ReSharper disable once CheckNamespace - Discoverability + namespace Serilog; /// @@ -31,7 +32,7 @@ public static class SentrySinkExtensions /// Whether the body compression is buffered and the request 'Content-Length' known in advance. /// Whether to log diagnostics messages. /// The diagnostics level to be used. - /// Whether or not to include referenced assemblies in each event sent to sentry. Defaults to . + /// What mode to use for reporting referenced assemblies in each event sent to sentry. Defaults to /// What modes to use for event automatic de-duplication. /// Whether to initialize this SDK through this integration. /// Defaults tags to add to all events. @@ -66,7 +67,7 @@ public static class SentrySinkExtensions /// "requestBodyCompressionBuffered": false, /// "debug": false, /// "diagnosticLevel": "Debug", - /// "reportAssemblies": false, + /// "reportAssembliesMode": ReportAssembliesMode.None, /// "deduplicateMode": "All", /// "initializeSdk": true, /// "defaultTags": { @@ -102,7 +103,7 @@ public static LoggerConfiguration Sentry( bool? requestBodyCompressionBuffered = null, bool? debug = null, SentryLevel? diagnosticLevel = null, - bool? reportAssemblies = null, + ReportAssembliesMode? reportAssembliesMode = null, DeduplicateMode? deduplicateMode = null, bool? initializeSdk = null, Dictionary? defaultTags = null) @@ -128,7 +129,7 @@ public static LoggerConfiguration Sentry( requestBodyCompressionBuffered, debug, diagnosticLevel, - reportAssemblies, + reportAssembliesMode, deduplicateMode, initializeSdk, defaultTags)); @@ -158,7 +159,7 @@ public static LoggerConfiguration Sentry( /// Whether the body compression is buffered and the request 'Content-Length' known in advance. /// Whether to log diagnostics messages. /// The diagnostics level to be used. - /// Whether or not to include referenced assemblies in each event sent to sentry. Defaults to . + /// What mode to use for reporting referenced assemblies in each event sent to sentry. Defaults to /// What modes to use for event automatic de-duplication. /// Whether to initialize this SDK through this integration. /// Defaults tags to add to all events. @@ -184,12 +185,12 @@ public static void ConfigureSentrySerilogOptions( bool? requestBodyCompressionBuffered = null, bool? debug = null, SentryLevel? diagnosticLevel = null, - bool? reportAssemblies = null, + ReportAssembliesMode? reportAssembliesMode = null, DeduplicateMode? deduplicateMode = null, bool? initializeSdk = null, Dictionary? defaultTags = null) { - if (!string.IsNullOrWhiteSpace(dsn)) + if (dsn is not null) { sentrySerilogOptions.Dsn = dsn; } @@ -289,11 +290,9 @@ public static void ConfigureSentrySerilogOptions( sentrySerilogOptions.DiagnosticLevel = diagnosticLevel.Value; } - if (reportAssemblies.HasValue) + if (reportAssembliesMode.HasValue) { -#pragma warning disable CS0618 // Type or member is obsolete - sentrySerilogOptions.ReportAssemblies = reportAssemblies.Value; -#pragma warning restore CS0618 // Type or member is obsolete + sentrySerilogOptions.ReportAssembliesMode = reportAssembliesMode.Value; } if (deduplicateMode.HasValue) diff --git a/src/Sentry/AttributeReader.cs b/src/Sentry/AttributeReader.cs index 1fa69e220b..2ad9fc9e0a 100644 --- a/src/Sentry/AttributeReader.cs +++ b/src/Sentry/AttributeReader.cs @@ -2,11 +2,6 @@ internal static class AttributeReader { - public static bool TryGetProjectDirectory(Assembly assembly, out string? projectDirectory) - { - projectDirectory = assembly.GetCustomAttributes() - .FirstOrDefault(x => x.Key == "Sentry.ProjectDirectory") - ?.Value; - return projectDirectory != null; - } + public static string? TryGetProjectDirectory(Assembly assembly) => + assembly.GetCustomAttributes().FirstOrDefault(x => x.Key == "Sentry.ProjectDirectory")?.Value; } diff --git a/src/Sentry/BindableSentryOptions.cs b/src/Sentry/BindableSentryOptions.cs new file mode 100644 index 0000000000..7b5cdf701c --- /dev/null +++ b/src/Sentry/BindableSentryOptions.cs @@ -0,0 +1,99 @@ +namespace Sentry; + +/// +/// Contains representations of the subset of properties in SentryOptions that can be set from ConfigurationBindings. +/// Note that all of these properties are nullable, so that if they are not present in configuration, the values from +/// the type being bound to will be preserved. +/// +internal partial class BindableSentryOptions +{ + public bool? IsGlobalModeEnabled { get; set; } + public bool? EnableScopeSync { get; set; } + public List? TagFilters { get; set; } + public bool? SendDefaultPii { get; set; } + public bool? IsEnvironmentUser { get; set; } + public string? ServerName { get; set; } + public bool? AttachStacktrace { get; set; } + public int? MaxBreadcrumbs { get; set; } + public float? SampleRate { get; set; } + public string? Release { get; set; } + public string? Distribution { get; set; } + public string? Environment { get; set; } + public string? Dsn { get; set; } + public int? MaxQueueItems { get; set; } + public int? MaxCacheItems { get; set; } + public TimeSpan? ShutdownTimeout { get; set; } + public TimeSpan? FlushTimeout { get; set; } + public DecompressionMethods? DecompressionMethods { get; set; } + public CompressionLevel? RequestBodyCompressionLevel { get; set; } + public bool? RequestBodyCompressionBuffered { get; set; } + public bool? SendClientReports { get; set; } + public bool? Debug { get; set; } + public SentryLevel? DiagnosticLevel { get; set; } + public ReportAssembliesMode? ReportAssembliesMode { get; set; } + public DeduplicateMode? DeduplicateMode { get; set; } + public string? CacheDirectoryPath { get; set; } + public bool? CaptureFailedRequests { get; set; } + public List? FailedRequestTargets { get; set; } + public TimeSpan? InitCacheFlushTimeout { get; set; } + public Dictionary? DefaultTags { get; set; } + public bool? EnableTracing { get; set; } + public double? TracesSampleRate { get; set; } + public List? TracePropagationTargets { get; set; } + public StackTraceMode? StackTraceMode { get; set; } + public long? MaxAttachmentSize { get; set; } + public StartupTimeDetectionMode? DetectStartupTime { get; set; } + public TimeSpan? AutoSessionTrackingInterval { get; set; } + public bool? AutoSessionTracking { get; set; } + public bool? UseAsyncFileIO { get; set; } + public bool? JsonPreserveReferences { get; set; } + + public void ApplyTo(SentryOptions options) + { + options.IsGlobalModeEnabled = IsGlobalModeEnabled ?? options.IsGlobalModeEnabled; + options.EnableScopeSync = EnableScopeSync ?? options.EnableScopeSync; + options.TagFilters = TagFilters?.Select(s => new SubstringOrRegexPattern(s)).ToList() ?? options.TagFilters; + options.SendDefaultPii = SendDefaultPii ?? options.SendDefaultPii; + options.IsEnvironmentUser = IsEnvironmentUser ?? options.IsEnvironmentUser; + options.ServerName = ServerName ?? options.ServerName; + options.AttachStacktrace = AttachStacktrace ?? options.AttachStacktrace; + options.MaxBreadcrumbs = MaxBreadcrumbs ?? options.MaxBreadcrumbs; + options.SampleRate = SampleRate ?? options.SampleRate; + options.Release = Release ?? options.Release; + options.Distribution = Distribution ?? options.Distribution; + options.Environment = Environment ?? options.Environment; + options.Dsn = Dsn ?? options.Dsn; + options.MaxQueueItems = MaxQueueItems ?? options.MaxQueueItems; + options.MaxCacheItems = MaxCacheItems ?? options.MaxCacheItems; + options.ShutdownTimeout = ShutdownTimeout ?? options.ShutdownTimeout; + options.FlushTimeout = FlushTimeout ?? options.FlushTimeout; + options.DecompressionMethods = DecompressionMethods ?? options.DecompressionMethods; + options.RequestBodyCompressionLevel = RequestBodyCompressionLevel ?? options.RequestBodyCompressionLevel; + options.RequestBodyCompressionBuffered = RequestBodyCompressionBuffered ?? options.RequestBodyCompressionBuffered; + options.SendClientReports = SendClientReports ?? options.SendClientReports; + options.Debug = Debug ?? options.Debug; + options.DiagnosticLevel = DiagnosticLevel ?? options.DiagnosticLevel; + options.ReportAssembliesMode = ReportAssembliesMode ?? options.ReportAssembliesMode; + options.DeduplicateMode = DeduplicateMode ?? options.DeduplicateMode; + options.CacheDirectoryPath = CacheDirectoryPath ?? options.CacheDirectoryPath; + options.CaptureFailedRequests = CaptureFailedRequests ?? options.CaptureFailedRequests; + options.FailedRequestTargets = FailedRequestTargets?.Select(s => new SubstringOrRegexPattern(s)).ToList() ?? options.FailedRequestTargets; + options.InitCacheFlushTimeout = InitCacheFlushTimeout ?? options.InitCacheFlushTimeout; + options.DefaultTags = DefaultTags ?? options.DefaultTags; + options.EnableTracing = EnableTracing ?? options.EnableTracing; + options.TracesSampleRate = TracesSampleRate ?? options.TracesSampleRate; + options.TracePropagationTargets = TracePropagationTargets?.Select(s => new SubstringOrRegexPattern(s)).ToList() ?? options.TracePropagationTargets; + options.StackTraceMode = StackTraceMode ?? options.StackTraceMode; + options.MaxAttachmentSize = MaxAttachmentSize ?? options.MaxAttachmentSize; + options.DetectStartupTime = DetectStartupTime ?? options.DetectStartupTime; + options.AutoSessionTrackingInterval = AutoSessionTrackingInterval ?? options.AutoSessionTrackingInterval; + options.AutoSessionTracking = AutoSessionTracking ?? options.AutoSessionTracking; + options.UseAsyncFileIO = UseAsyncFileIO ?? options.UseAsyncFileIO; + options.JsonPreserveReferences = JsonPreserveReferences ?? options.JsonPreserveReferences; +#if ANDROID + Android.ApplyTo(options.Android); +#elif __IOS__ + iOS.ApplyTo(options.iOS); +#endif + } +} diff --git a/src/Sentry/Contexts.cs b/src/Sentry/Contexts.cs index b4ab6d0335..46f69496e7 100644 --- a/src/Sentry/Contexts.cs +++ b/src/Sentry/Contexts.cs @@ -11,22 +11,24 @@ namespace Sentry; /// Represents Sentry's structured Context. /// /// -public sealed class Contexts : ConcurrentDictionary, IJsonSerializable +public sealed class Contexts : IDictionary, IJsonSerializable { + private readonly ConcurrentDictionary _innerDictionary = new(StringComparer.Ordinal); + /// /// Describes the application. /// - public App App => this.GetOrCreate(App.Type); + public App App => _innerDictionary.GetOrCreate(App.Type); /// /// Describes the browser. /// - public Browser Browser => this.GetOrCreate(Browser.Type); + public Browser Browser => _innerDictionary.GetOrCreate(Browser.Type); /// /// Describes the device. /// - public Device Device => this.GetOrCreate(Device.Type); + public Device Device => _innerDictionary.GetOrCreate(Device.Type); /// /// Defines the operating system. @@ -34,32 +36,32 @@ public sealed class Contexts : ConcurrentDictionary, IJsonSerial /// /// In web contexts, this is the operating system of the browser (normally pulled from the User-Agent string). /// - public OperatingSystem OperatingSystem => this.GetOrCreate(OperatingSystem.Type); + public OperatingSystem OperatingSystem => _innerDictionary.GetOrCreate(OperatingSystem.Type); /// /// Response interface that contains information on any HTTP response related to the event. /// - public Response Response => this.GetOrCreate(Response.Type); + public Response Response => _innerDictionary.GetOrCreate(Response.Type); /// /// This describes a runtime in more detail. /// - public Runtime Runtime => this.GetOrCreate(Runtime.Type); + public Runtime Runtime => _innerDictionary.GetOrCreate(Runtime.Type); /// /// This describes a GPU of the device. /// - public Gpu Gpu => this.GetOrCreate(Gpu.Type); + public Gpu Gpu => _innerDictionary.GetOrCreate(Gpu.Type); /// /// This describes trace information. /// - public Trace Trace => this.GetOrCreate(Trace.Type); + public Trace Trace => _innerDictionary.GetOrCreate(Trace.Type); /// /// Initializes an instance of . /// - public Contexts() : base(StringComparer.Ordinal) { } + public Contexts() { } /// /// Creates a deep clone of this context. @@ -80,7 +82,7 @@ internal void CopyTo(Contexts to) { foreach (var kv in this) { - to.AddOrUpdate(kv.Key, + to._innerDictionary.AddOrUpdate(kv.Key, addValueFactory: _ => kv.Value is ICloneable cloneable @@ -194,5 +196,69 @@ internal void ReplaceWith(Contexts? contexts) } } - internal Contexts? NullIfEmpty() => IsEmpty ? null : this; + internal Contexts? NullIfEmpty() => _innerDictionary.IsEmpty ? null : this; + + /// + public IEnumerator> GetEnumerator() => _innerDictionary.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_innerDictionary).GetEnumerator(); + + /// + public void Add(KeyValuePair item) + => ((ICollection>)_innerDictionary).Add(item); + + /// + public void Clear() => _innerDictionary.Clear(); + + /// + public bool Contains(KeyValuePair item) => _innerDictionary.Contains(item); + + /// + public void CopyTo(KeyValuePair[] array, int arrayIndex) + => ((ICollection>)_innerDictionary).CopyTo(array, arrayIndex); + + /// + public bool Remove(KeyValuePair item) + => ((ICollection>)_innerDictionary).Remove(item); + + /// + public int Count => _innerDictionary.Count; + + /// + public bool IsReadOnly => ((ICollection>)_innerDictionary).IsReadOnly; + + /// + public void Add(string key, object value) => _innerDictionary.Add(key, value); + + /// + public bool ContainsKey(string key) => _innerDictionary.ContainsKey(key); + + /// + public bool Remove(string key) => ((IDictionary)_innerDictionary).Remove(key); + + /// + public bool TryGetValue(string key, out object value) + { + if (_innerDictionary.TryGetValue(key, out var innerValue)) + { + value = innerValue; + return true; + } + + value = default!; + return false; + } + + /// + public object this[string key] + { + get => _innerDictionary[key]; + set => _innerDictionary[key] = value; + } + + /// + public ICollection Keys => _innerDictionary.Keys; + + /// + public ICollection Values => _innerDictionary.Values; } diff --git a/src/Sentry/CrashType.cs b/src/Sentry/CrashType.cs index 7e417081c1..0fb43468e1 100644 --- a/src/Sentry/CrashType.cs +++ b/src/Sentry/CrashType.cs @@ -7,15 +7,15 @@ namespace Sentry; [Obsolete("WARNING: This method deliberately causes a crash, and should not be used in a real application.")] public enum CrashType { - /// - /// A managed will be thrown from .NET. - /// - Managed, + /// + /// A managed will be thrown from .NET. + /// + Managed, - /// - /// A managed will be thrown from .NET on a background thread. - /// - ManagedBackgroundThread, + /// + /// A managed will be thrown from .NET on a background thread. + /// + ManagedBackgroundThread, #if ANDROID /// @@ -31,7 +31,7 @@ public enum CrashType #if __MOBILE__ /// - /// A native operation that will crash the appliction will be performed by a C library. + /// A native operation that will crash the application will be performed by a C library. /// Native #endif diff --git a/src/Sentry/Extensibility/DiagnosticLoggerExtensions.cs b/src/Sentry/Extensibility/DiagnosticLoggerExtensions.cs index ae157c4b15..579364db9f 100644 --- a/src/Sentry/Extensibility/DiagnosticLoggerExtensions.cs +++ b/src/Sentry/Extensibility/DiagnosticLoggerExtensions.cs @@ -211,8 +211,15 @@ internal static void LogWarning( /// public static void LogError( this IDiagnosticLogger logger, - string message, - Exception? exception = null) + string message) + => logger.LogIfEnabled(SentryLevel.Error, null, message); + + /// + /// Log an exception with an error message. + /// + public static void LogError(this IDiagnosticLogger logger, + Exception exception, + string message) => logger.LogIfEnabled(SentryLevel.Error, exception, message); /// @@ -220,37 +227,41 @@ public static void LogError( /// internal static void LogError( this SentryOptions options, - string message, - Exception? exception = null) + string message) + => options.DiagnosticLogger?.LogIfEnabled(SentryLevel.Error, null, message); + + /// + /// Log a error message. + /// + internal static void LogError(this SentryOptions options, + Exception exception, + string message) => options.DiagnosticLogger?.LogIfEnabled(SentryLevel.Error, exception, message); /// /// Log a error message. /// - public static void LogError( - this IDiagnosticLogger logger, - string message, + public static void LogError(this IDiagnosticLogger logger, Exception exception, + string message, TArg arg) => logger.LogIfEnabled(SentryLevel.Error, exception, message, arg); /// /// Log a error message. /// - internal static void LogError( - this SentryOptions options, - string message, + internal static void LogError(this SentryOptions options, Exception exception, + string message, TArg arg) => options.DiagnosticLogger?.LogIfEnabled(SentryLevel.Error, exception, message, arg); /// /// Log a error message. /// - public static void LogError( - this IDiagnosticLogger logger, - string message, + public static void LogError(this IDiagnosticLogger logger, Exception exception, + string message, TArg arg, TArg2 arg2) => logger.LogIfEnabled(SentryLevel.Error, exception, message, arg, arg2); @@ -258,10 +269,9 @@ public static void LogError( /// /// Log a error message. /// - internal static void LogError( - this SentryOptions options, - string message, + internal static void LogError(this SentryOptions options, Exception exception, + string message, TArg arg, TArg2 arg2) => options.DiagnosticLogger?.LogIfEnabled(SentryLevel.Error, exception, message, arg, arg2); @@ -269,10 +279,9 @@ internal static void LogError( /// /// Log a error message. /// - public static void LogError( - this IDiagnosticLogger logger, - string message, + public static void LogError(this IDiagnosticLogger logger, Exception exception, + string message, TArg arg, TArg2 arg2, TArg3 arg3, @@ -282,10 +291,9 @@ public static void LogError( /// /// Log a error message. /// - internal static void LogError( - this SentryOptions options, - string message, + internal static void LogError(this SentryOptions options, Exception exception, + string message, TArg arg, TArg2 arg2, TArg3 arg3, @@ -321,8 +329,15 @@ internal static void LogError( /// public static void LogFatal( this IDiagnosticLogger logger, - string message, - Exception? exception = null) + string message) + => logger.LogIfEnabled(SentryLevel.Fatal, null, message); + + /// + /// Log an exception with a warning message. + /// + public static void LogFatal(this IDiagnosticLogger logger, + Exception exception, + string message) => logger.LogIfEnabled(SentryLevel.Fatal, exception, message); /// @@ -330,8 +345,15 @@ public static void LogFatal( /// internal static void LogFatal( this SentryOptions options, - string message, - Exception? exception = null) + string message) + => options.DiagnosticLogger?.LogIfEnabled(SentryLevel.Fatal, null, message); + + /// + /// Log an exception with a warning message. + /// + internal static void LogFatal(this SentryOptions options, + Exception exception, + string message) => options.DiagnosticLogger?.LogIfEnabled(SentryLevel.Fatal, exception, message); internal static void LogIfEnabled( diff --git a/src/Sentry/Extensibility/DisabledHub.cs b/src/Sentry/Extensibility/DisabledHub.cs index 8a5ef6c8d2..c41ea7121e 100644 --- a/src/Sentry/Extensibility/DisabledHub.cs +++ b/src/Sentry/Extensibility/DisabledHub.cs @@ -41,17 +41,10 @@ public void ConfigureScope(Action configureScope) /// public IDisposable PushScope(TState state) => this; - /// - /// No-Op. - /// - public void WithScope(Action scopeCallback) - { - } - /// /// Returns a dummy transaction. /// - public ITransaction StartTransaction( + public ITransactionTracer StartTransaction( ITransactionContext context, IReadOnlyDictionary customSamplingContext) => // Transactions from DisabledHub are always sampled out @@ -89,7 +82,7 @@ public TransactionContext ContinueTrace( string? operation = null) { // Transactions from DisabledHub are always sampled out - return new TransactionContext( name ?? string.Empty, operation ?? string.Empty, false); + return new TransactionContext( name ?? string.Empty, operation ?? string.Empty, isSampled: false); } /// @@ -102,7 +95,7 @@ public TransactionContext ContinueTrace( string? operation = null) { // Transactions from DisabledHub are always sampled out - return new TransactionContext( name ?? string.Empty, operation ?? string.Empty, false); + return new TransactionContext( name ?? string.Empty, operation ?? string.Empty, isSampled: false); } /// @@ -143,17 +136,17 @@ public void BindClient(ISentryClient client) /// /// No-Op. /// - public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null) => SentryId.Empty; + public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null, Hint? hint = null) => SentryId.Empty; /// /// No-Op. /// - public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Scope? scope = null) => SentryId.Empty; + public SentryId CaptureEvent(SentryEvent evt, Action configureScope) => SentryId.Empty; /// /// No-Op. /// - public SentryId CaptureEvent(SentryEvent evt, Action configureScope) => SentryId.Empty; + public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Action configureScope) => SentryId.Empty; /// /// No-Op. @@ -165,7 +158,7 @@ public void CaptureTransaction(Transaction transaction) /// /// No-Op. /// - public void CaptureTransaction(Transaction transaction, Hint? hint) + public void CaptureTransaction(Transaction transaction, Scope? scope, Hint? hint) { } diff --git a/src/Sentry/Extensibility/HubAdapter.cs b/src/Sentry/Extensibility/HubAdapter.cs index 0869c7bdda..6f7cbaa4d1 100644 --- a/src/Sentry/Extensibility/HubAdapter.cs +++ b/src/Sentry/Extensibility/HubAdapter.cs @@ -12,7 +12,7 @@ namespace Sentry.Extensibility; /// /// [DebuggerStepThrough] -public sealed class HubAdapter : IHub, IHubEx +public sealed class HubAdapter : IHub { /// /// The single instance which forwards all calls to @@ -62,17 +62,8 @@ public IDisposable PushScope(TState state) /// /// Forwards the call to . /// - [Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage and CaptureException " + - "that provide a callback to a configurable scope.")] [DebuggerStepThrough] - public void WithScope(Action scopeCallback) - => SentrySdk.WithScope(scopeCallback); - - /// - /// Forwards the call to . - /// - [DebuggerStepThrough] - public ITransaction StartTransaction( + public ITransactionTracer StartTransaction( ITransactionContext context, IReadOnlyDictionary customSamplingContext) => SentrySdk.StartTransaction(context, customSamplingContext); @@ -81,7 +72,7 @@ public ITransaction StartTransaction( /// Forwards the call to . /// [DebuggerStepThrough] - internal ITransaction StartTransaction( + internal ITransactionTracer StartTransaction( ITransactionContext context, IReadOnlyDictionary customSamplingContext, DynamicSamplingContext? dynamicSamplingContext) @@ -204,12 +195,6 @@ public void AddBreadcrumb( data, level); - /// - /// Forwards the call to - /// - SentryId IHubEx.CaptureEventInternal(SentryEvent evt, Hint? hint, Scope? scope) - => SentrySdk.CaptureEventInternal(evt, hint, scope); - /// /// Forwards the call to . /// @@ -223,15 +208,15 @@ public SentryId CaptureEvent(SentryEvent evt) [DebuggerStepThrough] [EditorBrowsable(EditorBrowsableState.Never)] public SentryId CaptureEvent(SentryEvent evt, Scope? scope) - => SentrySdk.CaptureEvent(evt, scope); + => SentrySdk.CaptureEvent(evt, scope, null); /// /// Forwards the call to . /// [DebuggerStepThrough] [EditorBrowsable(EditorBrowsableState.Never)] - public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Scope? scope) - => SentrySdk.CaptureEvent(evt, hint, scope); + public SentryId CaptureEvent(SentryEvent evt, Scope? scope, Hint? hint = null) + => SentrySdk.CaptureEvent(evt, scope, hint); /// /// Forwards the call to . @@ -241,6 +226,12 @@ public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Scope? scope) public SentryId CaptureEvent(SentryEvent evt, Action configureScope) => SentrySdk.CaptureEvent(evt, configureScope); + /// + /// Forwards the call to . + /// + public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Action configureScope) + => SentrySdk.CaptureEvent(evt, hint, configureScope); + /// /// Forwards the call to . /// @@ -261,8 +252,8 @@ public void CaptureTransaction(Transaction transaction) /// [DebuggerStepThrough] [EditorBrowsable(EditorBrowsableState.Never)] - public void CaptureTransaction(Transaction transaction, Hint? hint) - => SentrySdk.CaptureTransaction(transaction, hint); + public void CaptureTransaction(Transaction transaction, Scope? scope, Hint? hint) + => SentrySdk.CaptureTransaction(transaction, scope, hint); /// /// Forwards the call to . @@ -287,28 +278,4 @@ public Task FlushAsync(TimeSpan timeout) [EditorBrowsable(EditorBrowsableState.Never)] public void CaptureUserFeedback(UserFeedback sentryUserFeedback) => SentrySdk.CaptureUserFeedback(sentryUserFeedback); - - /// - /// Forwards the call to - /// - [Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage and CaptureException " + - "that provide a callback to a configurable scope.")] - public T? WithScope(Func scopeCallback) - => SentrySdk.WithScope(scopeCallback); - - /// - /// Forwards the call to - /// - [Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage and CaptureException " + - "that provide a callback to a configurable scope.")] - public Task WithScopeAsync(Func scopeCallback) - => SentrySdk.WithScopeAsync(scopeCallback); - - /// - /// Forwards the call to - /// - [Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage and CaptureException " + - "that provide a callback to a configurable scope.")] - public Task WithScopeAsync(Func> scopeCallback) - => SentrySdk.WithScopeAsync(scopeCallback); } diff --git a/src/Sentry/GlobalSessionManager.cs b/src/Sentry/GlobalSessionManager.cs index 2a42f2b62d..3cbab88e42 100644 --- a/src/Sentry/GlobalSessionManager.cs +++ b/src/Sentry/GlobalSessionManager.cs @@ -85,7 +85,7 @@ public GlobalSessionManager( // and let the next installation id strategy kick in catch (Exception ex) { - _options.LogError("Failed to resolve persistent installation ID.", ex); + _options.LogError(ex, "Failed to resolve persistent installation ID."); return null; } } @@ -113,7 +113,7 @@ public GlobalSessionManager( } catch (Exception ex) { - _options.LogError("Failed to resolve hardware installation ID.", ex); + _options.LogError(ex, "Failed to resolve hardware installation ID."); return null; } } @@ -187,7 +187,7 @@ private void PersistSession(SessionUpdate update, DateTimeOffset? pauseTimestamp } catch (Exception ex) { - _options.LogError("Failed to persist session on the file system.", ex); + _options.LogError(ex, "Failed to persist session on the file system."); } } @@ -212,7 +212,7 @@ private void DeletePersistedSession() } catch (Exception ex) { - _options.LogError("Failed to read the contents of persisted session file '{0}'.", ex, filePath); + _options.LogError(ex, "Failed to read the contents of persisted session file '{0}'.", filePath); } } @@ -222,7 +222,7 @@ private void DeletePersistedSession() } catch (Exception ex) { - _options.LogError("Failed to delete persisted session from the file system: '{0}'", ex, filePath); + _options.LogError(ex, "Failed to delete persisted session from the file system: '{0}'", filePath); } } @@ -256,7 +256,7 @@ private void DeletePersistedSession() } catch (Exception e) { - _options.LogError("Invoking CrashedLastRun failed.", e); + _options.LogError(e, "Invoking CrashedLastRun failed."); } // Create a session update to end the recovered session @@ -285,7 +285,7 @@ private void DeletePersistedSession() } catch (Exception ex) { - _options.LogError("Failed to recover persisted session from the file system '{0}'.", ex, filePath); + _options.LogError(ex, "Failed to recover persisted session from the file system '{0}'.", filePath); return null; } diff --git a/src/Sentry/GraphQLRequestContent.cs b/src/Sentry/GraphQLRequestContent.cs index 865e8d11b1..e4d574ef05 100644 --- a/src/Sentry/GraphQLRequestContent.cs +++ b/src/Sentry/GraphQLRequestContent.cs @@ -1,5 +1,6 @@ using Sentry.Extensibility; using Sentry.Internal.Extensions; +using Sentry.Internal.GraphQL; namespace Sentry; @@ -25,8 +26,7 @@ public GraphQLRequestContent(string? requestContent, SentryOptions? options = nu try { - var deserialized = JsonSerializer.Deserialize>(requestContent, SerializerOptions); - Items = (deserialized ?? new Dictionary()).AsReadOnly(); + Items = GraphQLRequestContentReader.Read(requestContent); } catch (Exception e) { diff --git a/src/Sentry/HubExtensions.cs b/src/Sentry/HubExtensions.cs index 7364544d93..5c43d64792 100644 --- a/src/Sentry/HubExtensions.cs +++ b/src/Sentry/HubExtensions.cs @@ -14,13 +14,13 @@ public static class HubExtensions /// /// Starts a transaction. /// - public static ITransaction StartTransaction(this IHub hub, ITransactionContext context) => + public static ITransactionTracer StartTransaction(this IHub hub, ITransactionContext context) => hub.StartTransaction(context, new Dictionary()); /// /// Starts a transaction. /// - public static ITransaction StartTransaction( + public static ITransactionTracer StartTransaction( this IHub hub, string name, string operation) => @@ -29,7 +29,7 @@ public static ITransaction StartTransaction( /// /// Starts a transaction. /// - public static ITransaction StartTransaction( + public static ITransactionTracer StartTransaction( this IHub hub, string name, string operation, @@ -44,7 +44,7 @@ public static ITransaction StartTransaction( /// /// Starts a transaction from the specified trace header. /// - public static ITransaction StartTransaction( + public static ITransactionTracer StartTransaction( this IHub hub, string name, string operation, @@ -184,10 +184,7 @@ public LockedScope(IHub hub) } internal static SentryId CaptureExceptionInternal(this IHub hub, Exception ex) => - hub.CaptureEventInternal(new SentryEvent(ex)); - - internal static SentryId CaptureEventInternal(this IHub hub, SentryEvent evt) => - hub is IHubEx hubEx ? hubEx.CaptureEventInternal(evt, null, null) : hub.CaptureEvent(evt); + hub.CaptureEvent(new SentryEvent(ex)); /// /// Captures the exception with a configurable scope callback. @@ -224,7 +221,7 @@ public static SentryId CaptureMessage(this IHub hub, string message, Action customSamplingContext, @@ -235,14 +232,14 @@ internal static ITransaction StartTransaction( _ => hub.StartTransaction(context, customSamplingContext) }; - internal static ITransaction? GetTransaction(this IHub hub) + internal static ITransactionTracer? GetTransaction(this IHub hub) { - ITransaction? transaction = null; + ITransactionTracer? transaction = null; hub.ConfigureScope(scope => transaction = scope.Transaction); return transaction; } - internal static ITransaction? GetTransactionIfSampled(this IHub hub) + internal static ITransactionTracer? GetTransactionIfSampled(this IHub hub) { var transaction = hub.GetTransaction(); return transaction?.IsSampled == true ? transaction : null; diff --git a/src/Sentry/IEventLike.cs b/src/Sentry/IEventLike.cs index 9992a99fc6..36edead55e 100644 --- a/src/Sentry/IEventLike.cs +++ b/src/Sentry/IEventLike.cs @@ -3,8 +3,24 @@ namespace Sentry; /// /// Models members common between types that represent event-like data. /// -public interface IEventLike : IHasBreadcrumbs, IHasTags, IHasExtra +public interface IEventLike : IHasTags, IHasExtra { + /// + /// A trail of events which happened prior to an issue. + /// + /// + IReadOnlyCollection Breadcrumbs { get; } + + /// + /// Adds a breadcrumb. + /// + void AddBreadcrumb(Breadcrumb breadcrumb); + + /// + /// The release distribution of the application. + /// + public string? Distribution { get; set; } + /// /// Sentry level. /// @@ -34,16 +50,6 @@ public interface IEventLike : IHasBreadcrumbs, IHasTags, IHasExtra /// User User { get; set; } - /// - /// The name of the platform. - /// - /// - /// In most cases, the platform will be "csharp". However, it may differ if the event - /// was generated from another embeded SDK. For example, when targeting net6.0-android, - /// events generated by the Sentry Android SDK will have the platform "java". - /// - public string? Platform { get; set; } - /// /// The release version of the application. /// @@ -91,6 +97,102 @@ public interface IEventLike : IHasBreadcrumbs, IHasTags, IHasExtra [EditorBrowsable(EditorBrowsableState.Never)] public static class EventLikeExtensions { +#if !NETFRAMEWORK + /// + /// Adds a breadcrumb to the object. + /// + /// The object. + /// The message. + /// The category. + /// The type. + /// The data key-value pair. + /// The level. + public static void AddBreadcrumb( + this IEventLike eventLike, + string message, + string? category, + string? type, + (string, string)? dataPair = null, + BreadcrumbLevel level = default) + { + Dictionary? data = null; + + if (dataPair != null) + { + data = new Dictionary + { + {dataPair.Value.Item1, dataPair.Value.Item2} + }; + } + + eventLike.AddBreadcrumb( + null, + message, + category, + type, + data, + level); + } +#endif + + /// + /// Adds a breadcrumb to the object. + /// + /// The object. + /// The message. + /// The category. + /// The type. + /// The data. + /// The level. + public static void AddBreadcrumb( + this IEventLike eventLike, + string message, + string? category = null, + string? type = null, + IReadOnlyDictionary? data = null, + BreadcrumbLevel level = default) + { + eventLike.AddBreadcrumb( + null, + message, + category, + type, + data, + level); + } + + /// + /// Adds a breadcrumb to the object. + /// + /// + /// This overload is used for testing. + /// + /// The object. + /// The timestamp + /// The message. + /// The category. + /// The type. + /// The data + /// The level. + [EditorBrowsable(EditorBrowsableState.Never)] + public static void AddBreadcrumb( + this IEventLike eventLike, + DateTimeOffset? timestamp, + string message, + string? category = null, + string? type = null, + IReadOnlyDictionary? data = null, + BreadcrumbLevel level = default) + { + eventLike.AddBreadcrumb(new Breadcrumb( + timestamp, + message, + type, + data, + category, + level)); + } + /// /// Whether a has been set to the object with any of its fields non null. /// diff --git a/src/Sentry/IHasBreadcrumbs.cs b/src/Sentry/IHasBreadcrumbs.cs deleted file mode 100644 index 0146bf12d7..0000000000 --- a/src/Sentry/IHasBreadcrumbs.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Sentry.Internal.Extensions; - -namespace Sentry; - -/// -/// Implemented by objects that contain breadcrumbs. -/// -public interface IHasBreadcrumbs -{ - /// - /// A trail of events which happened prior to an issue. - /// - /// - IReadOnlyCollection Breadcrumbs { get; } - - /// - /// Adds a breadcrumb. - /// - void AddBreadcrumb(Breadcrumb breadcrumb); -} - -/// -/// Extensions for . -/// -[EditorBrowsable(EditorBrowsableState.Never)] -public static class HasBreadcrumbsExtensions -{ -#if !NETFRAMEWORK - /// - /// Adds a breadcrumb to the object. - /// - /// The object. - /// The message. - /// The category. - /// The type. - /// The data key-value pair. - /// The level. - public static void AddBreadcrumb( - this IHasBreadcrumbs hasBreadcrumbs, - string message, - string? category, - string? type, - (string, string)? dataPair = null, - BreadcrumbLevel level = default) - { - // Not to throw on code that ignores nullability warnings. - if (hasBreadcrumbs.IsNull()) - { - return; - } - - Dictionary? data = null; - - if (dataPair != null) - { - data = new Dictionary - { - {dataPair.Value.Item1, dataPair.Value.Item2} - }; - } - - hasBreadcrumbs.AddBreadcrumb( - null, - message, - category, - type, - data, - level); - } -#endif - - /// - /// Adds a breadcrumb to the object. - /// - /// The object. - /// The message. - /// The category. - /// The type. - /// The data. - /// The level. - public static void AddBreadcrumb( - this IHasBreadcrumbs hasBreadcrumbs, - string message, - string? category = null, - string? type = null, - IReadOnlyDictionary? data = null, - BreadcrumbLevel level = default) - { - // Not to throw on code that ignores nullability warnings. - if (hasBreadcrumbs.IsNull()) - { - return; - } - - hasBreadcrumbs.AddBreadcrumb( - null, - message, - category, - type, - data, - level); - } - - /// - /// Adds a breadcrumb to the object. - /// - /// - /// This overload is used for testing. - /// - /// The object. - /// The timestamp - /// The message. - /// The category. - /// The type. - /// The data - /// The level. - [EditorBrowsable(EditorBrowsableState.Never)] - public static void AddBreadcrumb( - this IHasBreadcrumbs hasBreadcrumbs, - DateTimeOffset? timestamp, - string message, - string? category = null, - string? type = null, - IReadOnlyDictionary? data = null, - BreadcrumbLevel level = default) - { - // Not to throw on code that ignores nullability warnings. - if (hasBreadcrumbs.IsNull()) - { - return; - } - - hasBreadcrumbs.AddBreadcrumb(new Breadcrumb( - timestamp, - message, - type, - data, - category, - level)); - } -} diff --git a/src/Sentry/IHasMeasurements.cs b/src/Sentry/IHasMeasurements.cs deleted file mode 100644 index ce54554d75..0000000000 --- a/src/Sentry/IHasMeasurements.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Sentry.Protocol; - -namespace Sentry; - -/// -/// Interface for transactions that can keep track of measurements. -/// -/// -/// Ideally, this would just be implemented as part of . -/// However, adding a property to a public interface is a breaking change. We can do that in a future major version. -/// -internal interface IHasMeasurements -{ - /// - /// The measurements that have been set on the transaction. - /// - IReadOnlyDictionary Measurements { get; } - - /// - /// Sets a measurement on the transaction. - /// - /// The name of the measurement. - /// The measurement. - [EditorBrowsable(EditorBrowsableState.Never)] - void SetMeasurement(string name, Measurement measurement); -} - -/// -/// Extensions for -/// -[EditorBrowsable(EditorBrowsableState.Never)] -public static class MeasurementExtensions -{ - /// - /// Sets a measurement on the transaction. - /// - /// The transaction. - /// The name of the measurement. - /// The value of the measurement. - /// The optional unit of the measurement. - public static void SetMeasurement(this ITransactionData transaction, string name, int value, - MeasurementUnit unit = default) => - (transaction as IHasMeasurements)?.SetMeasurement(name, new Measurement(value, unit)); - - /// - public static void SetMeasurement(this ITransactionData transaction, string name, long value, - MeasurementUnit unit = default) => - (transaction as IHasMeasurements)?.SetMeasurement(name, new Measurement(value, unit)); - - /// -#if !__MOBILE__ - // ulong parameter is not CLS compliant - [CLSCompliant(false)] -#endif - public static void SetMeasurement(this ITransactionData transaction, string name, ulong value, - MeasurementUnit unit = default) => - (transaction as IHasMeasurements)?.SetMeasurement(name, new Measurement(value, unit)); - - /// - public static void SetMeasurement(this ITransactionData transaction, string name, double value, - MeasurementUnit unit = default) => - (transaction as IHasMeasurements)?.SetMeasurement(name, new Measurement(value, unit)); -} \ No newline at end of file diff --git a/src/Sentry/IHasTransactionNameSource.cs b/src/Sentry/IHasTransactionNameSource.cs deleted file mode 100644 index 1362cd4dff..0000000000 --- a/src/Sentry/IHasTransactionNameSource.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Sentry; - -/// -/// Interface for transactions that implement a transaction name source. -/// -/// -/// Ideally, this would just be implemented as part of and . -/// However, adding a property to a public interface is a breaking change. We can do that in a future major version. -/// -public interface IHasTransactionNameSource -{ - /// - /// The source of the transaction name. - /// - TransactionNameSource NameSource { get; } -} diff --git a/src/Sentry/IHub.cs b/src/Sentry/IHub.cs index f2c20b1aee..726d548a7a 100644 --- a/src/Sentry/IHub.cs +++ b/src/Sentry/IHub.cs @@ -22,7 +22,7 @@ public interface IHub : /// /// Starts a transaction. /// - ITransaction StartTransaction( + ITransactionTracer StartTransaction( ITransactionContext context, IReadOnlyDictionary customSamplingContext); @@ -106,4 +106,16 @@ TransactionContext ContinueTrace( /// The callback to configure the scope. /// public SentryId CaptureEvent(SentryEvent evt, Action configureScope); + + /// + /// Captures an event with a configurable scope. + /// + /// + /// This allows modifying a scope without affecting other events. + /// + /// The event to be captured. + /// An optional hint to be provided with the event + /// The callback to configure the scope. + /// + public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Action configureScope); } diff --git a/src/Sentry/ISentryClient.cs b/src/Sentry/ISentryClient.cs index 01971d9790..0b1d193225 100644 --- a/src/Sentry/ISentryClient.cs +++ b/src/Sentry/ISentryClient.cs @@ -10,22 +10,14 @@ public interface ISentryClient /// bool IsEnabled { get; } - /// - /// Capture the event. - /// - /// The event to be captured. - /// An optional scope to be applied to the event. - /// The Id of the event. - SentryId CaptureEvent(SentryEvent evt, Scope? scope = null); - /// /// Capture the event /// /// The event to be captured. - /// An optional hint providing high level context for the source of the event /// An optional scope to be applied to the event. + /// An optional hint providing high level context for the source of the event /// The Id of the event. - SentryId CaptureEvent(SentryEvent evt, Hint? hint, Scope? scope = null); + SentryId CaptureEvent(SentryEvent evt, Scope? scope = null, Hint? hint = null); /// /// Captures a user feedback. @@ -52,12 +44,13 @@ public interface ISentryClient /// Instead, call on the transaction. /// /// The transaction. + /// The scope to be applied to the transaction /// /// A hint providing extra context. /// This will be available in callbacks prior to processing the transaction. /// [EditorBrowsable(EditorBrowsableState.Never)] - void CaptureTransaction(Transaction transaction, Hint? hint); + void CaptureTransaction(Transaction transaction, Scope? scope, Hint? hint); /// /// Captures a session update. diff --git a/src/Sentry/ISentryScopeManager.cs b/src/Sentry/ISentryScopeManager.cs index 9dce098e41..72456843b1 100644 --- a/src/Sentry/ISentryScopeManager.cs +++ b/src/Sentry/ISentryScopeManager.cs @@ -42,18 +42,4 @@ public interface ISentryScopeManager /// A disposable which removes the scope /// from the environment when invoked. IDisposable PushScope(TState state); - - /// - /// Runs the callback within a new scope. - /// - /// - /// Pushes a new scope, runs the callback, then pops the scope. Use this when you have significant work to - /// perform within an isolated scope. If you just need to configure scope for a single event, use the overloads - /// of CaptureEvent, CaptureMessage and CaptureException that provide a callback to a configurable scope. - /// - /// - /// The callback to run with the one time scope. - [Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage and CaptureException " + - "that provide a callback to a configurable scope.")] - void WithScope(Action scopeCallback); } diff --git a/src/Sentry/ISpan.cs b/src/Sentry/ISpan.cs index 38a31b7eb3..e1f4ad436c 100644 --- a/src/Sentry/ISpan.cs +++ b/src/Sentry/ISpan.cs @@ -3,7 +3,7 @@ namespace Sentry; /// -/// Span. +/// SpanTracer interface /// public interface ISpan : ISpanData { @@ -84,10 +84,10 @@ internal static ISpan StartChild(this ISpan span, SpanContext context) /// /// Gets the transaction that this span belongs to. /// - public static ITransaction GetTransaction(this ISpan span) => + public static ITransactionTracer GetTransaction(this ISpan span) => span switch { - ITransaction transaction => transaction, + ITransactionTracer transaction => transaction, SpanTracer tracer => tracer.Transaction, _ => throw new ArgumentOutOfRangeException(nameof(span), span, null) }; diff --git a/src/Sentry/ISpanContext.cs b/src/Sentry/ISpanContext.cs deleted file mode 100644 index 9ba75a0669..0000000000 --- a/src/Sentry/ISpanContext.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Sentry.Protocol; - -namespace Sentry; - -/// -/// Span metadata. -/// -public interface ISpanContext : ITraceContext -{ -} \ No newline at end of file diff --git a/src/Sentry/ISpanData.cs b/src/Sentry/ISpanData.cs index 2187513f83..373ff75c34 100644 --- a/src/Sentry/ISpanData.cs +++ b/src/Sentry/ISpanData.cs @@ -1,9 +1,11 @@ +using Sentry.Protocol; + namespace Sentry; /// /// Immutable data belonging to a span. /// -public interface ISpanData : ISpanContext, IHasTags, IHasExtra +public interface ISpanData : ITraceContext, IHasTags, IHasExtra { /// /// Start timestamp. @@ -24,4 +26,53 @@ public interface ISpanData : ISpanContext, IHasTags, IHasExtra /// Get Sentry trace header. /// SentryTraceHeader GetTraceHeader(); + + /// + /// The measurements that have been set on the transaction. + /// + IReadOnlyDictionary Measurements { get; } + + /// + /// Sets a measurement on the transaction. + /// + /// The name of the measurement. + /// The measurement. + void SetMeasurement(string name, Measurement measurement); +} + +/// +/// Extensions for +/// +[EditorBrowsable(EditorBrowsableState.Never)] +public static class SpanDataExtensions +{ + /// + /// Sets a measurement on the transaction. + /// + /// The transaction. + /// The name of the measurement. + /// The value of the measurement. + /// The optional unit of the measurement. + public static void SetMeasurement(this ISpanData spanData, string name, int value, + MeasurementUnit unit = default) => + spanData.SetMeasurement(name, new Measurement(value, unit)); + + /// + public static void SetMeasurement(this ISpanData spanData, string name, long value, + MeasurementUnit unit = default) => + spanData.SetMeasurement(name, new Measurement(value, unit)); + + /// +#if !__MOBILE__ + // ulong parameter is not CLS compliant + [CLSCompliant(false)] +#endif + public static void SetMeasurement(this ISpanData spanData, string name, ulong value, + MeasurementUnit unit = default) => + spanData.SetMeasurement(name, new Measurement(value, unit)); + + /// + public static void SetMeasurement(this ISpanData spanData, string name, double value, + MeasurementUnit unit = default) => + spanData.SetMeasurement(name, new Measurement(value, unit)); } diff --git a/src/Sentry/ITransactionContext.cs b/src/Sentry/ITransactionContext.cs index 43291ac6d8..d1cb0dc849 100644 --- a/src/Sentry/ITransactionContext.cs +++ b/src/Sentry/ITransactionContext.cs @@ -1,9 +1,11 @@ +using Sentry.Protocol; + namespace Sentry; /// /// Transaction metadata. /// -public interface ITransactionContext : ISpanContext +public interface ITransactionContext : ITraceContext { /// /// Transaction name. @@ -14,4 +16,9 @@ public interface ITransactionContext : ISpanContext /// Whether the parent transaction of this transaction has been sampled. /// bool? IsParentSampled { get; } + + /// + /// The source of the transaction name. + /// + TransactionNameSource NameSource { get; } } diff --git a/src/Sentry/ITransactionData.cs b/src/Sentry/ITransactionData.cs index 2a552a27c3..5752b9f3d8 100644 --- a/src/Sentry/ITransactionData.cs +++ b/src/Sentry/ITransactionData.cs @@ -5,4 +5,13 @@ namespace Sentry; /// public interface ITransactionData : ISpanData, ITransactionContext, IEventLike { + /// + /// The name of the platform. + /// + /// + /// In most cases, the platform will be "csharp". However, it may differ if the event + /// was generated from another embeded SDK. For example, when targeting net6.0-android, + /// events generated by the Sentry Android SDK will have the platform "java". + /// + public string? Platform { get; set; } } diff --git a/src/Sentry/ITransaction.cs b/src/Sentry/ITransactionTracer.cs similarity index 87% rename from src/Sentry/ITransaction.cs rename to src/Sentry/ITransactionTracer.cs index ad21ad325d..015840061c 100644 --- a/src/Sentry/ITransaction.cs +++ b/src/Sentry/ITransactionTracer.cs @@ -1,9 +1,9 @@ namespace Sentry; /// -/// Transaction. +/// TransactionTracer interface /// -public interface ITransaction : ITransactionData, ISpan +public interface ITransactionTracer : ITransactionData, ISpan { /// /// Transaction name. diff --git a/src/Sentry/Infrastructure/DebugDiagnosticLogger.cs b/src/Sentry/Infrastructure/DebugDiagnosticLogger.cs deleted file mode 100644 index 2a974eb5dc..0000000000 --- a/src/Sentry/Infrastructure/DebugDiagnosticLogger.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Sentry.Infrastructure; - -/// -/// Debug logger used by the SDK to report its internal logging. -/// -/// -/// Logger available when compiled in Debug mode. It's useful when debugging apps running under IIS which have no output to Console logger. -/// -[Obsolete("Logger doesn't work outside of Sentry SDK. Please use TraceDiagnosticLogger instead")] -public class DebugDiagnosticLogger : DiagnosticLogger -{ - /// - /// Creates a new instance of . - /// - public DebugDiagnosticLogger(SentryLevel minimalLevel) : base(minimalLevel) - { - } - - /// - protected override void LogMessage(string message) => Debug.WriteLine(message); -} diff --git a/src/Sentry/Infrastructure/SystemClock.cs b/src/Sentry/Infrastructure/SystemClock.cs index d93132ca01..2cc1f348a9 100644 --- a/src/Sentry/Infrastructure/SystemClock.cs +++ b/src/Sentry/Infrastructure/SystemClock.cs @@ -12,17 +12,12 @@ public sealed class SystemClock : ISystemClock /// /// This constructor should have been private originally. It will be removed in a future major version. /// - [Obsolete("This constructor will become private in a future major version. Use the `SystemClock.Clock` singleton instead.")] - public SystemClock() - { - } + private SystemClock() {} /// /// System clock singleton. /// -#pragma warning disable CS0618 public static readonly SystemClock Clock = new(); -#pragma warning restore CS0618 /// /// Gets the current time in UTC. diff --git a/src/Sentry/Integrations/NetFxInstallationsIntegration.cs b/src/Sentry/Integrations/NetFxInstallationsIntegration.cs index a37f9af36f..00060e8454 100644 --- a/src/Sentry/Integrations/NetFxInstallationsIntegration.cs +++ b/src/Sentry/Integrations/NetFxInstallationsIntegration.cs @@ -17,7 +17,7 @@ public void Register(IHub hub, SentryOptions options) } catch (Exception ex) { - options.LogError("Failed to register NetFxInstallations.", ex); + options.LogError(ex, "Failed to register NetFxInstallations."); } } } diff --git a/src/Sentry/Integrations/WinUIUnhandledExceptionIntegration.cs b/src/Sentry/Integrations/WinUIUnhandledExceptionIntegration.cs index 6690217054..a52f3951c1 100644 --- a/src/Sentry/Integrations/WinUIUnhandledExceptionIntegration.cs +++ b/src/Sentry/Integrations/WinUIUnhandledExceptionIntegration.cs @@ -1,5 +1,6 @@ -#if NET5_0_OR_GREATER +#if NET5_0_OR_GREATER && !__MOBILE__ using Sentry.Extensibility; +using Sentry.Internal; namespace Sentry.Integrations; @@ -35,7 +36,7 @@ internal class WinUIUnhandledExceptionIntegration : ISdkIntegration private IHub _hub = null!; private SentryOptions _options = null!; - public static bool IsApplicable => WinUIAssembly != null; + internal static bool IsApplicable => WinUIAssembly != null; public void Register(IHub hub, SentryOptions options) { @@ -73,6 +74,12 @@ public void Register(IHub hub, SentryOptions options) }); } + /// + /// This method uses reflection to hook up an UnhandledExceptionHandler. When IsTrimmed is true, users will have + /// follow our guidance to perform this initialization manually. + /// + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] + [UnconditionalSuppressMessage("Trimming", "IL2075:\'this\' argument does not satisfy \'DynamicallyAccessedMembersAttribute\' in call to target method. The return value of the source method does not have matching annotations.", Justification = AotHelper.SuppressionJustification)] private void AttachEventHandler() { try @@ -89,7 +96,9 @@ private void AttachEventHandler() } catch (Exception ex) { - _options.LogError("Could not attach WinUIUnhandledExceptionHandler.", ex); + // If we get an exception we should let the user know how they can manually wire up the event handler. + // TODO: We need to create a mechanism for users to wire this up manually and document this in a separate PR + _options.LogError(ex, "Could not attach WinUIUnhandledExceptionHandler."); } } @@ -105,7 +114,7 @@ private void WinUIUnhandledExceptionHandler(object sender, object e) } catch (Exception ex) { - _options.LogError("Could not get exception details in WinUIUnhandledExceptionHandler.", ex); + _options.LogError(ex, "Could not get exception details in WinUIUnhandledExceptionHandler."); return; } diff --git a/src/Sentry/Internal/AotHelper.cs b/src/Sentry/Internal/AotHelper.cs new file mode 100644 index 0000000000..4c689f7011 --- /dev/null +++ b/src/Sentry/Internal/AotHelper.cs @@ -0,0 +1,25 @@ +namespace Sentry.Internal; + +internal static class AotHelper +{ + internal const string SuppressionJustification = "Non-trimmable code is avoided at runtime"; + + private class AotTester + { + public void Test() { } + } + +#if NET8_0_OR_GREATER + internal static bool IsNativeAot { get; } + + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] + static AotHelper() + { + var stackTrace = new StackTrace(false); + IsNativeAot = stackTrace.GetFrame(0)?.GetMethod() is null; + } +#else + // This is a compile-time const so that the irrelevant code is removed during compilation. + internal const bool IsNativeAot = false; +#endif +} diff --git a/src/Sentry/Internal/BackgroundWorker.cs b/src/Sentry/Internal/BackgroundWorker.cs index a013841a0c..3e6ca09c16 100644 --- a/src/Sentry/Internal/BackgroundWorker.cs +++ b/src/Sentry/Internal/BackgroundWorker.cs @@ -167,11 +167,9 @@ private async Task DoWorkAsync() } catch (Exception exception) { - _options.LogError( + _options.LogError(exception, "Error while processing envelope (event ID: '{0}'). {1} items in queue.", - exception, - eventId, - _queue.Count); + eventId, _queue.Count); } finally { @@ -193,7 +191,7 @@ private async Task DoWorkAsync() } catch (Exception e) { - _options.LogFatal("Exception in the background worker.", e); + _options.LogFatal(e, "Exception in the background worker."); throw; } } @@ -314,8 +312,7 @@ private async Task SendFinalClientReportAsync(CancellationToken cancellationToke } catch (Exception exception) { - _options.LogError("Error while sending final client report (event ID: '{0}').", - exception, envelope.TryGetEventId(_options.DiagnosticLogger)); + _options.LogError(exception, "Error while sending final client report (event ID: '{0}').", envelope.TryGetEventId(_options.DiagnosticLogger)); } } } @@ -358,7 +355,7 @@ public void Dispose() } catch (Exception exception) { - _options.LogError("Stopping the background worker threw an exception.", exception); + _options.LogError(exception, "Stopping the background worker threw an exception."); } finally { diff --git a/src/Sentry/Internal/DebugStackTrace.cs b/src/Sentry/Internal/DebugStackTrace.cs index 056bfe010a..fceca4cc87 100644 --- a/src/Sentry/Internal/DebugStackTrace.cs +++ b/src/Sentry/Internal/DebugStackTrace.cs @@ -1,6 +1,7 @@ using Sentry.Internal.Extensions; using Sentry.Extensibility; using Sentry.Internal.ILSpy; +using Sentry.Protocol; namespace Sentry.Internal; @@ -16,6 +17,11 @@ internal class DebugStackTrace : SentryStackTrace private const int DebugImageMissing = -1; private bool _debugImagesMerged; +#if NET8_0_OR_GREATER + private Dictionary? _nativeDebugImages; + private HashSet _usedNativeDebugImages = new(); +#endif + /* * NOTE: While we could improve these regexes, doing so might break exception grouping on the backend. * Specifically, RegexAsyncFunctionName would be better as: @"^(.*)\+<(\w*|<\w*>b__\d*)>d(?:__\d*)?$" @@ -31,6 +37,9 @@ internal class DebugStackTrace : SentryStackTrace private static readonly Regex RegexAsyncReturn = new(@"^(.+`[0-9]+)\[\[", RegexOptions.Compiled | RegexOptions.CultureInvariant); + private static readonly Regex RegexNativeAOTInfo = new(@"^(.+)\.([^.]+\(.*\)) ?\+ ?0x", + RegexOptions.Compiled | RegexOptions.CultureInvariant); + internal DebugStackTrace(SentryOptions options) { _options = options; @@ -85,25 +94,55 @@ internal void MergeDebugImagesInto(SentryEvent @event) Dictionary relocations = new(); for (var i = 0; i < DebugImages.Count; i++) { - // First check if the image is already present on the event. Simple lookup should be faster than - // constructing a map first, assuming there are normally just a few debug images affected. - var found = false; - for (var j = 0; j < originalCount; j++) + // Managed debug images + if (DebugImages[i].ModuleVersionId is not null) { - if (DebugImages[i].ModuleVersionId == @event.DebugImages[j].ModuleVersionId) + // First check if the image is already present on the event. Simple lookup should be faster than + // constructing a map first, assuming there are normally just a few debug images affected. + var found = false; + for (var j = 0; j < originalCount; j++) { - if (i != j) + if (DebugImages[i].ModuleVersionId == @event.DebugImages[j].ModuleVersionId) { - relocations.Add(GetRelativeAddressMode(i), GetRelativeAddressMode(j)); + if (i != j) + { + relocations.Add(GetRelativeAddressMode(i), GetRelativeAddressMode(j)); + } + found = true; + break; } - found = true; + } + + if (!found) + { + relocations.Add(GetRelativeAddressMode(i), GetRelativeAddressMode(@event.DebugImages.Count)); + @event.DebugImages.Add(DebugImages[i]); } } + // Native debug images + else if (DebugImages[i].ImageAddress is not null) + { + // First check if the image is already present on the event. Simple lookup should be faster than + // constructing a map first, assuming there are normally just a few debug images affected. + var found = false; + for (var j = 0; j < originalCount; j++) + { + if (DebugImages[i].ImageAddress == @event.DebugImages[j].ImageAddress) + { + found = true; + break; + } + } - if (!found) + if (!found) + { + @event.DebugImages.Add(DebugImages[i]); + } + } + else { - relocations.Add(GetRelativeAddressMode(i), GetRelativeAddressMode(@event.DebugImages.Count)); - @event.DebugImages.Add(DebugImages[i]); + _options.LogWarning("Unexpected debug image: neither ModuleVersionId nor ImageAddress is defined"); + Debug.Assert(false, "This indicates an error in DebugStackTrace code."); } } @@ -119,17 +158,12 @@ internal void MergeDebugImagesInto(SentryEvent @event) /// /// Creates an enumerator of from a . /// + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] private IEnumerable CreateFrames(StackTrace stackTrace, bool isCurrentStackTrace) { - var frames = _options.StackTraceMode switch - { - StackTraceMode.Enhanced => EnhancedStackTrace.GetFrames(stackTrace).Select(p => p as StackFrame), - _ => stackTrace.GetFrames() - // error CS8619: Nullability of reference types in value of type 'StackFrame?[]' doesn't match target type 'IEnumerable'. -#if NETCOREAPP3_0 - .Where(f => f is not null) -#endif - }; + var frames = (!AotHelper.IsNativeAot && _options.StackTraceMode == StackTraceMode.Enhanced) + ? EnhancedStackTrace.GetFrames(stackTrace).Select(p => new RealStackFrame(p)) + : stackTrace.GetFrames().Select(p => new RealStackFrame(p)); // Not to throw on code that ignores nullability warnings. if (frames.IsNull()) @@ -153,103 +187,167 @@ private IEnumerable CreateFrames(StackTrace stackTrace, bool i #endif // Remove the frames until the call for capture with the SDK - if (firstFrame - && isCurrentStackTrace - && stackFrame.GetMethod() is { } method - && method.DeclaringType?.AssemblyQualifiedName?.StartsWith("Sentry") == true) + if (firstFrame && isCurrentStackTrace) { - _options.LogDebug("Skipping initial stack frame '{0}'", method.Name); - continue; + string? frameInfo = null; + if (stackFrame.GetMethod() is { } method) + { + frameInfo = method.DeclaringType?.AssemblyQualifiedName; + } + + // Native AOT currently only exposes some method info at runtime via ToString(). + // See https://github.com/dotnet/runtime/issues/92869 + if (frameInfo is null && stackFrame.HasNativeImage()) + { + frameInfo = stackFrame.ToString(); + } + + if (frameInfo?.StartsWith("Sentry") is true) + { + _options.LogDebug("Skipping initial stack frame '{0}'", frameInfo); + continue; + } } firstFrame = false; - yield return CreateFrame(stackFrame); + if (CreateFrame(stackFrame) is { } frame) + { + yield return frame; + } + else + { + _options.LogDebug("Could not resolve stack frame '{0}'", stackFrame.ToString()); + } } } +#if NET8_0_OR_GREATER /// - /// Create a from a . + /// Native AOT implementation of CreateFrame. + /// Native frames have only limited method information at runtime (and even that can be disabled). + /// We try to parse that and also add addresses for server-side symbolication. /// - internal SentryStackFrame CreateFrame(StackFrame stackFrame) => InternalCreateFrame(stackFrame, true); + private SentryStackFrame? TryCreateNativeAOTFrame(IStackFrame stackFrame) + { + if (!stackFrame.HasNativeImage()) + { + return null; + } + + var imageAddress = stackFrame.GetNativeImageBase(); + var frame = ParseNativeAOTToString(stackFrame.ToString()); + frame.ImageAddress = imageAddress; + frame.InstructionAddress = stackFrame.GetNativeIP(); + +#if __ANDROID__ + // TODO there will be support for NativeAOT in the future. + _nativeDebugImages ??= new(); +#elif __IOS__ || MACCATALYST + _nativeDebugImages ??= Sentry.iOS.C.LoadDebugImages(_options.DiagnosticLogger); +#else + _nativeDebugImages ??= Sentry.Native.C.LoadDebugImages(_options.DiagnosticLogger); +#endif + + if (!_usedNativeDebugImages.Contains(imageAddress) && _nativeDebugImages.TryGetValue(imageAddress, out var debugImage)) + { + _usedNativeDebugImages.Add(imageAddress); + DebugImages.Add(debugImage); + } + + return frame; + } + + // Method info is currently only exposed by ToString(), see https://github.com/dotnet/runtime/issues/92869 + // We only care about the case where the method is available (`StackTraceSupport` property is the default `true`): + // https://github.com/dotnet/runtime/blob/254230253da143a082f47cfaf8711627c0bf2faf/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs#L42 + internal static SentryStackFrame ParseNativeAOTToString(string info) + { + var frame = new SentryStackFrame(); + var match = RegexNativeAOTInfo.Match(info); + if (match is { Success: true, Groups.Count: 3 }) + { + frame.Module = match.Groups[1].Value; + frame.Function = match.Groups[2].Value; + } + return frame; + } +#endif /// /// Default the implementation of CreateFrame. /// - private SentryStackFrame InternalCreateFrame(StackFrame stackFrame, bool demangle) + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] + private SentryStackFrame? TryCreateManagedFrame(IStackFrame stackFrame) { + if (stackFrame.GetMethod() is not { } method) + { + return null; + } + const string unknownRequiredField = "(unknown)"; - string? projectPath = null; - var frame = new SentryStackFrame(); - if (stackFrame.GetMethod() is { } method) + var frame = new SentryStackFrame { - frame.Module = method.DeclaringType?.FullName ?? unknownRequiredField; - frame.Package = method.DeclaringType?.Assembly.FullName; + Module = method.DeclaringType?.FullName ?? unknownRequiredField, + Package = method.DeclaringType?.Assembly.FullName + }; - if (_options.StackTraceMode == StackTraceMode.Enhanced && - stackFrame is EnhancedStackFrame enhancedStackFrame) - { - var stringBuilder = new StringBuilder(); - frame.Function = enhancedStackFrame.MethodInfo.Append(stringBuilder, false).ToString(); + frame.Function = method.Name; - if (enhancedStackFrame.MethodInfo.DeclaringType is { } declaringType) - { - stringBuilder.Clear(); - stringBuilder.AppendTypeDisplayName(declaringType); - - // Ben.Demystifier doesn't always include the namespace, even when fullName==true. - // It's important that the module name always be fully qualified, so that in-app frame - // detection works correctly. - var module = stringBuilder.ToString(); - frame.Module = declaringType.Namespace is { } ns && !module.StartsWith(ns) - ? $"{ns}.{module}" - : module; - } - } - else - { - frame.Function = method.Name; - } + if (stackFrame.Frame is EnhancedStackFrame enhancedStackFrame) + { + var stringBuilder = new StringBuilder(); + frame.Function = enhancedStackFrame.MethodInfo.Append(stringBuilder, false).ToString(); - // Originally we didn't skip methods from dynamic assemblies, so not to break compatibility: - if (_options.StackTraceMode != StackTraceMode.Original && method.Module.Assembly.IsDynamic) + if (enhancedStackFrame.MethodInfo.DeclaringType is { } declaringType) { - frame.InApp = false; + stringBuilder.Clear(); + stringBuilder.AppendTypeDisplayName(declaringType); + + // Ben.Demystifier doesn't always include the namespace, even when fullName==true. + // It's important that the module name always be fully qualified, so that in-app frame + // detection works correctly. + var module = stringBuilder.ToString(); + frame.Module = declaringType.Namespace is { } ns && !module.StartsWith(ns) + ? $"{ns}.{module}" + : module; } + } - AttributeReader.TryGetProjectDirectory(method.Module.Assembly, out projectPath); + // Originally we didn't skip methods from dynamic assemblies, so not to break compatibility: + if (_options.StackTraceMode != StackTraceMode.Original && method.Module.Assembly.IsDynamic) + { + frame.InApp = false; + } - if (AddDebugImage(method.Module) is { } moduleIdx && moduleIdx != DebugImageMissing) - { - frame.AddressMode = GetRelativeAddressMode(moduleIdx); + if (AddManagedModuleDebugImage(method.Module) is { } moduleIdx && moduleIdx != DebugImageMissing) + { + frame.AddressMode = GetRelativeAddressMode(moduleIdx); - try - { - var token = method.MetadataToken; - // The top byte is the token type, the lower three bytes are the record id. - // See: https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms404456(v=vs.100)#metadata-token-structure - var tokenType = token & 0xff000000; - // See https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/cortokentype-enumeration - if (tokenType == 0x06000000) // CorTokenType.mdtMethodDef - { - var recordId = token & 0x00ffffff; - frame.FunctionId = $"0x{recordId:x}"; - } - } - catch (InvalidOperationException) + try + { + var token = method.MetadataToken; + // The top byte is the token type, the lower three bytes are the record id. + // See: https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms404456(v=vs.100)#metadata-token-structure + var tokenType = token & 0xff000000; + // See https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/cortokentype-enumeration + if (tokenType == 0x06000000) // CorTokenType.mdtMethodDef { - // method.MetadataToken may throw - // see https://learn.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo.metadatatoken?view=net-6.0 - _options.LogDebug("Could not get MetadataToken for stack frame {0} from {1}", frame.Function, method.Module.Name); + frame.FunctionId = token & 0x00ffffff; } } + catch (InvalidOperationException) + { + // method.MetadataToken may throw + // see https://learn.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo.metadatatoken?view=net-6.0 + _options.LogDebug("Could not get MetadataToken for stack frame {0} from {1}", frame.Function, method.Module.GetNameOrScopeName()); + } } - frame.ConfigureAppFrame(_options); - if (stackFrame.GetFileName() is { } frameFileName) { - if (projectPath != null && frameFileName.StartsWith(projectPath, StringComparison.OrdinalIgnoreCase)) + if (AttributeReader.TryGetProjectDirectory(method.Module.Assembly) is { } projectPath + && frameFileName.StartsWith(projectPath, StringComparison.OrdinalIgnoreCase)) { frame.AbsolutePath = frameFileName; frameFileName = frameFileName[projectPath.Length..]; @@ -257,11 +355,30 @@ private SentryStackFrame InternalCreateFrame(StackFrame stackFrame, bool demangl frame.FileName = frameFileName; } + return frame; + } + + /// + /// Create a from a . + /// + internal SentryStackFrame? CreateFrame(IStackFrame stackFrame) + { + var frame = TryCreateManagedFrame(stackFrame); +#if NET8_0_OR_GREATER + frame ??= TryCreateNativeAOTFrame(stackFrame); +#endif + if (frame is null) + { + return null; + } + + frame.ConfigureAppFrame(_options); + // stackFrame.HasILOffset() throws NotImplemented on Mono 5.12 var ilOffset = stackFrame.GetILOffset(); if (ilOffset != StackFrame.OFFSET_UNKNOWN) { - frame.InstructionAddress = $"0x{ilOffset:x}"; + frame.InstructionAddress = ilOffset; } var lineNo = stackFrame.GetFileLineNumber(); @@ -271,19 +388,18 @@ private SentryStackFrame InternalCreateFrame(StackFrame stackFrame, bool demangl } var colNo = stackFrame.GetFileColumnNumber(); - if (lineNo > 0) + if (colNo > 0) { frame.ColumnNumber = colNo; } - if (demangle && _options.StackTraceMode != StackTraceMode.Enhanced) + if (stackFrame.Frame is not EnhancedStackFrame) { DemangleAsyncFunctionName(frame); DemangleAnonymousFunction(frame); DemangleLambdaReturnType(frame); } - - if (_options.StackTraceMode == StackTraceMode.Enhanced) + else { // In Enhanced mode, Module (which in this case is the Namespace) // is already prepended to the function, after return type. @@ -378,8 +494,17 @@ private static void DemangleLambdaReturnType(SentryStackFrame frame) } } + [UnconditionalSuppressMessage("SingleFile", "IL3002:Avoid calling members marked with 'RequiresAssemblyFilesAttribute' when publishing as a single-file", Justification = AotHelper.SuppressionJustification)] private static PEReader? TryReadAssemblyFromDisk(Module module, SentryOptions options, out string? assemblyName) { + if (AotHelper.IsNativeAot) + { + #pragma warning disable 0162 // Unreachable code on old .NET frameworks + assemblyName = null; + return null; + #pragma warning restore 0162 + } + assemblyName = module.FullyQualifiedName; if (options.AssemblyReader is { } reader) { @@ -397,7 +522,7 @@ private static void DemangleLambdaReturnType(SentryStackFrame frame) } } - private int? AddDebugImage(Module module) + private int? AddManagedModuleDebugImage(Module module) { var id = module.ModuleVersionId; if (_debugImageIndexByModule.TryGetValue(id, out var idx)) @@ -405,7 +530,7 @@ private static void DemangleLambdaReturnType(SentryStackFrame frame) return idx; } - var debugImage = GetDebugImage(module, _options); + var debugImage = GetManagedModuleDebugImage(module, _options); if (debugImage == null) { // don't try to resolve again @@ -420,7 +545,7 @@ private static void DemangleLambdaReturnType(SentryStackFrame frame) return idx; } - internal static DebugImage? GetDebugImage(Module module, SentryOptions options) + internal static DebugImage? GetManagedModuleDebugImage(Module module, SentryOptions options) { // Try to get it from disk (most common use case) var moduleName = module.GetNameOrScopeName(); diff --git a/src/Sentry/Internal/Enricher.cs b/src/Sentry/Internal/Enricher.cs index 8e59579a54..e7acaf0a55 100644 --- a/src/Sentry/Internal/Enricher.cs +++ b/src/Sentry/Internal/Enricher.cs @@ -36,7 +36,16 @@ public void Apply(IEventLike eventLike) // RuntimeInformation.OSDescription is throwing on Mono 5.12 if (!PlatformAbstractions.Runtime.Current.IsMono()) { +#if NETFRAMEWORK + // RuntimeInformation.* throws on .NET Framework on macOS/Linux + try { + eventLike.Contexts.OperatingSystem.RawDescription = RuntimeInformation.OSDescription; + } catch { + eventLike.Contexts.OperatingSystem.RawDescription = Environment.OSVersion.VersionString; + } +#else eventLike.Contexts.OperatingSystem.RawDescription = RuntimeInformation.OSDescription; +#endif } } @@ -54,14 +63,11 @@ public void Apply(IEventLike eventLike) eventLike.Sdk.AddPackage("nuget:" + SdkVersion.Instance.Name, SdkVersion.Instance.Version); } - // Platform - eventLike.Platform ??= Sentry.Constants.Platform; - // Release eventLike.Release ??= _options.SettingLocator.GetRelease(); // Distribution - eventLike.WithDistribution(_ => _.Distribution ??= _options.Distribution); + eventLike.Distribution ??= _options.Distribution; // Environment eventLike.Environment ??= _options.SettingLocator.GetEnvironment(); diff --git a/src/Sentry/Internal/Extensions/CollectionsExtensions.cs b/src/Sentry/Internal/Extensions/CollectionsExtensions.cs index 0f7cb8fa6d..19277a632a 100644 --- a/src/Sentry/Internal/Extensions/CollectionsExtensions.cs +++ b/src/Sentry/Internal/Extensions/CollectionsExtensions.cs @@ -29,9 +29,16 @@ public static void TryCopyTo(this IDictionary from, } } - public static Dictionary ToDictionary( + // Note this was renamed from ToDictionary to ToDict to avoid conflicts with System.Linq.Enumerable.ToDictionary. + // on .NET 8 and later. Previously this code was simply omitted for .NET 8 targets and later, which compiles fine + // but breaks at runtime (where it's still looking for CollectionExtensions.ToDictionary method). + internal static Dictionary ToDict( this IEnumerable> source) where TKey : notnull => +#if NET8_0_OR_GREATER + source.ToDictionary(); +#else source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); +#endif public static IEnumerable> WhereNotNullValue( this IEnumerable> source) where TKey : notnull @@ -44,17 +51,17 @@ public static IEnumerable> WhereNotNullValue> Append( this IEnumerable> source, TKey key, TValue value) => source.Append(new KeyValuePair(key, value)); - public static IReadOnlyList AsReadOnly(this IList list) => list as IReadOnlyList ?? new ReadOnlyCollection(list); +#if !NET7_0_OR_GREATER public static IReadOnlyDictionary AsReadOnly(this IDictionary dictionary) where TKey : notnull => new ReadOnlyDictionary(dictionary); +#endif public static IEnumerable ExceptNulls(this IEnumerable source) => source.Where(x => x != null).Select(x => x!); diff --git a/src/Sentry/Internal/Extensions/JsonExtensions.cs b/src/Sentry/Internal/Extensions/JsonExtensions.cs index 500cf71aaa..3dc403efb7 100644 --- a/src/Sentry/Internal/Extensions/JsonExtensions.cs +++ b/src/Sentry/Internal/Extensions/JsonExtensions.cs @@ -14,40 +14,80 @@ internal static class JsonExtensions new UIntPtrNullableJsonConverter() }; + private static List CustomConverters = new List(); + internal static bool JsonPreserveReferences { get; set; } = true; + + static JsonExtensions() + { + ResetSerializerOptions(); + } + + private static JsonSerializerOptions BuildOptions(bool preserveReferences) + { + var options = new JsonSerializerOptions(); + if (preserveReferences) + { + options.ReferenceHandler = ReferenceHandler.Preserve; + } + foreach (var converter in DefaultConverters) + { + options.Converters.Add(converter); + } + foreach (var converter in CustomConverters) + { + options.Converters.Add(converter); + } + + return options; + } + private static JsonSerializerOptions SerializerOptions = null!; private static JsonSerializerOptions AltSerializerOptions = null!; - static JsonExtensions() + private static List DefaultSerializerContexts = new(); + private static List ReferencePreservingSerializerContexts = new(); + + private static List> JsonSerializerContextBuilders = new() { + options => new SentryJsonContext(options) + }; + + internal static void AddJsonSerializerContext(Func jsonSerializerContextBuilder) + where T: JsonSerializerContext + { + JsonSerializerContextBuilders.Add(jsonSerializerContextBuilder); ResetSerializerOptions(); } internal static void ResetSerializerOptions() { - SerializerOptions = new JsonSerializerOptions() - .AddDefaultConverters(); + // For our classic reflection based serialization + SerializerOptions = BuildOptions(false); + AltSerializerOptions = BuildOptions(true); - AltSerializerOptions = new JsonSerializerOptions - { - ReferenceHandler = ReferenceHandler.Preserve - } - .AddDefaultConverters(); + // For the new AOT serialization + DefaultSerializerContexts.Clear(); + ReferencePreservingSerializerContexts.Clear(); + foreach (var builder in JsonSerializerContextBuilders) + { + DefaultSerializerContexts.Add(builder(BuildOptions(false))); + ReferencePreservingSerializerContexts.Add(builder(BuildOptions(true))); + } } internal static void AddJsonConverter(JsonConverter converter) { // only add if we don't have this instance already - var converters = SerializerOptions.Converters; - if (converters.Contains(converter)) + if (CustomConverters.Contains(converter)) { return; } try { - SerializerOptions.Converters.Add(converter); - AltSerializerOptions.Converters.Add(converter); + CustomConverters.Add(converter); + ResetSerializerOptions(); } catch (InvalidOperationException) { @@ -62,16 +102,6 @@ internal static void AddJsonConverter(JsonConverter converter) } } - private static JsonSerializerOptions AddDefaultConverters(this JsonSerializerOptions options) - { - foreach (var converter in DefaultConverters) - { - options.Converters.Add(converter); - } - - return options; - } - public static void Deconstruct(this JsonProperty jsonProperty, out string name, out JsonElement value) { name = jsonProperty.Name; @@ -183,7 +213,7 @@ public static void Deconstruct(this JsonProperty jsonProperty, out string name, return double.Parse(json.ToString()!, CultureInfo.InvariantCulture); } - public static long? GetAddressAsLong(this JsonElement json) + public static long? GetHexAsLong(this JsonElement json) { // If the address is in json as a number, we can just use it. if (json.ValueKind == JsonValueKind.Number) @@ -477,31 +507,94 @@ public static void WriteDynamicValue( { writer.WriteStringValue(formattable.ToString(null, CultureInfo.InvariantCulture)); } + else if (value.GetType().ToString() == "System.RuntimeType") + { + writer.WriteStringValue(value.ToString()); + } else { if (!JsonPreserveReferences) { - JsonSerializer.Serialize(writer, value, SerializerOptions); + InternalSerialize(writer, value, preserveReferences: false); return; } try { - // Use an intermediate temporary stream, so we can retry if serialization fails. - using var tempStream = new MemoryStream(); - using var tempWriter = new Utf8JsonWriter(tempStream, writer.Options); - JsonSerializer.Serialize(tempWriter, value, SerializerOptions); - tempWriter.Flush(); - writer.WriteRawValue(tempStream.ToArray()); + // Use an intermediate byte array, so we can retry if serialization fails. + var bytes = InternalSerializeToUtf8Bytes(value); + writer.WriteRawValue(bytes); } catch (JsonException) { // Retry, preserving references to avoid cyclical dependency. - JsonSerializer.Serialize(writer, value, AltSerializerOptions); + InternalSerialize(writer, value, preserveReferences: true); } } } + internal static string ToUtf8Json(this object value, bool preserveReferences = false) + { + using var stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream); + InternalSerialize(writer, value, preserveReferences); + writer.Flush(); + return Encoding.UTF8.GetString(stream.ToArray()); + } + + private static JsonSerializerContext GetSerializerContext(Type type, bool preserveReferences = false) + { + var contexts = preserveReferences ? ReferencePreservingSerializerContexts : DefaultSerializerContexts; + return contexts.FirstOrDefault(c => c.GetTypeInfo(type) != null) + ?? contexts[0]; // If none of the contexts has type info, this gives us a proper exception message + } + + private static byte[] InternalSerializeToUtf8Bytes(object value) + { +#if NET8_0_OR_GREATER + byte[] AotSerializeToUtf8Bytes() + { + var context = GetSerializerContext(value.GetType()); + return JsonSerializer.SerializeToUtf8Bytes(value, value.GetType(), context); + } + return JsonSerializer.IsReflectionEnabledByDefault + ? JitSerializeToUtf8Bytes() + : AotSerializeToUtf8Bytes(); +#else + return JitSerializeToUtf8Bytes(); +#endif + + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = AotHelper.SuppressionJustification)] + byte[] JitSerializeToUtf8Bytes() => JsonSerializer.SerializeToUtf8Bytes(value, SerializerOptions); + } + + private static void InternalSerialize(Utf8JsonWriter writer, object value, bool preserveReferences = false) + { +#if NET8_0_OR_GREATER + if (JsonSerializer.IsReflectionEnabledByDefault) + { + JitSerialize(); + } + else + { + var context = GetSerializerContext(value.GetType(), preserveReferences); + JsonSerializer.Serialize(writer, value, value.GetType(), context); + } +#else + JitSerialize(); +#endif + return; + + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = AotHelper.SuppressionJustification)] + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] + void JitSerialize() + { + var options = preserveReferences ? AltSerializerOptions : SerializerOptions; + JsonSerializer.Serialize(writer, value, options); + } + } + public static void WriteDynamic( this Utf8JsonWriter writer, string propertyName, @@ -706,7 +799,7 @@ public static void WriteDictionaryIfNotEmpty( IEnumerable>? dic, IDiagnosticLogger? logger) { - var dictionary = dic as IReadOnlyDictionary ?? dic?.ToDictionary(); + var dictionary = dic as IReadOnlyDictionary ?? dic?.ToDict(); if (dictionary is not null && dictionary.Count > 0) { writer.WriteDictionary(propertyName, dictionary, logger); @@ -720,7 +813,7 @@ public static void WriteDictionaryIfNotEmpty( IDiagnosticLogger? logger) where TValue : IJsonSerializable? { - var dictionary = dic as IReadOnlyDictionary ?? dic?.ToDictionary(); + var dictionary = dic as IReadOnlyDictionary ?? dic?.ToDict(); if (dictionary is not null && dictionary.Count > 0) { writer.WriteDictionary(propertyName, dictionary, logger); @@ -732,7 +825,7 @@ public static void WriteStringDictionaryIfNotEmpty( string propertyName, IEnumerable>? dic) { - var dictionary = dic as IReadOnlyDictionary ?? dic?.ToDictionary(); + var dictionary = dic as IReadOnlyDictionary ?? dic?.ToDict(); if (dictionary is not null && dictionary.Count > 0) { writer.WriteStringDictionary(propertyName, dictionary); @@ -791,3 +884,10 @@ public static void WriteString( } } } + +[JsonSerializable(typeof(GrowableArray))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +internal partial class SentryJsonContext : JsonSerializerContext +{ +} diff --git a/src/Sentry/Internal/Extensions/PEReaderExtensions.cs b/src/Sentry/Internal/Extensions/PEReaderExtensions.cs index ae612ac6d7..dba8455671 100644 --- a/src/Sentry/Internal/Extensions/PEReaderExtensions.cs +++ b/src/Sentry/Internal/Extensions/PEReaderExtensions.cs @@ -1,4 +1,5 @@ using Sentry.Extensibility; +using Sentry.Protocol; namespace Sentry.Internal.Extensions; diff --git a/src/Sentry/Internal/Extensions/StringExtensions.cs b/src/Sentry/Internal/Extensions/StringExtensions.cs index b2f6a8a164..b0b1f8401d 100644 --- a/src/Sentry/Internal/Extensions/StringExtensions.cs +++ b/src/Sentry/Internal/Extensions/StringExtensions.cs @@ -11,4 +11,19 @@ public static string ToSnakeCase(this string str) => /// Otherwise, returns . /// public static string? NullIfWhitespace(this string? str) => string.IsNullOrWhiteSpace(str) ? null : str; + + public static long ParseHexAsLong(this string str) + { + // It should be in hex format, such as "0x7fff5bf346c0" + if (str.StartsWith("0x") && + long.TryParse(str[2..], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + else if (long.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out result)) + { + return result; + } + throw new FormatException($"ParseHexAsLong() cannot parse '{str}'"); + } } diff --git a/src/Sentry/Internal/GraphQL/ATTRIBUTION.txt b/src/Sentry/Internal/GraphQL/ATTRIBUTION.txt new file mode 100644 index 0000000000..bfb5da5d59 --- /dev/null +++ b/src/Sentry/Internal/GraphQL/ATTRIBUTION.txt @@ -0,0 +1,22 @@ +Parts of the code in this subdirectory have been adapted from +https://github.com/graphql-dotnet/graphql-dotnet/ + +The original license is as follows: + + +The MIT License (MIT) + +Copyright (c) 2015-2023 Joseph T. McBride, Ivan Maximov, Shane Krueger, et al. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/Sentry/Internal/GraphQL/GraphQLRequestContentReader.cs b/src/Sentry/Internal/GraphQL/GraphQLRequestContentReader.cs new file mode 100644 index 0000000000..f8a3909cf1 --- /dev/null +++ b/src/Sentry/Internal/GraphQL/GraphQLRequestContentReader.cs @@ -0,0 +1,64 @@ +namespace Sentry.Internal.GraphQL; + +/// +/// Adapted from https://github.com/graphql-dotnet/graphql-dotnet/blob/42a299e77748ec588bf34c33334e985098563298/src/GraphQL.SystemTextJson/GraphQLRequestJsonConverter.cs#L64 +/// +internal static class GraphQLRequestContentReader +{ + /// + /// Name for the operation name parameter. + /// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters + /// + private const string OperationNameKey = "operationName"; + + /// + /// Name for the query parameter. + /// See https://github.com/graphql/graphql-over-http/blob/master/spec/GraphQLOverHTTP.md#request-parameters + /// + private const string QueryKey = "query"; + + + public static IReadOnlyDictionary Read(string requestContent) + { + Utf8JsonReader reader = new(Encoding.UTF8.GetBytes(requestContent)); + if (!reader.Read() || reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected start of object"); + } + + var request = new Dictionary(); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + return request; + } + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected property name"); + } + + var key = reader.GetString()!; + + if (!reader.Read()) + { + throw new JsonException("unexpected end of data"); + } + + switch (key) + { + case QueryKey: + case OperationNameKey: + request[key] = reader.GetString()!; + break; + default: + reader.Skip(); + break; + } + } + + throw new JsonException("unexpected end of data"); + } +} diff --git a/src/Sentry/Internal/Http/CachingTransport.cs b/src/Sentry/Internal/Http/CachingTransport.cs index d5ac3261c9..93db1fbed4 100644 --- a/src/Sentry/Internal/Http/CachingTransport.cs +++ b/src/Sentry/Internal/Http/CachingTransport.cs @@ -147,7 +147,7 @@ private async Task CachedTransportBackgroundTaskAsync() } catch (Exception ex) { - _options.LogError("Exception in CachingTransport worker.", ex); + _options.LogError(ex, "Exception in CachingTransport worker."); try { @@ -209,9 +209,8 @@ private void MoveUnprocessedFilesBackToCache() } else { - _options.LogError( - "Failed to move unprocessed file back to cache (attempt {0}, done.): {1}", ex, - attempt, filePath); + _options.LogError(ex, + "Failed to move unprocessed file back to cache (attempt {0}, done.): {1}", attempt, filePath); } // note: we do *not* want to re-throw the exception @@ -321,7 +320,7 @@ private async Task InnerProcessCacheAsync(string file, CancellationToken cancell catch (Exception ex) when (ex is HttpRequestException or WebException or SocketException or IOException) { - _options.LogError("Failed to send cached envelope: {0}, retrying after a delay.", ex, file); + _options.LogError(ex, "Failed to send cached envelope: {0}, retrying after a delay.", file); // Let the worker catch, log, wait a bit and retry. throw; } @@ -367,11 +366,11 @@ private void LogFailureWithDiscard(string file, Exception ex) if (envelopeContents == null) { - _options.LogError("Failed to send cached envelope: {0}, discarding cached envelope.", ex, file); + _options.LogError(ex, "Failed to send cached envelope: {0}, discarding cached envelope.", file); } else { - _options.LogError("Failed to send cached envelope: {0}, discarding cached envelope. Envelope contents: {1}", ex, file, envelopeContents); + _options.LogError(ex, "Failed to send cached envelope: {0}, discarding cached envelope. Envelope contents: {1}", file, envelopeContents); } } @@ -502,9 +501,7 @@ public async ValueTask DisposeAsync() catch (Exception ex) { // Don't throw inside dispose - _options.LogError( - "Error stopping worker during dispose.", - ex); + _options.LogError(ex, "Error stopping worker during dispose."); } _workerSignal.Dispose(); diff --git a/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs b/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs index f8577e5bd7..ab1f9a795d 100644 --- a/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs +++ b/src/Sentry/Internal/Http/DefaultSentryHttpClientFactory.cs @@ -23,10 +23,16 @@ public HttpClient Create(SentryOptions options) HttpMessageHandler handler = options.CreateHttpMessageHandler?.Invoke() ?? new HttpClientHandler(); if (handler is HttpClientHandler httpClientHandler) { - if (options.HttpProxy != null) + if (options.HttpProxy is not null) { - httpClientHandler.Proxy = options.HttpProxy; - options.LogInfo("Using Proxy: {0}", options.HttpProxy); + // [CA1416] This call site is reachable on: 'ios' 10.0 and later, 'maccatalyst' 10.0 and later. 'HttpClientHandler.Proxy' is unsupported on: 'ios' all versions, 'maccatalyst' all versions. +#if NET6_0_OR_GREATER + if (!OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) +#endif + { + httpClientHandler.Proxy = options.HttpProxy; + options.LogInfo("Using Proxy: {0}", options.HttpProxy); + } } // If the platform supports automatic decompression diff --git a/src/Sentry/Internal/Http/EnvelopeHttpContent.cs b/src/Sentry/Internal/Http/EnvelopeHttpContent.cs index 66c4565c99..5db14092a0 100644 --- a/src/Sentry/Internal/Http/EnvelopeHttpContent.cs +++ b/src/Sentry/Internal/Http/EnvelopeHttpContent.cs @@ -25,7 +25,7 @@ protected override async Task SerializeToStreamAsync(Stream stream, TransportCon } catch (Exception e) { - _logger?.LogError("Failed to serialize Envelope into the network stream", e); + _logger?.LogError(e, "Failed to serialize Envelope into the network stream"); throw; } } @@ -38,7 +38,7 @@ protected override void SerializeToStream(Stream stream, TransportContext? conte } catch (Exception e) { - _logger?.LogError("Failed to serialize Envelope into the network stream", e); + _logger?.LogError(e, "Failed to serialize Envelope into the network stream"); throw; } } diff --git a/src/Sentry/Internal/Hub.cs b/src/Sentry/Internal/Hub.cs index f511d58568..8d0aa0049f 100644 --- a/src/Sentry/Internal/Hub.cs +++ b/src/Sentry/Internal/Hub.cs @@ -5,7 +5,7 @@ namespace Sentry.Internal; -internal class Hub : IHubEx, IDisposable +internal class Hub : IHub, IDisposable { private readonly object _sessionPauseLock = new(); @@ -14,7 +14,6 @@ internal class Hub : IHubEx, IDisposable private readonly ISessionManager _sessionManager; private readonly SentryOptions _options; private readonly RandomValuesFactory _randomValuesFactory; - private readonly Enricher _enricher; private int _isPersistedSessionRecovered; @@ -59,8 +58,6 @@ internal Hub( PushScope(); } - _enricher = new Enricher(options); - foreach (var integration in options.Integrations) { options.LogDebug("Registering integration: '{0}'.", integration.GetType().Name); @@ -76,7 +73,7 @@ public void ConfigureScope(Action configureScope) } catch (Exception e) { - _options.LogError("Failure to ConfigureScope", e); + _options.LogError(e, "Failure to ConfigureScope"); } } @@ -88,7 +85,7 @@ public async Task ConfigureScopeAsync(Func configureScope) } catch (Exception e) { - _options.LogError("Failure to ConfigureScopeAsync", e); + _options.LogError(e, "Failure to ConfigureScopeAsync"); } } @@ -98,26 +95,14 @@ public async Task ConfigureScopeAsync(Func configureScope) public void RestoreScope(Scope savedScope) => ScopeManager.RestoreScope(savedScope); - [Obsolete] - public void WithScope(Action scopeCallback) => ScopeManager.WithScope(scopeCallback); - - [Obsolete] - public T? WithScope(Func scopeCallback) => ScopeManager.WithScope(scopeCallback); - - [Obsolete] - public Task WithScopeAsync(Func scopeCallback) => ScopeManager.WithScopeAsync(scopeCallback); - - [Obsolete] - public Task WithScopeAsync(Func> scopeCallback) => ScopeManager.WithScopeAsync(scopeCallback); - public void BindClient(ISentryClient client) => ScopeManager.BindClient(client); - public ITransaction StartTransaction( + public ITransactionTracer StartTransaction( ITransactionContext context, IReadOnlyDictionary customSamplingContext) => StartTransaction(context, customSamplingContext, null); - internal ITransaction StartTransaction( + internal ITransactionTracer StartTransaction( ITransactionContext context, IReadOnlyDictionary customSamplingContext, DynamicSamplingContext? dynamicSamplingContext) @@ -277,7 +262,7 @@ public void StartSession() } catch (Exception ex) { - _options.LogError("Failed to recover persisted session.", ex); + _options.LogError(ex, "Failed to recover persisted session."); } } @@ -292,7 +277,7 @@ public void StartSession() } catch (Exception ex) { - _options.LogError("Failed to start a session.", ex); + _options.LogError(ex, "Failed to start a session."); } } @@ -306,7 +291,7 @@ public void PauseSession() } catch (Exception ex) { - _options.LogError("Failed to pause a session.", ex); + _options.LogError(ex, "Failed to pause a session."); } } } @@ -324,7 +309,7 @@ public void ResumeSession() } catch (Exception ex) { - _options.LogError("Failed to resume a session.", ex); + _options.LogError(ex, "Failed to resume a session."); } } } @@ -341,7 +326,7 @@ private void EndSession(DateTimeOffset timestamp, SessionEndStatus status) } catch (Exception ex) { - _options.LogError("Failed to end a session.", ex); + _options.LogError(ex, "Failed to end a session."); } } @@ -380,8 +365,8 @@ private void ApplyTraceContextToEvent(SentryEvent evt, SentryPropagationContext evt.DynamicSamplingContext = propagationContext.GetOrCreateDynamicSamplingContext(_options); } - public SentryId CaptureEvent(SentryEvent evt, Action configureScope) => - CaptureEvent(evt, null, configureScope); + public SentryId CaptureEvent(SentryEvent evt, Action configureScope) + => CaptureEvent(evt, null, configureScope); public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Action configureScope) { @@ -395,23 +380,22 @@ public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Action configur var clonedScope = ScopeManager.GetCurrent().Key.Clone(); configureScope(clonedScope); - return CaptureEvent(evt, hint, clonedScope); + return CaptureEvent(evt, clonedScope, hint); } catch (Exception e) { - _options.LogError("Failure to capture event: {0}", e, evt.EventId); + _options.LogError(e, "Failure to capture event: {0}", evt.EventId); return SentryId.Empty; } } - public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null) => - CaptureEvent(evt, null, scope); - - public SentryId CaptureEvent(SentryEvent evt, Hint? hint, Scope? scope = null) => - IsEnabled ? ((IHubEx)this).CaptureEventInternal(evt, hint, scope) : SentryId.Empty; - - SentryId IHubEx.CaptureEventInternal(SentryEvent evt, Hint? hint, Scope? scope) + public SentryId CaptureEvent(SentryEvent evt, Scope? scope = null, Hint? hint = null) { + if (!IsEnabled) + { + return SentryId.Empty; + } + try { ScopeManager.GetCurrent().Deconstruct(out var currentScope, out var sentryClient); @@ -433,7 +417,7 @@ SentryId IHubEx.CaptureEventInternal(SentryEvent evt, Hint? hint, Scope? scope) } // Now capture the event with the Sentry client on the current scope. - var id = sentryClient.CaptureEvent(evt, hint, actualScope); + var id = sentryClient.CaptureEvent(evt, actualScope, hint); actualScope.LastEventId = id; actualScope.SessionUpdate = null; @@ -449,7 +433,7 @@ SentryId IHubEx.CaptureEventInternal(SentryEvent evt, Hint? hint, Scope? scope) } catch (Exception e) { - _options.LogError("Failure to capture event: {0}", e, evt.EventId); + _options.LogError(e, "Failure to capture event: {0}", evt.EventId); return SentryId.Empty; } } @@ -467,13 +451,13 @@ public void CaptureUserFeedback(UserFeedback userFeedback) } catch (Exception e) { - _options.LogError("Failure to capture user feedback: {0}", e, userFeedback.EventId); + _options.LogError(e, "Failure to capture user feedback: {0}", userFeedback.EventId); } } - public void CaptureTransaction(Transaction transaction) => CaptureTransaction(transaction, null); + public void CaptureTransaction(Transaction transaction) => CaptureTransaction(transaction, null, null); - public void CaptureTransaction(Transaction transaction, Hint? hint) + public void CaptureTransaction(Transaction transaction, Scope? scope, Hint? hint) { // Note: The hub should capture transactions even if it is disabled. // This allows transactions to be reported as failed when they encountered an unhandled exception, @@ -486,38 +470,14 @@ public void CaptureTransaction(Transaction transaction, Hint? hint) try { - // Apply scope data - var (scope, client) = ScopeManager.GetCurrent(); - scope.Evaluate(); - scope.Apply(transaction); - - // Apply enricher - _enricher.Apply(transaction); - - // Add attachments to the hint for processors and callbacks - hint ??= new Hint(); - hint.AddAttachmentsFromScope(scope); - - var processedTransaction = transaction; - if (transaction.IsSampled != false) - { - foreach (var processor in scope.GetAllTransactionProcessors()) - { - processedTransaction = processor.DoProcessTransaction(transaction, hint); - if (processedTransaction == null) - { - _options.ClientReportRecorder.RecordDiscardedEvent(DiscardReason.EventProcessor, DataCategory.Transaction); - _options.LogInfo("Event dropped by processor {0}", processor.GetType().Name); - return; - } - } - } + var (currentScope, client) = ScopeManager.GetCurrent(); + scope ??= currentScope; - client.CaptureTransaction(processedTransaction, hint); + client.CaptureTransaction(transaction, scope, hint); } catch (Exception e) { - _options.LogError("Failure to capture transaction: {0}", e, transaction.SpanId); + _options.LogError(e, "Failure to capture transaction: {0}", transaction.SpanId); } } @@ -534,7 +494,7 @@ public void CaptureSession(SessionUpdate sessionUpdate) } catch (Exception e) { - _options.LogError("Failure to capture session update: {0}", e, sessionUpdate.Id); + _options.LogError(e, "Failure to capture session update: {0}", sessionUpdate.Id); } } @@ -547,7 +507,7 @@ public async Task FlushAsync(TimeSpan timeout) } catch (Exception e) { - _options.LogError("Failure to Flush events", e); + _options.LogError(e, "Failure to Flush events"); } } diff --git a/src/Sentry/Internal/IHasDistribution.cs b/src/Sentry/Internal/IHasDistribution.cs deleted file mode 100644 index 36c6309cea..0000000000 --- a/src/Sentry/Internal/IHasDistribution.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Sentry.Internal; -// NOTE: We only need this interface because IEventLike is public and thus we can't -// add more properties without introducing a potentially breaking change. -// TODO: Move the Distribution property to IEventLike in the next major release. - -internal interface IHasDistribution -{ - /// - /// The release distribution of the application. - /// - public string? Distribution { get; set; } -} - -internal static class HasDistributionExtensions -{ - internal static string? GetDistribution(this IEventLike obj) => - (obj as IHasDistribution)?.Distribution; - - internal static void WithDistribution(this IEventLike obj, Action action) - { - if (obj is IHasDistribution hasDistribution) - { - action.Invoke(hasDistribution); - } - } -} diff --git a/src/Sentry/Internal/IHubEx.cs b/src/Sentry/Internal/IHubEx.cs deleted file mode 100644 index 9a6b200a63..0000000000 --- a/src/Sentry/Internal/IHubEx.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Sentry.Internal; - -internal interface IHubEx : IHub -{ - SentryId CaptureEventInternal(SentryEvent evt, Hint? hint, Scope? scope = null); - - T? WithScope(Func scopeCallback); - Task WithScopeAsync(Func scopeCallback); - Task WithScopeAsync(Func> scopeCallback); -} diff --git a/src/Sentry/Internal/IInternalScopeManager.cs b/src/Sentry/Internal/IInternalScopeManager.cs index 796597b311..81398d1ec4 100644 --- a/src/Sentry/Internal/IInternalScopeManager.cs +++ b/src/Sentry/Internal/IInternalScopeManager.cs @@ -8,9 +8,4 @@ internal interface IInternalScopeManager : ISentryScopeManager, IDisposable void RestoreScope(Scope savedScope); IScopeStackContainer ScopeStackContainer { get; } - - // TODO: Move The following to ISentryScopeManager in a future major version. - T? WithScope(Func scopeCallback); - Task WithScopeAsync(Func scopeCallback); - Task WithScopeAsync(Func> scopeCallback); } diff --git a/src/Sentry/Internal/ILSpy/SingleFileApp.cs b/src/Sentry/Internal/ILSpy/SingleFileApp.cs index e73190ca42..5368fddd96 100644 --- a/src/Sentry/Internal/ILSpy/SingleFileApp.cs +++ b/src/Sentry/Internal/ILSpy/SingleFileApp.cs @@ -1,5 +1,6 @@ using Sentry.Extensibility; using Sentry.Internal.Extensions; +using Sentry.Protocol; namespace Sentry.Internal.ILSpy; @@ -134,17 +135,3 @@ internal static class SingleFileAppExtensions } #endif - -internal static class ModuleExtensions -{ - /// - /// The Module.Name for Modules that are embedded in SingleFileApps will be null - /// or <Unknown>, in that case we can use Module.ScopeName instead - /// - /// A Module instance - /// module.Name, if this is available. module.ScopeName otherwise - public static string? GetNameOrScopeName(this Module module) => - (module?.Name is null || module.Name.Equals("")) - ? module?.ScopeName - : module?.Name; -} diff --git a/src/Sentry/Internal/ITransactionProfiler.cs b/src/Sentry/Internal/ITransactionProfiler.cs index 27cb3ae6fb..71b8280654 100644 --- a/src/Sentry/Internal/ITransactionProfiler.cs +++ b/src/Sentry/Internal/ITransactionProfiler.cs @@ -10,7 +10,7 @@ internal interface ITransactionProfilerFactory /// /// Called during transaction start to start a new profiler, if applicable. /// - ITransactionProfiler? Start(ITransaction transaction, CancellationToken cancellationToken); + ITransactionProfiler? Start(ITransactionTracer transaction, CancellationToken cancellationToken); } /// diff --git a/src/Sentry/Internal/ModuleExtensions.cs b/src/Sentry/Internal/ModuleExtensions.cs new file mode 100644 index 0000000000..0d0665d565 --- /dev/null +++ b/src/Sentry/Internal/ModuleExtensions.cs @@ -0,0 +1,18 @@ +namespace Sentry.Internal; + +internal static class ModuleExtensions +{ + /// + /// The Module.Name for Modules that are embedded in SingleFileApps will be null + /// or <Unknown>, in that case we can use Module.ScopeName instead + /// + /// A Module instance + /// module.Name, if this is available. module.ScopeName otherwise + [UnconditionalSuppressMessage("SingleFile", "IL3002:Avoid calling members marked with 'RequiresAssemblyFilesAttribute' when publishing as a single-file", Justification = AotHelper.SuppressionJustification)] + public static string? GetNameOrScopeName(this Module module) + { + return (AotHelper.IsNativeAot || module?.Name is null || module.Name.Equals("")) + ? module?.ScopeName + : module?.Name; + } +} diff --git a/src/Sentry/Internal/NoOpSpan.cs b/src/Sentry/Internal/NoOpSpan.cs index 96b1cf9106..d5f9ffb505 100644 --- a/src/Sentry/Internal/NoOpSpan.cs +++ b/src/Sentry/Internal/NoOpSpan.cs @@ -1,3 +1,5 @@ +using Sentry.Protocol; + namespace Sentry.Internal; /// @@ -70,4 +72,10 @@ public void SetExtra(string key, object? value) } public SentryTraceHeader GetTraceHeader() => SentryTraceHeader.Empty; + + public IReadOnlyDictionary Measurements => ImmutableDictionary.Empty; + + public void SetMeasurement(string name, Measurement measurement) + { + } } diff --git a/src/Sentry/Internal/NoOpTransaction.cs b/src/Sentry/Internal/NoOpTransaction.cs index 92535847d2..7693e4dddc 100644 --- a/src/Sentry/Internal/NoOpTransaction.cs +++ b/src/Sentry/Internal/NoOpTransaction.cs @@ -1,11 +1,13 @@ +using Sentry.Protocol; + namespace Sentry.Internal; /// /// Transaction class to use when we can't return null but a request to create a transaction couldn't be completed. /// -internal class NoOpTransaction : NoOpSpan, ITransaction +internal class NoOpTransaction : NoOpSpan, ITransactionTracer { - public new static ITransaction Instance { get; } = new NoOpTransaction(); + public new static ITransactionTracer Instance { get; } = new NoOpTransaction(); private NoOpTransaction() { @@ -25,6 +27,14 @@ public bool? IsParentSampled set { } } + public TransactionNameSource NameSource => TransactionNameSource.Custom; + + public string? Distribution + { + get => string.Empty; + set { } + } + public SentryLevel? Level { get => default; @@ -78,8 +88,10 @@ public IReadOnlyList Fingerprint } public IReadOnlyCollection Spans => ImmutableList.Empty; + public IReadOnlyCollection Breadcrumbs => ImmutableList.Empty; public ISpan? GetLastActiveSpan() => default; + public void AddBreadcrumb(Breadcrumb breadcrumb) { } } diff --git a/src/Sentry/Internal/ProcessInfo.cs b/src/Sentry/Internal/ProcessInfo.cs index 506d7aa66b..99b564020b 100644 --- a/src/Sentry/Internal/ProcessInfo.cs +++ b/src/Sentry/Internal/ProcessInfo.cs @@ -56,13 +56,11 @@ internal ProcessInfo( // ArgumentOutOfRangeException: The added or subtracted value results in an un-representable DateTime. // https://github.com/getsentry/sentry-unity/issues/233 - options.LogError( + options.LogError(e, "Failed to find BootTime: Now {0}, GetTimestamp {1}, Frequency {2}, TicksPerSecond: {3}", - e, now, timestamp, - Stopwatch.Frequency, - TimeSpan.TicksPerSecond); + Stopwatch.Frequency, TimeSpan.TicksPerSecond); } // An opt-out to the more precise approach (mainly due to IL2CPP): @@ -85,7 +83,7 @@ internal ProcessInfo( } catch (Exception e) { - options.LogError("Failure getting precise App startup time.", e); + options.LogError(e, "Failure getting precise App startup time."); //Ignore any exception and stay with the less-precise DateTime.UtcNow value. } }).ContinueWith(_ => diff --git a/src/Sentry/Internal/RandomValuesFactory.cs b/src/Sentry/Internal/RandomValuesFactory.cs index e2a5f59f92..4b14d198da 100644 --- a/src/Sentry/Internal/RandomValuesFactory.cs +++ b/src/Sentry/Internal/RandomValuesFactory.cs @@ -7,7 +7,7 @@ internal abstract class RandomValuesFactory public abstract double NextDouble(); public abstract void NextBytes(byte[] bytes); -#if !(NETSTANDARD2_0 || NET461) +#if !(NETSTANDARD2_0 || NET462) public abstract void NextBytes(Span bytes); #endif diff --git a/src/Sentry/Internal/SentryScopeManager.cs b/src/Sentry/Internal/SentryScopeManager.cs index aab716c867..676c105eb5 100644 --- a/src/Sentry/Internal/SentryScopeManager.cs +++ b/src/Sentry/Internal/SentryScopeManager.cs @@ -107,42 +107,6 @@ public void RestoreScope(Scope savedScope) ScopeAndClientStack = newScopeAndClientStack; } - public void WithScope(Action scopeCallback) - { - using (PushScope()) - { - var (scope, _) = GetCurrent(); - scopeCallback.Invoke(scope); - } - } - - public T? WithScope(Func scopeCallback) - { - using (PushScope()) - { - var (scope, _) = GetCurrent(); - return scopeCallback.Invoke(scope); - } - } - - public async Task WithScopeAsync(Func scopeCallback) - { - using (PushScope()) - { - var (scope, _) = GetCurrent(); - await scopeCallback.Invoke(scope).ConfigureAwait(false); - } - } - - public async Task WithScopeAsync(Func> scopeCallback) - { - using (PushScope()) - { - var (scope, _) = GetCurrent(); - return await scopeCallback.Invoke(scope).ConfigureAwait(false); - } - } - public void BindClient(ISentryClient? client) { _options.LogDebug("Binding a new client to the current scope."); diff --git a/src/Sentry/Internal/SettingLocator.cs b/src/Sentry/Internal/SettingLocator.cs index c86963421a..a0a6dfe4fd 100644 --- a/src/Sentry/Internal/SettingLocator.cs +++ b/src/Sentry/Internal/SettingLocator.cs @@ -35,19 +35,15 @@ public string GetDsn() // For DSN only // An empty string set on the option should NOT be converted to null because it is used // to indicate the the SDK is disabled. - - var dsn = _options.Dsn; - if (dsn != null) + _options.Dsn ??= GetEnvironmentVariable(Constants.DsnEnvironmentVariable) + ?? AssemblyForAttributes?.GetCustomAttribute()?.Dsn; + if (_options.Dsn is null) { - return dsn; + throw new ArgumentNullException("You must supply a DSN to use Sentry." + + "To disable Sentry, pass an empty string: \"\"." + + "See https://docs.sentry.io/platforms/dotnet/configuration/options/#dsn"); } - - dsn = GetEnvironmentVariable(Constants.DsnEnvironmentVariable) - ?? AssemblyForAttributes?.GetCustomAttribute()?.Dsn - ?? Sentry.Constants.DisableSdkDsnValue; - - _options.Dsn = dsn; - return dsn; + return _options.Dsn; } public string GetEnvironment() => GetEnvironment(true)!; diff --git a/src/Sentry/Internal/StackFrame.cs b/src/Sentry/Internal/StackFrame.cs new file mode 100644 index 0000000000..2ce23b1344 --- /dev/null +++ b/src/Sentry/Internal/StackFrame.cs @@ -0,0 +1,133 @@ +using Sentry.Internal.Extensions; +using Sentry.Extensibility; + +namespace Sentry.Internal; + +/// +/// Mockable variant of the Diagnostics.StackFrame. +/// This is necessary to test NativeAOT code that relies on extensions from StackFrameExtensions. +/// +internal interface IStackFrame +{ + StackFrame? Frame { get; } + + /// + /// Returns a pointer to the base address of the native image that this stack frame is executing. + /// + /// + /// A pointer to the base address of the native image or System.IntPtr.Zero if you're targeting the .NET Framework. + /// + public nint GetNativeImageBase(); + + /// + /// Gets an interface pointer to the start of the native code for the method that is being executed. + /// + /// + /// An interface pointer to the start of the native code for the method that is being + /// executed or System.IntPtr.Zero if you're targeting the .NET Framework. + /// + public nint GetNativeIP(); + + /// + /// Indicates whether the native image is available for the specified stack frame. + /// + /// + /// true if a native image is available for this stack frame; otherwise, false. + /// + public bool HasNativeImage(); + + /// + /// Gets the column number in the file that contains the code that is executing. + /// This information is typically extracted from the debugging symbols for the executable. + /// + /// + /// The file column number, or 0 (zero) if the file column number cannot be determined. + /// + public int GetFileColumnNumber(); + + /// + /// Gets the line number in the file that contains the code that is executing. This + /// information is typically extracted from the debugging symbols for the executable. + /// + /// + /// The file line number, or 0 (zero) if the file line number cannot be determined. + /// + public int GetFileLineNumber(); + + /// + /// Gets the file name that contains the code that is executing. This information + /// is typically extracted from the debugging symbols for the executable. + /// + /// + /// The file name, or null if the file name cannot be determined. + /// + public string? GetFileName(); + + /// + /// Gets the offset from the start of the Microsoft intermediate language (MSIL) + /// code for the method that is executing. This offset might be an approximation + /// depending on whether or not the just-in-time (JIT) compiler is generating debugging + /// code. The generation of this debugging information is controlled by the System.Diagnostics.DebuggableAttribute. + /// + /// + /// The offset from the start of the MSIL code for the method that is executing. + /// + public int GetILOffset(); + + /// + /// Gets the method in which the frame is executing. + /// + /// + /// The method in which the frame is executing. + /// + public MethodBase? GetMethod(); + + /// + /// Builds a readable representation of the stack trace. + /// + /// + /// A readable representation of the stack trace. + /// + public string ToString(); +} + +internal class RealStackFrame : IStackFrame +{ + private readonly StackFrame _frame; + + public RealStackFrame(StackFrame frame) + { + _frame = frame; + } + + public StackFrame? Frame => _frame; + + public override string ToString() => _frame.ToString(); + + public int GetFileColumnNumber() => _frame.GetFileColumnNumber(); + + public int GetFileLineNumber() => _frame.GetFileLineNumber(); + + public string? GetFileName() => _frame.GetFileName(); + + public int GetILOffset() => _frame.GetILOffset(); + + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = AotHelper.SuppressionJustification)] + public MethodBase? GetMethod() => AotHelper.IsNativeAot + ? null + : _frame.GetMethod(); + +#if NET5_0_OR_GREATER + public nint GetNativeImageBase() => _frame.GetNativeImageBase(); + + public nint GetNativeIP() => _frame.GetNativeIP(); + + public bool HasNativeImage() => _frame.HasNativeImage(); +#else + public nint GetNativeImageBase() => default; + + public nint GetNativeIP() => default; + + public bool HasNativeImage() => false; +#endif +} diff --git a/src/Sentry/Internal/SynchronizedRandomValuesFactory.cs b/src/Sentry/Internal/SynchronizedRandomValuesFactory.cs index b1f591ce12..6388f76314 100644 --- a/src/Sentry/Internal/SynchronizedRandomValuesFactory.cs +++ b/src/Sentry/Internal/SynchronizedRandomValuesFactory.cs @@ -17,7 +17,7 @@ internal class SynchronizedRandomValuesFactory : RandomValuesFactory public override double NextDouble() => Random.NextDouble(); public override void NextBytes(byte[] bytes) => Random.NextBytes(bytes); -#if !(NETSTANDARD2_0 || NET461) +#if !(NETSTANDARD2_0 || NET462) public override void NextBytes(Span bytes) => Random.NextBytes(bytes); #endif diff --git a/src/Sentry/PlatformAbstractions/NetFxInstallationsEventProcessor.cs b/src/Sentry/PlatformAbstractions/NetFxInstallationsEventProcessor.cs index 2ff529c032..dd57ccd646 100644 --- a/src/Sentry/PlatformAbstractions/NetFxInstallationsEventProcessor.cs +++ b/src/Sentry/PlatformAbstractions/NetFxInstallationsEventProcessor.cs @@ -38,7 +38,7 @@ private static Dictionary GetInstallationsDictionary() => } catch (Exception ex) { - _options.LogError("Failed to add NetFxInstallations into event.", ex); + _options.LogError(ex, "Failed to add NetFxInstallations into event."); // In case of any failure, this process function will be disabled to avoid throwing exceptions for future events. _netFxInstallationEnabled = false; diff --git a/src/Sentry/PlatformAbstractions/Runtime.cs b/src/Sentry/PlatformAbstractions/Runtime.cs index 71020b3877..ad9985faac 100644 --- a/src/Sentry/PlatformAbstractions/Runtime.cs +++ b/src/Sentry/PlatformAbstractions/Runtime.cs @@ -56,18 +56,7 @@ public class Runtime : IEquatable /// /// This property will be populated for .NET 5 and newer, or null otherwise. /// - public string? Identifier - { - get => _identifier; - - [Obsolete("This setter is nonfunctional, and will be removed in a future version.")] - // ReSharper disable ValueParameterNotUsed - set { } - // ReSharper restore ValueParameterNotUsed - } - - // TODO: Convert to get-only auto-property in next major version - private readonly string? _identifier; + public string? Identifier { get; } /// /// Creates a new Runtime instance @@ -83,7 +72,7 @@ public Runtime( Version = version; FrameworkInstallation = frameworkInstallation; Raw = raw; - _identifier = null; + Identifier = null; } #else public Runtime( @@ -95,7 +84,7 @@ public Runtime( Name = name; Version = version; Raw = raw; - _identifier = identifier; + Identifier = identifier; } #endif @@ -185,7 +174,7 @@ public override int GetHashCode() #if NETFRAMEWORK hashCode = (hashCode * 397) ^ (FrameworkInstallation?.GetHashCode() ?? 0); #else - hashCode = (hashCode * 397) ^ (_identifier?.GetHashCode() ?? 0); + hashCode = (hashCode * 397) ^ (Identifier?.GetHashCode() ?? 0); #endif return hashCode; } diff --git a/src/Sentry/PlatformAbstractions/RuntimeInfo.cs b/src/Sentry/PlatformAbstractions/RuntimeInfo.cs index af12391754..8a40596a96 100644 --- a/src/Sentry/PlatformAbstractions/RuntimeInfo.cs +++ b/src/Sentry/PlatformAbstractions/RuntimeInfo.cs @@ -1,3 +1,5 @@ +using System; + namespace Sentry.PlatformAbstractions; // https://github.com/dotnet/corefx/issues/17452 @@ -83,29 +85,18 @@ internal static void GetNetFxInstallationAndVersion( } } #else - // Known issue on Docker: https://github.com/dotnet/BenchmarkDotNet/issues/448#issuecomment-361027977 private static string? GetNetCoreVersion(Runtime runtime) { - if (!runtime.IsNetCore()) - { - return null; - } - - // https://github.com/dotnet/BenchmarkDotNet/issues/448#issuecomment-308424100 - var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly; -#if NETCOREAPP3_0_OR_GREATER - var assemblyPath = assembly.Location; -#else - var assemblyPath = assembly.CodeBase; -#endif - var parts = assemblyPath.Split(new[] {'/', '\\'}, StringSplitOptions.RemoveEmptyEntries); - var netCoreAppIndex = Array.IndexOf(parts, "Microsoft.NETCore.App"); - if (netCoreAppIndex > 0 && netCoreAppIndex < parts.Length - 2) - { - return parts[netCoreAppIndex + 1]; - } - - return null; + var description = RuntimeInformation.FrameworkDescription; + return RemovePrefixOrNull(description, ".NET Core") + ?? RemovePrefixOrNull(description, ".NET Framework") + ?? RemovePrefixOrNull(description, ".NET Native") + ?? RemovePrefixOrNull(description, ".NET"); + + static string? RemovePrefixOrNull(string? value, string prefix) + => value?.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) == true + ? value.Substring(prefix.Length) + : null; } #endif diff --git a/src/Sentry/Platforms/Android/AndroidHelpers.cs b/src/Sentry/Platforms/Android/AndroidHelpers.cs index 62efba4854..0de68d6c62 100644 --- a/src/Sentry/Platforms/Android/AndroidHelpers.cs +++ b/src/Sentry/Platforms/Android/AndroidHelpers.cs @@ -45,7 +45,7 @@ public static IList GetSupportedAbis() } catch (Exception ex) { - logger?.LogError("Cannot create assembly reader.", ex); + logger?.LogError(ex, "Cannot create assembly reader."); return null; } } diff --git a/src/Sentry/Platforms/Android/AndroidScopeObserver.cs b/src/Sentry/Platforms/Android/AndroidScopeObserver.cs index 1958505d3c..329930e97f 100644 --- a/src/Sentry/Platforms/Android/AndroidScopeObserver.cs +++ b/src/Sentry/Platforms/Android/AndroidScopeObserver.cs @@ -1,5 +1,6 @@ using Sentry.Android.Extensions; using Sentry.Extensibility; +using Sentry.Internal.Extensions; namespace Sentry.Android; @@ -48,12 +49,12 @@ public void SetExtra(string key, object? value) try { - var json = JsonSerializer.Serialize(value); + var json = value.ToUtf8Json(); JavaSdk.Sentry.SetExtra(key, json); } catch (Exception ex) { - _options.LogError("Extra with key '{0}' could not be serialized.", ex, key); + _options.LogError(ex, "Extra with key '{0}' could not be serialized.", key); } } finally diff --git a/src/Sentry/Platforms/Android/BindableSentryOptions.cs b/src/Sentry/Platforms/Android/BindableSentryOptions.cs new file mode 100644 index 0000000000..45c7ab1654 --- /dev/null +++ b/src/Sentry/Platforms/Android/BindableSentryOptions.cs @@ -0,0 +1,64 @@ +// ReSharper disable once CheckNamespace +namespace Sentry; + +internal partial class BindableSentryOptions +{ + public AndroidOptions Android { get; } = new AndroidOptions(); + + /// + /// Provides additional options for the Android platform. + /// + public class AndroidOptions + { + public bool? AnrEnabled { get; set; } + public bool? AnrReportInDebug { get; set; } + public TimeSpan? AnrTimeoutInterval { get; set; } + public bool? AttachScreenshot { get; set; } + public bool? EnableActivityLifecycleBreadcrumbs { get; set; } + public bool? EnableAppComponentBreadcrumbs { get; set; } + public bool? EnableAppLifecycleBreadcrumbs { get; set; } + public bool? EnableRootCheck { get; set; } + public bool? EnableSystemEventBreadcrumbs { get; set; } + public bool? EnableUserInteractionBreadcrumbs { get; set; } + public bool? EnableAutoActivityLifecycleTracing { get; set; } + public bool? EnableActivityLifecycleTracingAutoFinish { get; set; } + public bool? EnableUserInteractionTracing { get; set; } + public bool? AttachThreads { get; set; } + public TimeSpan? ConnectionTimeout { get; set; } + public bool? EnableNdk { get; set; } + public bool? EnableShutdownHook { get; set; } + public bool? EnableUncaughtExceptionHandler { get; set; } + public bool? PrintUncaughtStackTrace { get; set; } + public double? ProfilesSampleRate { get; set; } + public TimeSpan? ReadTimeout { get; set; } + public bool? EnableAndroidSdkTracing { get; set; } + public bool? EnableAndroidSdkBeforeSend { get; set; } + + public void ApplyTo(SentryOptions.AndroidOptions options) + { + options.AnrEnabled = AnrEnabled ?? options.AnrEnabled; + options.AnrReportInDebug = AnrReportInDebug ?? options.AnrReportInDebug; + options.AnrTimeoutInterval = AnrTimeoutInterval ?? options.AnrTimeoutInterval; + options.AttachScreenshot = AttachScreenshot ?? options.AttachScreenshot; + options.EnableActivityLifecycleBreadcrumbs = EnableActivityLifecycleBreadcrumbs ?? options.EnableActivityLifecycleBreadcrumbs; + options.EnableAppComponentBreadcrumbs = EnableAppComponentBreadcrumbs ?? options.EnableAppComponentBreadcrumbs; + options.EnableAppLifecycleBreadcrumbs = EnableAppLifecycleBreadcrumbs ?? options.EnableAppLifecycleBreadcrumbs; + options.EnableRootCheck = EnableRootCheck ?? options.EnableRootCheck; + options.EnableSystemEventBreadcrumbs = EnableSystemEventBreadcrumbs ?? options.EnableSystemEventBreadcrumbs; + options.EnableUserInteractionBreadcrumbs = EnableUserInteractionBreadcrumbs ?? options.EnableUserInteractionBreadcrumbs; + options.EnableAutoActivityLifecycleTracing = EnableAutoActivityLifecycleTracing ?? options.EnableAutoActivityLifecycleTracing; + options.EnableActivityLifecycleTracingAutoFinish = EnableActivityLifecycleTracingAutoFinish ?? options.EnableActivityLifecycleTracingAutoFinish; + options.EnableUserInteractionTracing = EnableUserInteractionTracing ?? options.EnableUserInteractionTracing; + options.AttachThreads = AttachThreads ?? options.AttachThreads; + options.ConnectionTimeout = ConnectionTimeout ?? options.ConnectionTimeout; + options.EnableNdk = EnableNdk ?? options.EnableNdk; + options.EnableShutdownHook = EnableShutdownHook ?? options.EnableShutdownHook; + options.EnableUncaughtExceptionHandler = EnableUncaughtExceptionHandler ?? options.EnableUncaughtExceptionHandler; + options.PrintUncaughtStackTrace = PrintUncaughtStackTrace ?? options.PrintUncaughtStackTrace; + options.ProfilesSampleRate = ProfilesSampleRate ?? options.ProfilesSampleRate; + options.ReadTimeout = ReadTimeout ?? options.ReadTimeout; + options.EnableAndroidSdkTracing = EnableAndroidSdkTracing ?? options.EnableAndroidSdkTracing; + options.EnableAndroidSdkBeforeSend = EnableAndroidSdkBeforeSend ?? options.EnableAndroidSdkBeforeSend; + } + } +} diff --git a/src/Sentry/Platforms/Android/SentryOptions.cs b/src/Sentry/Platforms/Android/SentryOptions.cs index 2c352c729c..a93de39b8c 100644 --- a/src/Sentry/Platforms/Android/SentryOptions.cs +++ b/src/Sentry/Platforms/Android/SentryOptions.cs @@ -143,13 +143,6 @@ internal AndroidOptions(SentryOptions options) /// public bool EnableUserInteractionTracing { get; set; } = false; - /// - /// Deprecated. - /// - [Obsolete("This property is deprecated and ignored.")] - public TimeSpan ProfilingTracesInterval { get; set; } - - // ---------- From SentryOptions.java ---------- /// @@ -164,16 +157,6 @@ internal AndroidOptions(SentryOptions options) /// public TimeSpan ConnectionTimeout { get; set; } = TimeSpan.FromSeconds(5); - /// - /// The distribution of the application, associated with the release set in . - /// - [Obsolete("Use SentryOptions.Distribution instead. This property will be removed in a future version.")] - public string? Distribution - { - get => _options.Distribution; - set => _options.Distribution = value; - } - /// /// Gets or sets a value that indicates if the NDK (Android Native Development Kit) is enabled. /// The default value is true (enabled). @@ -201,17 +184,6 @@ public string? Distribution /// public bool PrintUncaughtStackTrace { get; set; } = false; - /// - /// Gets or sets if profiling is enabled for transactions. - /// The default value is false (disabled). - /// - [Obsolete("Use ProfilesSampleRate instead")] - public bool ProfilingEnabled - { - get => (ProfilesSampleRate ?? 0.0) > 0.0; - set => ProfilesSampleRate = value ? 1.0 : null; - } - /// /// Gets or sets the profiling sample rate, between 0.0 and 1.0. /// The default value is null (disabled). @@ -270,8 +242,8 @@ public void AddInAppInclude(string prefix){ public bool EnableAndroidSdkTracing { get; set; } = false; /// - /// Gets or sets a value that indicates if the callback will be invoked for - /// events that originate from the embedded Android SDK. The default value is false (disabled). + /// Gets or sets a value that indicates if the BeforeSend callback set in + /// will be invoked for events that originate from the embedded Android SDK. The default value is false (disabled). /// /// /// This is an experimental feature and is imperfect, as the .NET SDK and the embedded Android SDK don't diff --git a/src/Sentry/Platforms/Android/SentrySdk.cs b/src/Sentry/Platforms/Android/SentrySdk.cs index 942facc124..0cecf5c36a 100644 --- a/src/Sentry/Platforms/Android/SentrySdk.cs +++ b/src/Sentry/Platforms/Android/SentrySdk.cs @@ -220,7 +220,9 @@ private static void AndroidEnvironment_UnhandledExceptionRaiser(object? _, Raise return null; } +#pragma warning disable CS0618 // Type or member is obsolete var packageInfo = AppContext.PackageManager?.GetPackageInfo(packageName, PackageInfoFlags.Permissions); +#pragma warning restore CS0618 // Type or member is obsolete return packageInfo == null ? null : $"{packageName}@{packageInfo.VersionName}+{packageInfo.GetVersionCode()}"; } @@ -234,7 +236,9 @@ private static void AndroidEnvironment_UnhandledExceptionRaiser(object? _, Raise return null; } +#pragma warning disable CS0618 // Type or member is obsolete var packageInfo = AppContext.PackageManager?.GetPackageInfo(packageName, PackageInfoFlags.Permissions); +#pragma warning restore CS0618 // Type or member is obsolete return packageInfo?.GetVersionCode(); } @@ -251,7 +255,10 @@ private static void AndroidEnvironment_UnhandledExceptionRaiser(object? _, Raise #pragma warning disable CS0618 // obsolete on Android >= P (28) +#pragma warning disable CA1422 + // 'PackageInfo.VersionCode' is obsoleted on: 'Android' 28.0 and later. return packageInfo.VersionCode; +#pragma warning restore CA1422 #pragma warning restore CS0618 } } diff --git a/src/Sentry/Platforms/Native/.gitignore b/src/Sentry/Platforms/Native/.gitignore new file mode 100644 index 0000000000..adf28a93fc --- /dev/null +++ b/src/Sentry/Platforms/Native/.gitignore @@ -0,0 +1 @@ +sentry-native diff --git a/src/Sentry/Platforms/Native/CFunctions.cs b/src/Sentry/Platforms/Native/CFunctions.cs new file mode 100644 index 0000000000..2f6eb6d69a --- /dev/null +++ b/src/Sentry/Platforms/Native/CFunctions.cs @@ -0,0 +1,221 @@ +using Sentry.Extensibility; +using Sentry.Internal.Extensions; +using Sentry.Protocol; + +namespace Sentry.Native; + +// https://github.com/getsentry/sentry-unity/blob/3eb6eca6ed270c5ec023bf75ee53c1ca00bb7c82/src/Sentry.Unity/NativeUtils/CFunctions.cs + +internal static class C +{ + internal static void SetValueIfNotNull(sentry_value_t obj, string key, string? value) + { + if (value is not null) + { + _ = sentry_value_set_by_key(obj, key, sentry_value_new_string(value)); + } + } + + internal static void SetValueIfNotNull(sentry_value_t obj, string key, int? value) + { + if (value.HasValue) + { + _ = sentry_value_set_by_key(obj, key, sentry_value_new_int32(value.Value)); + } + } + + internal static void SetValueIfNotNull(sentry_value_t obj, string key, bool? value) + { + if (value.HasValue) + { + _ = sentry_value_set_by_key(obj, key, sentry_value_new_bool(value.Value ? 1 : 0)); + } + } + + internal static void SetValueIfNotNull(sentry_value_t obj, string key, double? value) + { + if (value.HasValue) + { + _ = sentry_value_set_by_key(obj, key, sentry_value_new_double(value.Value)); + } + } + + internal static sentry_value_t? GetValueOrNul(sentry_value_t obj, string key) + { + var cValue = sentry_value_get_by_key(obj, key); + return sentry_value_is_null(cValue) == 0 ? cValue : null; + } + + internal static string? GetValueString(sentry_value_t obj, string key) + { + if (GetValueOrNul(obj, key) is { } cValue) + { + var cString = sentry_value_as_string(cValue); + if (cString != IntPtr.Zero) + { + return Marshal.PtrToStringAnsi(cString); + } + } + return null; + } + + internal static int? GetValueInt(sentry_value_t obj, string key) + { + if (GetValueOrNul(obj, key) is { } cValue) + { + return sentry_value_as_int32(cValue); + } + return null; + } + + internal static double? GetValueDouble(sentry_value_t obj, string key) + { + if (GetValueOrNul(obj, key) is { } cValue) + { + return sentry_value_as_double(cValue); + } + return null; + } + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_object(); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_null(); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_bool(int value); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_double(double value); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_int32(int value); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_string(string value); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_new_breadcrumb(string? type, string? message); + + [DllImport("sentry-native")] + internal static extern int sentry_value_set_by_key(sentry_value_t value, string k, sentry_value_t v); + + internal static bool IsNull(sentry_value_t value) => sentry_value_is_null(value) != 0; + + [DllImport("sentry-native")] + internal static extern int sentry_value_is_null(sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern int sentry_value_as_int32(sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern double sentry_value_as_double(sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern IntPtr sentry_value_as_string(sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern UIntPtr sentry_value_get_length(sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_get_by_index(sentry_value_t value, UIntPtr index); + + [DllImport("sentry-native")] + internal static extern sentry_value_t sentry_value_get_by_key(sentry_value_t value, string key); + + [DllImport("sentry-native")] + internal static extern void sentry_set_context(string key, sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern void sentry_add_breadcrumb(sentry_value_t breadcrumb); + + [DllImport("sentry-native")] + internal static extern void sentry_set_tag(string key, string value); + + [DllImport("sentry-native")] + internal static extern void sentry_remove_tag(string key); + + [DllImport("sentry-native")] + internal static extern void sentry_set_user(sentry_value_t user); + + [DllImport("sentry-native")] + internal static extern void sentry_remove_user(); + + [DllImport("sentry-native")] + internal static extern void sentry_set_extra(string key, sentry_value_t value); + + [DllImport("sentry-native")] + internal static extern void sentry_remove_extra(string key); + + internal static Dictionary LoadDebugImages(IDiagnosticLogger? logger) + { + logger?.LogDebug("Collecting a list of native debug images."); + var result = new Dictionary(); + try + { + var cList = sentry_get_modules_list(); + try + { + if (!IsNull(cList)) + { + var len = sentry_value_get_length(cList).ToUInt32(); + logger?.LogDebug("There are {0} native debug images, parsing the information.", len); + for (uint i = 0; i < len; i++) + { + var cItem = sentry_value_get_by_index(cList, (UIntPtr)i); + if (!IsNull(cItem)) + { + // See possible values present in `cItem` in the following files (or their latest versions) + // * https://github.com/getsentry/sentry-native/blob/8faa78298da68d68043f0c3bd694f756c0e95dfa/src/modulefinder/sentry_modulefinder_windows.c#L81 + // * https://github.com/getsentry/sentry-native/blob/8faa78298da68d68043f0c3bd694f756c0e95dfa/src/modulefinder/sentry_modulefinder_windows.c#L24 + // * https://github.com/getsentry/sentry-native/blob/c5c31e56d36bed37fa5422750a591f44502edb41/src/modulefinder/sentry_modulefinder_linux.c#L465 + if (GetValueString(cItem, "image_addr") is { } imageAddr && imageAddr.Length > 0) + { + var imageAddress = imageAddr.ParseHexAsLong(); + result.Add(imageAddress, new DebugImage() + { + CodeFile = GetValueString(cItem, "code_file"), + ImageAddress = imageAddress, + ImageSize = GetValueInt(cItem, "image_size"), + DebugFile = GetValueString(cItem, "debug_file"), + DebugId = GetValueString(cItem, "debug_id"), + CodeId = GetValueString(cItem, "code_id"), + Type = GetValueString(cItem, "type"), + }); + } + } + } + } + } + finally + { + sentry_value_decref(cList); + } + } + catch (Exception e) + { + logger?.LogWarning("Error loading the list of debug images", e); + } + return result; + } + + // Returns a new reference to an immutable, frozen list. + // The reference must be released with `sentry_value_decref`. + [DllImport("sentry-native")] + private static extern sentry_value_t sentry_get_modules_list(); + + [DllImport("sentry-native")] + internal static extern void sentry_value_decref(sentry_value_t value); + + // native union sentry_value_u/t + [StructLayout(LayoutKind.Explicit)] + internal struct sentry_value_t + { + [FieldOffset(0)] + internal ulong _bits; + [FieldOffset(0)] + internal double _double; + } + +} diff --git a/src/Sentry/Platforms/Native/Sentry.Native.targets b/src/Sentry/Platforms/Native/Sentry.Native.targets new file mode 100644 index 0000000000..3e04d891bc --- /dev/null +++ b/src/Sentry/Platforms/Native/Sentry.Native.targets @@ -0,0 +1,64 @@ + + + + ..\..\modules\sentry-native\ + sentry-native + ../../scripts/build-sentry-native.ps1 + ../../.git/modules/modules/sentry-native/HEAD;$(MSBuildThisFileDirectory)Sentry.Native.targets;$(SentryNativeBuildScript) + $(MSBuildThisFileDirectory)sentry-native\ + + win-x64 + $(SentryNativeOutputDirectory)$(NativeLibRelativePath-win-x64)\ + linux-x64 + $(SentryNativeOutputDirectory)$(NativeLibRelativePath-linux-x64)\ + osx + $(SentryNativeOutputDirectory)$(NativeLibRelativePath-osx)\ + $(SentryNativeOutputDirectory-win-x64)$(SentryNativeLibraryName).lib + $(SentryNativeOutputDirectory-linux-x64)lib$(SentryNativeLibraryName).a + $(SentryNativeOutputDirectory-osx)lib$(SentryNativeLibraryName).a + + + + + + + + + + + + true + \sentry-native\$(NativeLibRelativePath-win-x64) + + + + + + true + \sentry-native\$(NativeLibRelativePath-linux-x64) + + + + + + true + \sentry-native\$(NativeLibRelativePath-osx) + + + + + + + + + + + + + + diff --git a/src/Sentry/Platforms/Native/buildTransitive/Sentry.Native.targets b/src/Sentry/Platforms/Native/buildTransitive/Sentry.Native.targets new file mode 100644 index 0000000000..86128a87e2 --- /dev/null +++ b/src/Sentry/Platforms/Native/buildTransitive/Sentry.Native.targets @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Sentry/Platforms/Native/windows-config.cmake b/src/Sentry/Platforms/Native/windows-config.cmake new file mode 100644 index 0000000000..cde2a2bdce --- /dev/null +++ b/src/Sentry/Platforms/Native/windows-config.cmake @@ -0,0 +1,3 @@ +# Include debug info in the static library itself. See https://github.com/getsentry/sentry-native/issues/895 for context. +set(CMAKE_C_FLAGS_RELWITHDEBINFO "/Z7 /O2 /Ob1 /DNDEBUG" CACHE STRING "C Flags for RelWithDebInfo" FORCE) +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/Z7 /O2 /Ob1 /DNDEBUG" CACHE STRING "CXX Flags for RelWithDebInfo" FORCE) \ No newline at end of file diff --git a/src/Sentry/Platforms/iOS/BindableSentryOptions.cs b/src/Sentry/Platforms/iOS/BindableSentryOptions.cs new file mode 100644 index 0000000000..f98f979a44 --- /dev/null +++ b/src/Sentry/Platforms/iOS/BindableSentryOptions.cs @@ -0,0 +1,48 @@ +// ReSharper disable once CheckNamespace +namespace Sentry; + +internal partial class BindableSentryOptions +{ + public IosOptions iOS { get; } = new IosOptions(); + + /// + /// Provides additional options for the Android platform. + /// + public class IosOptions + { + public bool? AttachScreenshot { get; set; } + public TimeSpan? AppHangTimeoutInterval { get; set; } + public TimeSpan? IdleTimeout { get; set; } + public bool? EnableAppHangTracking { get; set; } + public bool? EnableAutoBreadcrumbTracking { get; set; } + public bool? EnableAutoPerformanceTracing { get; set; } + public bool? EnableCoreDataTracing { get; set; } + public bool? EnableFileIOTracing { get; set; } + public bool? EnableNetworkBreadcrumbs { get; set; } + public bool? EnableNetworkTracking { get; set; } + public bool? EnableWatchdogTerminationTracking { get; set; } + public bool? EnableSwizzling { get; set; } + public bool? EnableUIViewControllerTracing { get; set; } + public bool? EnableUserInteractionTracing { get; set; } + public bool? EnableCocoaSdkTracing { get; set; } + + public void ApplyTo(SentryOptions.IosOptions options) + { + options.AttachScreenshot = AttachScreenshot ?? options.AttachScreenshot; + options.AppHangTimeoutInterval = AppHangTimeoutInterval ?? options.AppHangTimeoutInterval; + options.IdleTimeout = IdleTimeout ?? options.IdleTimeout; + options.EnableAppHangTracking = EnableAppHangTracking ?? options.EnableAppHangTracking; + options.EnableAutoBreadcrumbTracking = EnableAutoBreadcrumbTracking ?? options.EnableAutoBreadcrumbTracking; + options.EnableAutoPerformanceTracing = EnableAutoPerformanceTracing ?? options.EnableAutoPerformanceTracing; + options.EnableCoreDataTracing = EnableCoreDataTracing ?? options.EnableCoreDataTracing; + options.EnableFileIOTracing = EnableFileIOTracing ?? options.EnableFileIOTracing; + options.EnableNetworkBreadcrumbs = EnableNetworkBreadcrumbs ?? options.EnableNetworkBreadcrumbs; + options.EnableNetworkTracking = EnableNetworkTracking ?? options.EnableNetworkTracking; + options.EnableWatchdogTerminationTracking = EnableWatchdogTerminationTracking ?? options.EnableWatchdogTerminationTracking; + options.EnableSwizzling = EnableSwizzling ?? options.EnableSwizzling; + options.EnableUIViewControllerTracing = EnableUIViewControllerTracing ?? options.EnableUIViewControllerTracing; + options.EnableUserInteractionTracing = EnableUserInteractionTracing ?? options.EnableUserInteractionTracing; + options.EnableCocoaSdkTracing = EnableCocoaSdkTracing ?? options.EnableCocoaSdkTracing; + } + } +} diff --git a/src/Sentry/Platforms/iOS/CFunctions.cs b/src/Sentry/Platforms/iOS/CFunctions.cs new file mode 100644 index 0000000000..3463b3f7fa --- /dev/null +++ b/src/Sentry/Platforms/iOS/CFunctions.cs @@ -0,0 +1,38 @@ +using Sentry.Extensibility; +using Sentry.Internal.Extensions; +using Sentry.Protocol; + +namespace Sentry.iOS; + +internal static class C +{ + internal static Dictionary LoadDebugImages(IDiagnosticLogger? logger) + { + logger?.LogDebug("Collecting a list of native debug images."); + var result = new Dictionary(); + try + { + var cList = SentryCocoaHybridSdk.DebugImages; + logger?.LogDebug("There are {0} native debug images, parsing the information.", cList.Length); + foreach (var cItem in cList) + { + if (cItem.ImageAddress?.ParseHexAsLong() is { } imageAddress) + { + result.Add(imageAddress, new DebugImage() + { + CodeFile = cItem.CodeFile, + ImageAddress = imageAddress, + ImageSize = cItem.ImageSize?.LongValue, + DebugId = cItem.DebugID, + Type = cItem.Type, + }); + } + } + } + catch (Exception e) + { + logger?.LogWarning("Error loading the list of debug images", e); + } + return result; + } +} diff --git a/src/Sentry/Platforms/iOS/Extensions/CocoaExtensions.cs b/src/Sentry/Platforms/iOS/Extensions/CocoaExtensions.cs index 69b86b19dd..f66dcc24a1 100644 --- a/src/Sentry/Platforms/iOS/Extensions/CocoaExtensions.cs +++ b/src/Sentry/Platforms/iOS/Extensions/CocoaExtensions.cs @@ -46,7 +46,7 @@ internal static class CocoaExtensions } catch (Exception ex) { - logger?.LogError("Error serializing {0} to JSON", ex, obj.GetType().Name); + logger?.LogError(ex, "Error serializing {0} to JSON", obj.GetType().Name); return null; } } diff --git a/src/Sentry/Platforms/iOS/IosScopeObserver.cs b/src/Sentry/Platforms/iOS/IosScopeObserver.cs index 5274aa1487..7fdb33ee4b 100644 --- a/src/Sentry/Platforms/iOS/IosScopeObserver.cs +++ b/src/Sentry/Platforms/iOS/IosScopeObserver.cs @@ -1,5 +1,6 @@ using Sentry.iOS.Extensions; using Sentry.Extensibility; +using Sentry.Internal.Extensions; namespace Sentry.iOS; @@ -50,12 +51,12 @@ public void SetExtra(string key, object? value) try { - var json = JsonSerializer.Serialize(value); + var json = value.ToUtf8Json(); SentryCocoaSdk.ConfigureScope(scope => scope.SetExtraValue(NSObject.FromObject(json), key)); } catch (Exception ex) { - _options.LogError("Extra with key '{0}' could not be serialized.", ex, key); + _options.LogError(ex, "Extra with key '{0}' could not be serialized.", key); } } finally diff --git a/src/Sentry/Platforms/iOS/SentryOptions.cs b/src/Sentry/Platforms/iOS/SentryOptions.cs index f1f51a7c94..c43712d357 100644 --- a/src/Sentry/Platforms/iOS/SentryOptions.cs +++ b/src/Sentry/Platforms/iOS/SentryOptions.cs @@ -56,16 +56,6 @@ internal IosOptions(SentryOptions options) /// public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(3); - /// - /// The distribution of the application, associated with the release set in . - /// - [Obsolete("Use SentryOptions.Distribution instead. This property will be removed in a future version.")] - public string? Distribution - { - get => _options.Distribution; - set => _options.Distribution = value; - } - /// /// When enabled, the SDK tracks when the application stops responding for a specific amount of /// time defined by the option. @@ -97,23 +87,6 @@ public string? Distribution /// public bool EnableAutoPerformanceTracing { get; set; } = true; - /// - /// When enabled, the SDK tracks performance for subclasses and HTTP requests - /// automatically. It also measures the app start and slow and frozen frames. - /// The default value is true (enabled). - /// - /// - /// Performance Monitoring must be enabled for this option to take effect. - /// See: https://docs.sentry.io/platforms/apple/performance/ - /// And: https://docs.sentry.io/platforms/apple/performance/instrumentation/automatic-instrumentation/#opt-out - /// - [Obsolete("Use EnableAutoPerformanceTracing instead. This property will be removed in a future version.")] - public bool EnableAutoPerformanceTracking - { - get => EnableAutoPerformanceTracing; - set => EnableAutoPerformanceTracing = value; - } - /// /// When enabled, the SDK tracks the performance of Core Data operations. /// It requires enabling performance monitoring. @@ -125,22 +98,6 @@ public bool EnableAutoPerformanceTracking /// public bool EnableCoreDataTracing { get; set; } = true; - /// - /// When enabled, the SDK tracks the performance of Core Data operations. - /// It requires enabling performance monitoring. - /// The default value is true (enabled). - /// - /// - /// Performance Monitoring must be enabled for this option to take effect. - /// See https://docs.sentry.io/platforms/apple/performance/instrumentation/automatic-instrumentation/#core-data-instrumentation - /// - [Obsolete("Use EnableCoreDataTracing instead. This property will be removed in a future version.")] - public bool EnableCoreDataTracking - { - get => EnableCoreDataTracing; - set => EnableCoreDataTracing = value; - } - /// /// When enabled, the SDK tracks performance for file IO reads and writes with /// if auto performance tracking and are enabled. @@ -151,21 +108,6 @@ public bool EnableCoreDataTracking /// public bool EnableFileIOTracing { get; set; } = true; - /// - /// When enabled, the SDK tracks performance for file IO reads and writes with - /// if auto performance tracking and are enabled. - /// The default value is true (enabled). - /// - /// - /// See https://docs.sentry.io/platforms/apple/performance/instrumentation/automatic-instrumentation/#file-io-instrumentation - /// - [Obsolete("Use EnableFileIOTracing instead. This property will be removed in a future version.")] - public bool EnableFileIOTracking - { - get => EnableFileIOTracing; - set => EnableFileIOTracing = value; - } - /// /// When enabled, the SDK adds breadcrumbs for each network request /// if auto performance tracking and are enabled. @@ -192,20 +134,6 @@ public bool EnableFileIOTracking /// public bool EnableWatchdogTerminationTracking { get; set; } = true; - /// - /// Whether to enable out of memory tracking or not. - /// The default value is true (enabled). - /// - /// - /// https://docs.sentry.io/platforms/apple/configuration/out-of-memory/ - /// - [Obsolete("Use EnableWatchdogTerminationTracking instead. This property will be removed in a future version.")] - public bool EnableOutOfMemoryTracking - { - get => EnableWatchdogTerminationTracking; - set => EnableWatchdogTerminationTracking = value; - } - /// /// Whether the SDK should use swizzling or not. /// The default value is true (enabled). @@ -228,20 +156,6 @@ public bool EnableOutOfMemoryTracking /// public bool EnableUIViewControllerTracing { get; set; } = true; - /// - /// When enabled, the SDK tracks performance for subclasses. - /// The default value is true (enabled). - /// - /// - /// See https://docs.sentry.io/platforms/apple/performance/instrumentation/automatic-instrumentation/#uiviewcontroller-instrumentation - /// - [Obsolete("Use EnableUIViewControllerTracing instead.")] - public bool EnableUIViewControllerTracking - { - get => EnableUIViewControllerTracing; - set => EnableUIViewControllerTracing = value; - } - /// /// When enabled, the SDK creates transactions for UI events like buttons clicks, switch toggles, /// and other UI elements that uses . @@ -252,28 +166,6 @@ public bool EnableUIViewControllerTracking /// public bool EnableUserInteractionTracing { get; set; } = false; - /// - /// This feature is no longer available. This option does nothing and will be removed in a future release. - /// - /// - /// This was removed from the Cocoa SDK in 8.6.0 with https://github.com/getsentry/sentry-cocoa/pull/2973 - /// - [Obsolete("This feature is no longer available. This option does nothing and will be removed in a future release.")] - public bool StitchAsyncCode { get; set; } = false; - - // /// - // /// This gets called shortly after the initialization of the SDK when the last program execution - // /// terminated with a crash. It is not guaranteed that this is called on the main thread. - // /// - // /// - // /// This callback is only executed once during the entire run of the program to avoid - // /// multiple callbacks if there are multiple crash events to send. This can happen when the program - // /// terminates with a crash before the SDK can send the crash event. - // /// You can use if you prefer a callback for every event. - // /// See also https://docs.sentry.io/platforms/apple/enriching-events/user-feedback/ - // /// - // public Action? OnCrashedLastRun { get; set; } = null; - /// /// When provided, this will be set as delegate on the used for network /// data-transfer tasks performed by the native Sentry Cocoa SDK. @@ -292,17 +184,6 @@ public bool EnableUIViewControllerTracking /// public bool EnableCocoaSdkTracing { get; set; } = false; - // /// - // /// Gets or sets a value that indicates if the callback will be invoked for - // /// events that originate from the embedded Cocoa SDK. The default value is false (disabled). - // /// - // /// - // /// This is an experimental feature and is imperfect, as the .NET SDK and the embedded Cocoa SDK don't - // /// implement all of the same features that may be present in the event graph. Some optional elements may - // /// be stripped away during the round-tripping between the two SDKs. Use with caution. - // /// - // public bool EnableCocoaSdkBeforeSend { get; set; } - internal List? InAppExcludes { get; private set; } internal List? InAppIncludes { get; private set; } diff --git a/src/Sentry/DebugImage.cs b/src/Sentry/Protocol/DebugImage.cs similarity index 95% rename from src/Sentry/DebugImage.cs rename to src/Sentry/Protocol/DebugImage.cs index 00c633aa23..6f6a41b9c3 100644 --- a/src/Sentry/DebugImage.cs +++ b/src/Sentry/Protocol/DebugImage.cs @@ -1,7 +1,7 @@ using Sentry.Extensibility; using Sentry.Internal.Extensions; -namespace Sentry; +namespace Sentry.Protocol; /// /// The Sentry Debug Meta Images interface. @@ -16,9 +16,8 @@ public sealed class DebugImage : IJsonSerializable /// /// Memory address, at which the image is mounted in the virtual address space of the process. - /// Should be a string in hex representation prefixed with "0x". /// - public string? ImageAddress { get; set; } + public long? ImageAddress { get; set; } /// /// The size of the image in virtual memory. @@ -60,7 +59,7 @@ public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) writer.WriteStartObject(); writer.WriteStringIfNotWhiteSpace("type", Type); - writer.WriteStringIfNotWhiteSpace("image_addr", ImageAddress); + writer.WriteStringIfNotWhiteSpace("image_addr", ImageAddress?.NullIfDefault()?.ToHexString()); writer.WriteNumberIfNotNull("image_size", ImageSize); writer.WriteStringIfNotWhiteSpace("debug_id", DebugId); writer.WriteStringIfNotWhiteSpace("debug_checksum", DebugChecksum); @@ -77,7 +76,7 @@ public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) public static DebugImage FromJson(JsonElement json) { var type = json.GetPropertyOrNull("type")?.GetString(); - var imageAddress = json.GetPropertyOrNull("image_addr")?.GetString(); + var imageAddress = json.GetPropertyOrNull("image_addr")?.GetHexAsLong(); var imageSize = json.GetPropertyOrNull("image_size")?.GetInt64(); var debugId = json.GetPropertyOrNull("debug_id")?.GetString(); var debugChecksum = json.GetPropertyOrNull("debug_checksum")?.GetString(); diff --git a/src/Sentry/DebugMeta.cs b/src/Sentry/Protocol/DebugMeta.cs similarity index 96% rename from src/Sentry/DebugMeta.cs rename to src/Sentry/Protocol/DebugMeta.cs index e140bbd69a..be18118b45 100644 --- a/src/Sentry/DebugMeta.cs +++ b/src/Sentry/Protocol/DebugMeta.cs @@ -1,7 +1,7 @@ using Sentry.Extensibility; using Sentry.Internal.Extensions; -namespace Sentry; +namespace Sentry.Protocol; /// /// The Sentry Debug Meta interface. diff --git a/src/Sentry/Protocol/Envelopes/Envelope.cs b/src/Sentry/Protocol/Envelopes/Envelope.cs index 76b3f02d0c..488f07ed93 100644 --- a/src/Sentry/Protocol/Envelopes/Envelope.cs +++ b/src/Sentry/Protocol/Envelopes/Envelope.cs @@ -269,7 +269,7 @@ public static Envelope FromEvent( } catch (Exception exception) { - logger?.LogError("Failed to add attachment: {0}.", exception, attachment.FileName); + logger?.LogError(exception, "Failed to add attachment: {0}.", attachment.FileName); } } } diff --git a/src/Sentry/Protocol/Envelopes/EnvelopeItem.cs b/src/Sentry/Protocol/Envelopes/EnvelopeItem.cs index 47e0884d09..022fb75dcc 100644 --- a/src/Sentry/Protocol/Envelopes/EnvelopeItem.cs +++ b/src/Sentry/Protocol/Envelopes/EnvelopeItem.cs @@ -150,7 +150,7 @@ public async Task SerializeAsync(Stream stream, IDiagnosticLogger? logger, // Write to the outbound stream asynchronously. It's likely either an HttpRequestStream or a FileStream. // Header - var headerWithLength = Header.ToDictionary(); + var headerWithLength = Header.ToDict(); headerWithLength[LengthKey] = payloadBuffer.Length; await SerializeHeaderAsync(stream, headerWithLength, logger, cancellationToken).ConfigureAwait(false); await stream.WriteNewlineAsync(cancellationToken).ConfigureAwait(false); @@ -170,7 +170,7 @@ public void Serialize(Stream stream, IDiagnosticLogger? logger) using var payloadBuffer = BufferPayload(logger); // Header - var headerWithLength = Header.ToDictionary(); + var headerWithLength = Header.ToDict(); headerWithLength[LengthKey] = payloadBuffer.Length; SerializeHeader(stream, headerWithLength, logger); stream.WriteNewline(); diff --git a/src/Sentry/Protocol/Mechanism.cs b/src/Sentry/Protocol/Mechanism.cs index 6eba1b608e..1d1e7d26ec 100644 --- a/src/Sentry/Protocol/Mechanism.cs +++ b/src/Sentry/Protocol/Mechanism.cs @@ -171,8 +171,8 @@ public static Mechanism FromJson(JsonElement json) IsExceptionGroup = isExceptionGroup, ExceptionId = exceptionId, ParentId = parentId, - InternalData = data?.WhereNotNullValue().ToDictionary(), - InternalMeta = meta?.WhereNotNullValue().ToDictionary() + InternalData = data?.WhereNotNullValue().ToDict(), + InternalMeta = meta?.WhereNotNullValue().ToDict() }; } diff --git a/src/Sentry/Protocol/Response.cs b/src/Sentry/Protocol/Response.cs index ef3b3807e6..f6976eac8c 100644 --- a/src/Sentry/Protocol/Response.cs +++ b/src/Sentry/Protocol/Response.cs @@ -144,7 +144,7 @@ public static Response FromJson(JsonElement json) BodySize = bodySize, Cookies = cookies, Data = data, - InternalHeaders = headers?.WhereNotNullValue().ToDictionary(), + InternalHeaders = headers?.WhereNotNullValue().ToDict(), StatusCode = statusCode }; } diff --git a/src/Sentry/Protocol/Runtime.cs b/src/Sentry/Protocol/Runtime.cs index 1ee2a3b4e4..572c3d9047 100644 --- a/src/Sentry/Protocol/Runtime.cs +++ b/src/Sentry/Protocol/Runtime.cs @@ -51,9 +51,7 @@ public sealed class Runtime : IJsonSerializable, ICloneable, IUpdatable /// /// Clones this instance /// - // NOTE: This appears to have been public by mistake - [Obsolete("This method will be made internal in a future version.")] - public Runtime Clone() => ((ICloneable)this).Clone(); + internal Runtime Clone() => ((ICloneable)this).Clone(); Runtime ICloneable.Clone() => new() diff --git a/src/Sentry/Protocol/SentryException.cs b/src/Sentry/Protocol/SentryException.cs index c22bde09f4..c04b95bf2f 100644 --- a/src/Sentry/Protocol/SentryException.cs +++ b/src/Sentry/Protocol/SentryException.cs @@ -43,16 +43,6 @@ public sealed class SentryException : IJsonSerializable /// public Mechanism? Mechanism { get; set; } - /// - /// Arbitrary extra data that is related to this error. - /// - /// - /// This property is obsolete and should no longer be used. - /// Anything added here will be ignored and not sent to Sentry. - /// - [Obsolete("Use SentryException.Mechanism.Data instead. This property will be removed in a future version.")] - public IDictionary Data { get; } = new Dictionary(StringComparer.Ordinal); - /// public void WriteTo(Utf8JsonWriter writer, IDiagnosticLogger? logger) { diff --git a/src/Sentry/Reflection/AssemblyExtensions.cs b/src/Sentry/Reflection/AssemblyExtensions.cs index a4f0a855fe..486edfba6f 100644 --- a/src/Sentry/Reflection/AssemblyExtensions.cs +++ b/src/Sentry/Reflection/AssemblyExtensions.cs @@ -4,8 +4,7 @@ namespace Sentry.Reflection; /// Extension methods to . /// [EditorBrowsable(EditorBrowsableState.Never)] -[Obsolete("Should not be public. This method will be removed in version 4.")] -public static class AssemblyExtensions +internal static class AssemblyExtensions { /// /// Get the assemblies Name and Version. @@ -30,7 +29,7 @@ public static SdkVersion GetNameAndVersion(this Assembly asm) try { var informationalVersion = assembly.GetCustomAttribute()?.InformationalVersion; - if (informationalVersion != null) + if (!string.IsNullOrEmpty(informationalVersion)) { return informationalVersion; } @@ -41,10 +40,6 @@ public static SdkVersion GetNameAndVersion(this Assembly asm) // therefore this method uses a try/catch to make sure this method always returns a value } - // Note: even though the informational version could be "invalid" (e.g. string.Empty), it should - // be used for versioning and the software should not fallback to the assembly version string. - // See https://github.com/getsentry/sentry-dotnet/pull/1079#issuecomment-866992216 - // TODO: Lets change this in a new major to return the Version as fallback return assembly.GetName().Version?.ToString(); } } diff --git a/src/Sentry/Request.cs b/src/Sentry/Request.cs index 7c78e81a83..5a9a6ea0a0 100644 --- a/src/Sentry/Request.cs +++ b/src/Sentry/Request.cs @@ -174,9 +174,9 @@ public static Request FromJson(JsonElement json) return new Request { - InternalEnv = env?.WhereNotNullValue().ToDictionary(), - InternalOther = other?.WhereNotNullValue().ToDictionary(), - InternalHeaders = headers?.WhereNotNullValue().ToDictionary(), + InternalEnv = env?.WhereNotNullValue().ToDict(), + InternalOther = other?.WhereNotNullValue().ToDict(), + InternalHeaders = headers?.WhereNotNullValue().ToDict(), Url = url, Method = method, Data = data, diff --git a/src/Sentry/Scope.cs b/src/Sentry/Scope.cs index f01977d7dd..8daffb13dd 100644 --- a/src/Sentry/Scope.cs +++ b/src/Sentry/Scope.cs @@ -13,7 +13,7 @@ namespace Sentry; /// Scope data is sent together with any event captured /// during the lifetime of the scope. /// -public class Scope : IEventLike, IHasDistribution +public class Scope : IEventLike { internal SentryOptions Options { get; } @@ -137,9 +137,6 @@ public User User } } - /// - public string? Platform { get; set; } - /// public string? Release { get; set; } @@ -182,12 +179,12 @@ public string? TransactionName } } - private ITransaction? _transaction; + private ITransactionTracer? _transaction; /// /// Transaction. /// - public ITransaction? Transaction + public ITransactionTracer? Transaction { get => _transaction; set => _transaction = value; @@ -345,7 +342,6 @@ public void Clear() Request = new(); Contexts.Clear(); User = new(); - Platform = default; Release = default; Distribution = default; Environment = default; @@ -435,9 +431,8 @@ public void Apply(IEventLike other) Request.CopyTo(other.Request); User.CopyTo(other.User); - other.Platform ??= Platform; other.Release ??= Release; - other.WithDistribution(_ => _.Distribution ??= Distribution); + other.Distribution ??= Distribution; other.Environment ??= Environment; other.TransactionName ??= TransactionName; other.Level ??= Level; @@ -532,7 +527,7 @@ internal void Evaluate() } catch (Exception ex) { - Options.DiagnosticLogger?.LogError("Failed invoking event handler.", ex); + Options.DiagnosticLogger?.LogError(ex, "Failed invoking event handler."); } finally { @@ -541,12 +536,6 @@ internal void Evaluate() } } - /// - /// Obsolete. Use the property instead. - /// - [Obsolete("Use the Span property instead. This method will be removed in a future release.")] - public ISpan? GetSpan() => Span; - private ISpan? _span; /// @@ -571,6 +560,6 @@ public ISpan? Span set => _span = value; } - internal void ResetTransaction(ITransaction? expectedCurrentTransaction) => + internal void ResetTransaction(ITransactionTracer? expectedCurrentTransaction) => Interlocked.CompareExchange(ref _transaction, null, expectedCurrentTransaction); } diff --git a/src/Sentry/Sentry.csproj b/src/Sentry/Sentry.csproj index bdfd79855c..44aeea1a2b 100644 --- a/src/Sentry/Sentry.csproj +++ b/src/Sentry/Sentry.csproj @@ -8,10 +8,10 @@ - net6.0;net5.0;netcoreapp3.0;netstandard2.1;netstandard2.0;net461 - $(TargetFrameworks);net6.0-android - $(TargetFrameworks);net6.0-ios - $(TargetFrameworks);net6.0-maccatalyst + net8.0;net6.0;netstandard2.1;netstandard2.0;net462 + $(TargetFrameworks);net7.0-android;net8.0-android + $(TargetFrameworks);net7.0-ios;net8.0-ios + $(TargetFrameworks);net7.0-maccatalyst;net8.0-maccatalyst @@ -21,6 +21,17 @@ + + + + true + + + + + + - + @@ -69,9 +80,9 @@ - - - + + + - true + + true @@ -120,53 +125,110 @@ - - + + + true + $(PublishDir) + + + _CopyAotSymbols + + + + + + + + + + false + $(OutputPath) + Build + + + + + + + + - + + + + + + - - - - + - - - - - - - - - - - - - - <_SentryDebugInfoFile>@(IntermediateAssembly->'$(IntermediateOutputPath)%(FileName).pdb') - <_SentryDebugInfoFile Condition="!Exists('$(_SentryDebugInfoFile)')">@(IntermediateAssembly->'$(IntermediateOutputPath)%(FileName)%(Extension)') - <_SentrySourceBundle>@(IntermediateAssembly->'$(IntermediateOutputPath)%(FileName).src.zip') + $(SentryCLIUploadDirectory) + $(SentryCLIUploadItems) @(AndroidNativeSymbolFilesExceptDll -> '%(Identity)', ' ') - - - - - - - + + + + + + + + + + + + + $(NativeBinary)$(NativeSymbolExt) + @(IntermediateAssembly->'$(SentryCLIUploadDirectory)%(FileName).pdb') + @(IntermediateAssembly->'$(SentryCLIUploadDirectory)%(FileName)%(Extension)') + $([System.IO.Path]::GetDirectoryName('$(SentryCLIDebugInfoFile)')) + + + + + + + + + + + - + @@ -174,6 +236,7 @@ - + + diff --git a/test/AndroidTestApp/AndroidTestApp.csproj b/test/AndroidTestApp/AndroidTestApp.csproj index 1ff3c71975..ad0a41eb1d 100644 --- a/test/AndroidTestApp/AndroidTestApp.csproj +++ b/test/AndroidTestApp/AndroidTestApp.csproj @@ -1,6 +1,6 @@ - net7.0-android + net8.0-android 21 Exe enable diff --git a/test/CommonModuleInit.cs b/test/CommonModuleInit.cs index d661db0f0d..03c33d63c8 100644 --- a/test/CommonModuleInit.cs +++ b/test/CommonModuleInit.cs @@ -2,7 +2,10 @@ public static class CommonModuleInit { [ModuleInitializer] - public static void Init() => + [SuppressMessage("Usage", "CA2255:The \'ModuleInitializer\' attribute should not be used in libraries")] + public static void Init() + { VerifyDiffPlex.Initialize(); + } } #endif diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 0b3d74d32c..34902f4399 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -7,11 +7,8 @@ true false true - - - - - false + + $(NoWarn);SYSLIB0005;SYSLIB0012 + true + + diff --git a/test/MauiTestUtils/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj b/test/MauiTestUtils/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj index 4397e5a5e3..23107138dc 100644 --- a/test/MauiTestUtils/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj +++ b/test/MauiTestUtils/DeviceTests.Runners/TestUtils.DeviceTests.Runners.csproj @@ -6,6 +6,7 @@ $(TargetFrameworks);net7.0-windows10.0.19041.0 $(TargetFrameworks);net7.0-ios $(TargetFrameworks);net7.0-maccatalyst + true Microsoft.Maui.TestUtils.DeviceTests.Runners Microsoft.Maui.TestUtils.DeviceTests.Runners diff --git a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.Core3_1.verified.txt deleted file mode 100644 index bd28d88ca7..0000000000 --- a/test/Sentry.Android.AssemblyReader.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ /dev/null @@ -1,12 +0,0 @@ -namespace Sentry.Android.AssemblyReader -{ - public static class AndroidAssemblyReaderFactory - { - public static Sentry.Android.AssemblyReader.IAndroidAssemblyReader Open(string apkPath, System.Collections.Generic.IList supportedAbis, Sentry.Android.AssemblyReader.DebugLogger? logger = null) { } - } - public delegate void DebugLogger(string message, params object?[] args); - public interface IAndroidAssemblyReader : System.IDisposable - { - System.Reflection.PortableExecutable.PEReader? TryReadAssembly(string name); - } -} diff --git a/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj b/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj index 22e3caaa12..c3ca8f5c0b 100644 --- a/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj +++ b/test/Sentry.Android.AssemblyReader.Tests/Sentry.Android.AssemblyReader.Tests.csproj @@ -1,7 +1,7 @@ - net7.0;net6.0;netcoreapp3.1 + net7.0;net6.0 $(TargetFrameworks);net7.0-android enable @@ -13,7 +13,7 @@ - + diff --git a/test/Sentry.AspNet.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.AspNet.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index 7980235cdf..89bfce1155 100644 --- a/test/Sentry.AspNet.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.AspNet.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -4,7 +4,7 @@ { public static void FinishSentryTransaction(this System.Web.HttpContext httpContext) { } public static void StartOrContinueTrace(this System.Web.HttpContext httpContext) { } - public static Sentry.ITransaction StartSentryTransaction(this System.Web.HttpContext httpContext) { } + public static Sentry.ITransactionTracer StartSentryTransaction(this System.Web.HttpContext httpContext) { } } public static class SentryAspNetOptionsExtensions { diff --git a/test/Sentry.AspNet.Tests/HttpContextExtensionsTests.cs b/test/Sentry.AspNet.Tests/HttpContextExtensionsTests.cs index ef87155717..17b1bc0ddf 100644 --- a/test/Sentry.AspNet.Tests/HttpContextExtensionsTests.cs +++ b/test/Sentry.AspNet.Tests/HttpContextExtensionsTests.cs @@ -16,7 +16,7 @@ public void StartSentryTransaction_CreatesValidTransaction() // Assert transaction.Name.Should().Be("GET /the/path"); transaction.Operation.Should().Be("http.server"); - ((IHasTransactionNameSource)transaction).NameSource.Should().Be(TransactionNameSource.Url); + transaction.NameSource.Should().Be(TransactionNameSource.Url); } [Fact] diff --git a/test/Sentry.AspNet.Tests/Sentry.AspNet.Tests.csproj b/test/Sentry.AspNet.Tests/Sentry.AspNet.Tests.csproj index b4a984dfbd..33055817eb 100644 --- a/test/Sentry.AspNet.Tests/Sentry.AspNet.Tests.csproj +++ b/test/Sentry.AspNet.Tests/Sentry.AspNet.Tests.csproj @@ -1,7 +1,7 @@ - net48 + net48 diff --git a/test/Sentry.AspNetCore.Grpc.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.AspNetCore.Grpc.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 98% rename from test/Sentry.AspNetCore.Grpc.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.AspNetCore.Grpc.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index a1a242794b..60439aee0e 100644 --- a/test/Sentry.AspNetCore.Grpc.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.AspNetCore.Grpc.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -1,4 +1,4 @@ -namespace Sentry.AspNetCore.Grpc +namespace Sentry.AspNetCore.Grpc { public class DefaultProtobufRequestPayloadExtractor : Sentry.AspNetCore.Grpc.IProtobufRequestPayloadExtractor { diff --git a/test/Sentry.AspNetCore.Grpc.Tests/Sentry.AspNetCore.Grpc.Tests.csproj b/test/Sentry.AspNetCore.Grpc.Tests/Sentry.AspNetCore.Grpc.Tests.csproj index 0f504d1a6f..5d1ba3482c 100644 --- a/test/Sentry.AspNetCore.Grpc.Tests/Sentry.AspNetCore.Grpc.Tests.csproj +++ b/test/Sentry.AspNetCore.Grpc.Tests/Sentry.AspNetCore.Grpc.Tests.csproj @@ -1,7 +1,7 @@ - net7.0;net6.0;netcoreapp3.1 + net8.0;net7.0;net6.0 diff --git a/test/Sentry.AspNetCore.TestUtils/AspNetSentrySdkTestFixture.cs b/test/Sentry.AspNetCore.TestUtils/AspNetSentrySdkTestFixture.cs index a005772473..07321035a3 100644 --- a/test/Sentry.AspNetCore.TestUtils/AspNetSentrySdkTestFixture.cs +++ b/test/Sentry.AspNetCore.TestUtils/AspNetSentrySdkTestFixture.cs @@ -1,3 +1,4 @@ +#if NET6_0_OR_GREATER using Microsoft.AspNetCore.Hosting; namespace Sentry.AspNetCore.TestUtils; @@ -24,3 +25,4 @@ protected override void ConfigureBuilder(WebHostBuilder builder) AfterConfigureBuilder?.Invoke(builder); } } +#endif diff --git a/test/Sentry.AspNetCore.TestUtils/Sentry.AspNetCore.TestUtils.csproj b/test/Sentry.AspNetCore.TestUtils/Sentry.AspNetCore.TestUtils.csproj index 4bf16a8d4e..38685ecdc0 100644 --- a/test/Sentry.AspNetCore.TestUtils/Sentry.AspNetCore.TestUtils.csproj +++ b/test/Sentry.AspNetCore.TestUtils/Sentry.AspNetCore.TestUtils.csproj @@ -1,30 +1,32 @@ - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 false - + + + + + ASP.NET Core on .NET Framework is supported by Microsoft indefinitely on version 2.1 only. + Indeed, version 2.1 has newer nuget packages than version 2.2 (which is out of support). + Thus, we will test on 2.1.*, not 2.*. + See https://dotnet.microsoft.com/platform/support/policy/aspnet + And https://github.com/dotnet/aspnetcore/issues/3753#issuecomment-438046364 + Also, JetBrains Rider (via Checkmarx) may report the following security vulnerabilities: + CVE-2019-0815 + CVE-2020-1045 + CVE-2020-1597 + These are safe to ignore for our tests. A real project would resolve them by installing + an updated version of the ASP.NET Core runtime on their hosting server. + See https://github.com/dotnet/aspnetcore/issues/15423 +--> @@ -34,22 +36,25 @@ - - - - - + - - + + + + + + + + + diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt index bc47fa31bd..7c93a78bf7 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -32,13 +32,6 @@ namespace Sentry.AspNetCore { Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } } - [System.Obsolete("This interface is tightly coupled to AspNetCore and will be removed in version 4." + - "0.0. Please consider using ISentryUserFactory with IHttpContextAccessor instead." + - "")] - public interface IUserFactory - { - Sentry.User? Create(Microsoft.AspNetCore.Http.HttpContext context); - } public static class SamplingExtensions { public static Microsoft.AspNetCore.Http.HttpContext? TryGetHttpContext(this Sentry.TransactionSamplingContext samplingContext) { } @@ -66,12 +59,10 @@ namespace Sentry.AspNetCore public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; } public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; } } - public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions + public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions { public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - [System.Obsolete("Use constructor with no IHostingEnvironment")] - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration, Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment) { } - public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } + public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } } public static class SentryBuilderExtensions { diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt index bc47fa31bd..7c93a78bf7 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt @@ -32,13 +32,6 @@ namespace Sentry.AspNetCore { Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } } - [System.Obsolete("This interface is tightly coupled to AspNetCore and will be removed in version 4." + - "0.0. Please consider using ISentryUserFactory with IHttpContextAccessor instead." + - "")] - public interface IUserFactory - { - Sentry.User? Create(Microsoft.AspNetCore.Http.HttpContext context); - } public static class SamplingExtensions { public static Microsoft.AspNetCore.Http.HttpContext? TryGetHttpContext(this Sentry.TransactionSamplingContext samplingContext) { } @@ -66,12 +59,10 @@ namespace Sentry.AspNetCore public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; } public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; } } - public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions + public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions { public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - [System.Obsolete("Use constructor with no IHostingEnvironment")] - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration, Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment) { } - public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } + public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } } public static class SentryBuilderExtensions { diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 86% rename from test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index bc47fa31bd..7c93a78bf7 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -32,13 +32,6 @@ namespace Sentry.AspNetCore { Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } } - [System.Obsolete("This interface is tightly coupled to AspNetCore and will be removed in version 4." + - "0.0. Please consider using ISentryUserFactory with IHttpContextAccessor instead." + - "")] - public interface IUserFactory - { - Sentry.User? Create(Microsoft.AspNetCore.Http.HttpContext context); - } public static class SamplingExtensions { public static Microsoft.AspNetCore.Http.HttpContext? TryGetHttpContext(this Sentry.TransactionSamplingContext samplingContext) { } @@ -66,12 +59,10 @@ namespace Sentry.AspNetCore public Sentry.Extensibility.RequestSize MaxRequestBodySize { get; set; } public Sentry.AspNetCore.TransactionNameProvider? TransactionNameProvider { get; set; } } - public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions + public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.IConfigureOptions { public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - [System.Obsolete("Use constructor with no IHostingEnvironment")] - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration, Microsoft.AspNetCore.Hosting.IWebHostEnvironment hostingEnvironment) { } - public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } + public void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } } public static class SentryBuilderExtensions { diff --git a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index 97c9e6d5db..92074d97ed 100644 --- a/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.AspNetCore.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -32,13 +32,6 @@ namespace Sentry.AspNetCore { Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; } } - [System.Obsolete("This interface is tightly coupled to AspNetCore and will be removed in version 4." + - "0.0. Please consider using ISentryUserFactory with IHttpContextAccessor instead." + - "")] - public interface IUserFactory - { - Sentry.User? Create(Microsoft.AspNetCore.Http.HttpContext context); - } public static class SamplingExtensions { public static Microsoft.AspNetCore.Http.HttpContext? TryGetHttpContext(this Sentry.TransactionSamplingContext samplingContext) { } @@ -69,8 +62,6 @@ namespace Sentry.AspNetCore public class SentryAspNetCoreOptionsSetup : Microsoft.Extensions.Options.ConfigureFromConfigurationOptions { public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration) { } - [System.Obsolete("Use constructor with no IHostingEnvironment")] - public SentryAspNetCoreOptionsSetup(Microsoft.Extensions.Logging.Configuration.ILoggerProviderConfiguration providerConfiguration, Microsoft.AspNetCore.Hosting.IHostingEnvironment hostingEnvironment) { } public override void Configure(Sentry.AspNetCore.SentryAspNetCoreOptions options) { } } public static class SentryBuilderExtensions diff --git a/test/Sentry.AspNetCore.Tests/AspNetCoreSentryWebHostBuilder.IntegrationTests.cs b/test/Sentry.AspNetCore.Tests/AspNetCoreSentryWebHostBuilder.IntegrationTests.cs index 676693ca1f..9823b9ad7a 100644 --- a/test/Sentry.AspNetCore.Tests/AspNetCoreSentryWebHostBuilder.IntegrationTests.cs +++ b/test/Sentry.AspNetCore.Tests/AspNetCoreSentryWebHostBuilder.IntegrationTests.cs @@ -27,11 +27,9 @@ public void UseSentry_ValidDsnString_EnablesSdk() } [Fact] - public void UseSentry_NoDsnProvided_DisabledSdk() + public void UseSentry_NoDsnProvided_ThrowsException() { - _ = _webHostBuilder.UseSentry().Build(); - - Assert.False(SentrySdk.IsEnabled); + Assert.Throws(() => _webHostBuilder.UseSentry().Build()); } [Fact] diff --git a/test/Sentry.AspNetCore.Tests/BindableSentryAspNetCoreOptionsTests.cs b/test/Sentry.AspNetCore.Tests/BindableSentryAspNetCoreOptionsTests.cs new file mode 100644 index 0000000000..0df315c7b2 --- /dev/null +++ b/test/Sentry.AspNetCore.Tests/BindableSentryAspNetCoreOptionsTests.cs @@ -0,0 +1,30 @@ +#if !NETFRAMEWORK +using Microsoft.Extensions.Configuration; + +namespace Sentry.AspNetCore.Tests; + +public class BindableSentryAspNetCoreOptionsTests: BindableTests +{ + [Fact] + public void BindableProperties_MatchOptionsProperties() + { + var actual = GetPropertyNames(); + AssertContainsAllOptionsProperties(actual); + } + + [Fact] + public void ApplyTo_SetsOptionsFromConfig() + { + // Arrange + var actual = new SentryAspNetCoreOptions(); + var bindable = new BindableSentryAspNetCoreOptions(); + + // Act + Fixture.Config.Bind(bindable); + bindable.ApplyTo(actual); + + // Assert + AssertContainsExpectedPropertyValues(actual); + } +} +#endif diff --git a/test/Sentry.AspNetCore.Tests/MiddlewareLoggerIntegration.cs b/test/Sentry.AspNetCore.Tests/MiddlewareLoggerIntegration.cs index 17094275f2..b1ee841e41 100644 --- a/test/Sentry.AspNetCore.Tests/MiddlewareLoggerIntegration.cs +++ b/test/Sentry.AspNetCore.Tests/MiddlewareLoggerIntegration.cs @@ -41,7 +41,7 @@ public Fixture() }; loggingOptions.InitializeSdk = false; - Client.When(client => client.CaptureEvent(Arg.Any(), Arg.Any(), Arg.Any())) + Client.When(client => client.CaptureEvent(Arg.Any(), Arg.Any(), Arg.Any())) .Do(callback => callback.Arg().Evaluate()); var hub = new Hub(new SentryOptions { Dsn = ValidDsn }); @@ -83,8 +83,7 @@ public async Task InvokeAsync_LoggerMessage_AsBreadcrumb() _ = _fixture.Client.Received(1).CaptureEvent( Arg.Any(), - Arg.Any(), - Arg.Is(e => e.Breadcrumbs.Any(b => b.Message == expectedCrumb))); + Arg.Is(e => e.Breadcrumbs.Any(b => b.Message == expectedCrumb)), Arg.Any()); } [Fact] @@ -105,8 +104,7 @@ public async Task InvokeAsync_LoggerPushesScope_LoggerMessage_AsBreadcrumb() _ = _fixture.Client.Received(1).CaptureEvent( Arg.Any(), - Arg.Any(), - Arg.Is(e => e.Breadcrumbs.Any(b => b.Message == expectedCrumb))); + Arg.Is(e => e.Breadcrumbs.Any(b => b.Message == expectedCrumb)), Arg.Any()); } [Fact] @@ -121,8 +119,7 @@ public async Task InvokeAsync_OptionsConfigureScope_AffectsAllRequests() _ = _fixture.Client.Received(1).CaptureEvent( Arg.Any(), - Arg.Any(), - Arg.Is(e => e.Level == expected)); + Arg.Is(e => e.Level == expected), Arg.Any()); } public void Dispose() => _fixture.Dispose(); diff --git a/test/Sentry.AspNetCore.Tests/RouteUtilsTests.cs b/test/Sentry.AspNetCore.Tests/RouteUtilsTests.cs index 0d64c8df64..03fa6ca2ad 100644 --- a/test/Sentry.AspNetCore.Tests/RouteUtilsTests.cs +++ b/test/Sentry.AspNetCore.Tests/RouteUtilsTests.cs @@ -28,13 +28,13 @@ private static void AddRouteValuesIfNotNull(RouteValueDictionary route, string k } [Theory] - [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "myPath/theArea/house/about/{id?}", "house", "about", "theArea")] - [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "myPath/{area=MyArea}/house/about/{id?}", "house", "about", null)] - [InlineData("{area=}/{controller=}/{action=}/{id?}", "myPath/{area=}/{controller=}/{action=}/{id?}", "house", "about", "theArea")] - [InlineData("{controller=Home}/{action=Index}/{id?}", "myPath/house/about/{id?}", "house", "about", null)] - [InlineData("{controller=Home}/{action=Index}", "myPath/house/about", "house", "about", null)] - [InlineData("{controller=Home}/{id?}", "myPath/house/{id?}", "house", "about", null)] - [InlineData("{action=Index}/{id?}", "myPath/about/{id?}", null, "about", null)] + [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "/myPath/theArea/house/about/{id?}", "house", "about", "theArea")] + [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "/myPath/{area=MyArea}/house/about/{id?}", "house", "about", null)] + [InlineData("{area=}/{controller=}/{action=}/{id?}", "/myPath/{area=}/{controller=}/{action=}/{id?}", "house", "about", "theArea")] + [InlineData("{controller=Home}/{action=Index}/{id?}", "/myPath/house/about/{id?}", "house", "about", null)] + [InlineData("{controller=Home}/{action=Index}", "/myPath/house/about", "house", "about", null)] + [InlineData("{controller=Home}/{id?}", "/myPath/house/{id?}", "house", "about", null)] + [InlineData("{action=Index}/{id?}", "/myPath/about/{id?}", null, "about", null)] public void NewRouteFormat_MvcRouteWithPathBase_ParsedParameters(string routeInput, string expectedOutput, string controller, string action, string area) { // Arrange @@ -48,14 +48,14 @@ public void NewRouteFormat_MvcRouteWithPathBase_ParsedParameters(string routeInp } [Theory] - [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "theArea/house/about/{id?}", "house", "about", "theArea", null)] - [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "{area=MyArea}/house/about/{id?}", "house", "about", null, null)] - [InlineData("{area=}/{controller=}/{action=}/{id?}", "{area=}/{controller=}/{action=}/{id?}", "house", "about", "theArea", null)] - [InlineData("{controller=Home}/{action=Index}/{id?}", "house/about/{id?}", "house", "about", null, null)] - [InlineData("{controller=Home}/{action=Index}", "house/about", "house", "about", null, null)] - [InlineData("{controller=Home}/{id?}", "house/{id?}", "house", "about", null, null)] - [InlineData("{action=Index}/{id?}", "about/{id?}", null, "about", null, null)] - [InlineData("v{version:apiVersion}/Target", "v1.1/Target", null, "about", null, "1.1")] + [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "/theArea/house/about/{id?}", "house", "about", "theArea", null)] + [InlineData("{area=MyArea}/{controller=Home}/{action=Index}/{id?}", "/{area=MyArea}/house/about/{id?}", "house", "about", null, null)] + [InlineData("{area=}/{controller=}/{action=}/{id?}", "/{area=}/{controller=}/{action=}/{id?}", "house", "about", "theArea", null)] + [InlineData("{controller=Home}/{action=Index}/{id?}", "/house/about/{id?}", "house", "about", null, null)] + [InlineData("{controller=Home}/{action=Index}", "/house/about", "house", "about", null, null)] + [InlineData("{controller=Home}/{id?}", "/house/{id?}", "house", "about", null, null)] + [InlineData("{action=Index}/{id?}", "/about/{id?}", null, "about", null, null)] + [InlineData("v{version:apiVersion}/Target", "/v1.1/Target", null, "about", null, "1.1")] public void NewRouteFormat_MvcRouteWithoutPathBase_ParsedParameters(string routeInput, string expectedOutput, string controller, string action, string area, string version) { // Arrange @@ -69,9 +69,9 @@ public void NewRouteFormat_MvcRouteWithoutPathBase_ParsedParameters(string route } [Theory] - [InlineData("myPath/some/Path", "/myPath", "some/Path")] - [InlineData("some/Path", null, "some/Path")] - [InlineData("api/health", "/api", "/health")] + [InlineData("/myPath/some/Path", "/myPath", "some/Path")] + [InlineData("/some/Path", null, "some/Path")] + [InlineData("/api/health", "/api", "/health")] [InlineData(null, null, "")] [InlineData(null, null, null)] public void NewRouteFormat_WithPathBase_MatchesExpectedRoute(string expectedRoute, string pathBase, string rawRoute) diff --git a/test/Sentry.AspNetCore.Tests/ScopeExtensionsTests.cs b/test/Sentry.AspNetCore.Tests/ScopeExtensionsTests.cs index 56b2b5dd8d..0de8281312 100644 --- a/test/Sentry.AspNetCore.Tests/ScopeExtensionsTests.cs +++ b/test/Sentry.AspNetCore.Tests/ScopeExtensionsTests.cs @@ -42,7 +42,7 @@ public Fixture GetSut(bool addTransaction = true) { if (addTransaction) { - Scope.Transaction = Substitute.For(); + Scope.Transaction = Substitute.For(); } var routeFeature = new RoutingFeature @@ -67,7 +67,7 @@ public Fixture GetSutWithEmptyRoute(bool addTransaction = true) { if (addTransaction) { - Scope.Transaction = Substitute.For(); + Scope.Transaction = Substitute.For(); } var routeFeature = new RoutingFeature { diff --git a/test/Sentry.AspNetCore.Tests/Sentry.AspNetCore.Tests.csproj b/test/Sentry.AspNetCore.Tests/Sentry.AspNetCore.Tests.csproj index 528d6fb00d..ee66f9fe0e 100644 --- a/test/Sentry.AspNetCore.Tests/Sentry.AspNetCore.Tests.csproj +++ b/test/Sentry.AspNetCore.Tests/Sentry.AspNetCore.Tests.csproj @@ -1,7 +1,7 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0 diff --git a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs index 49524f6b9a..8cf76716ab 100644 --- a/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs +++ b/test/Sentry.AspNetCore.Tests/SentryAspNetCoreOptionsSetupTests.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Configuration; @@ -11,29 +12,60 @@ namespace Sentry.AspNetCore.Tests; public class SentryAspNetCoreOptionsSetupTests { - private readonly SentryAspNetCoreOptionsSetup _sut = new( - Substitute.For>()); + class Fixture + { + public Dictionary Configuration { get; set; } = new(); + + public SentryAspNetCoreOptionsSetup GetSut() + { + var config = new ConfigurationBuilder() + .AddInMemoryCollection(Configuration) + .Build(); + var loggingConfig = Substitute.For>(); + loggingConfig.Configuration.Returns(config); + return new(loggingConfig); + } + } + private readonly Fixture _fixture = new(); private readonly SentryAspNetCoreOptions _target = new(); [Fact] public void Filters_KestrelApplicationEvent_NoException_Filtered() { - _sut.Configure(_target); + // Arrange + var sut = _fixture.GetSut(); + + // Act + sut.Configure(_target); + + //Assert Assert.Contains(_target.Filters, f => f.Filter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Critical, 13, null)); } [Fact] public void Filters_KestrelApplicationEvent_WithException_Filtered() { - _sut.Configure(_target); + // Arrange + var sut = _fixture.GetSut(); + + // Act + sut.Configure(_target); + + // Assert Assert.Contains(_target.Filters, f => f.Filter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Critical, 13, new Exception())); } [Fact] public void Filters_KestrelEventId1_WithException_NotFiltered() { - _sut.Configure(_target); + // Arrange + var sut = _fixture.GetSut(); + + // Act + sut.Configure(_target); + + // Assert Assert.DoesNotContain(_target.Filters, f => f.Filter("Microsoft.AspNetCore.Server.Kestrel", LogLevel.Trace, 1, null)); } diff --git a/test/Sentry.AspNetCore.Tests/SentryTracingBuilderTests.cs b/test/Sentry.AspNetCore.Tests/SentryTracingBuilderTests.cs index 4b274ba8ef..ec37786118 100644 --- a/test/Sentry.AspNetCore.Tests/SentryTracingBuilderTests.cs +++ b/test/Sentry.AspNetCore.Tests/SentryTracingBuilderTests.cs @@ -45,7 +45,11 @@ public void UseRouting_AutoRegisterTracingDisabled_SentryTracingNotRegistered() // Arrange _fixture.ConfigureServices = services => services.AddRouting(); _fixture.Configure = applicationBuilder => applicationBuilder.UseRouting(); - _fixture.ConfigureOptions = options => options.AutoRegisterTracing = false; + _fixture.ConfigureOptions = options => + { + options.Dsn = Sentry.Constants.DisableSdkDsnValue; + options.AutoRegisterTracing = false; + }; // Act - implicit var (_, builder) = _fixture.GetSut(); @@ -60,7 +64,11 @@ public void UseRouting_OtelInstrumentation_SentryTracingNotRegistered() // Arrange _fixture.ConfigureServices = services => services.AddRouting(); _fixture.Configure = applicationBuilder => applicationBuilder.UseRouting(); - _fixture.ConfigureOptions = options => options.Instrumenter = Instrumenter.OpenTelemetry; + _fixture.ConfigureOptions = options => + { + options.Dsn = Sentry.Constants.DisableSdkDsnValue; + options.Instrumenter = Instrumenter.OpenTelemetry; + }; // Act - implicit var (_, builder) = _fixture.GetSut(); @@ -82,6 +90,10 @@ public void UseRouting_SentryTracingRegisteredWithoutWarning() services.AddRouting(); }; _fixture.Configure = applicationBuilder => applicationBuilder.UseRouting(); + _fixture.ConfigureOptions = options => + { + options.Dsn = Sentry.Constants.DisableSdkDsnValue; + }; // Act var (_, builder) = _fixture.GetSut(); @@ -107,6 +119,10 @@ public void UseSentryTracing_AutoRegisterTracing_Warning() applicationBuilder.UseRouting(); applicationBuilder.UseSentryTracing(); }; + _fixture.ConfigureOptions = options => + { + options.Dsn = Sentry.Constants.DisableSdkDsnValue; + }; // Act var _ = _fixture.GetSut(); diff --git a/test/Sentry.AspNetCore.Tests/SentryTracingMiddlewareTests.cs b/test/Sentry.AspNetCore.Tests/SentryTracingMiddlewareTests.cs index cfff3f5b0f..1151a6bd03 100644 --- a/test/Sentry.AspNetCore.Tests/SentryTracingMiddlewareTests.cs +++ b/test/Sentry.AspNetCore.Tests/SentryTracingMiddlewareTests.cs @@ -56,6 +56,7 @@ public async Task Transactions_are_grouped_by_route() Arg.Is(transaction => transaction.Name == "GET /person/{id}" && transaction.NameSource == TransactionNameSource.Route), + Arg.Any(), Arg.Any() ); } @@ -102,7 +103,7 @@ public async Task Transaction_is_bound_on_the_scope_automatically() // Assert transaction.Should().NotBeNull(); transaction.Name.Should().Be("GET /person/{id}"); - ((IHasTransactionNameSource)transaction).NameSource.Should().Be(TransactionNameSource.Route); + transaction.NameSource.Should().Be(TransactionNameSource.Route); } [Fact] @@ -151,10 +152,54 @@ public async Task Transaction_is_started_automatically_from_incoming_trace_heade t.ParentSpanId == SpanId.Parse("1000000000000000") && t.IsSampled == false ), + Arg.Any(), Arg.Any() ); } + [Fact] + public async Task Transaction_name_includes_slash_prefix() + { + // Arrange + var sentryClient = Substitute.For(); + + var hub = new Hub(new SentryOptions { Dsn = ValidDsn, TracesSampleRate = 1 }, sentryClient); + + var server = new TestServer(new WebHostBuilder() + .UseDefaultServiceProvider(di => di.EnableValidation()) + .UseSentry() + .ConfigureServices(services => + { + services.AddRouting(); + + services.RemoveAll(typeof(Func)); + services.AddSingleton>(() => hub); + }) + .Configure(app => + { + app.UseRouting(); + + app.UseEndpoints(routes => routes.Map("foo", _ => Task.CompletedTask)); + })); + + var client = server.CreateClient(); + Transaction transaction = null; + sentryClient.CaptureTransaction( + Arg.Do(t => transaction = t), + Arg.Any(), + Arg.Any() + ); + + // Act + using var request = new HttpRequestMessage(HttpMethod.Get, "foo"); + + await client.SendAsync(request); + + // Assert + transaction.Should().NotBeNull(); + transaction.Name.Should().Be("GET /foo"); + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -395,9 +440,7 @@ public async Task Transaction_is_automatically_populated_with_request_data() // Arrange ITransactionData transaction = null; - var sentryClient = Substitute.For(); - - var hub = new Hub(new SentryOptions { Dsn = ValidDsn, TracesSampleRate = 1 }, sentryClient); + var hub = new Hub(new SentryOptions { Dsn = ValidDsn, TracesSampleRate = 1 }); var server = new TestServer(new WebHostBuilder() .UseDefaultServiceProvider(di => di.EnableValidation()) @@ -556,7 +599,7 @@ public async Task Transaction_TransactionNameProviderSetSet_TransactionNameSet() var expectedName = "My custom name"; var sentryClient = Substitute.For(); - sentryClient.When(x => x.CaptureTransaction(Arg.Any(), Arg.Any())) + sentryClient.When(x => x.CaptureTransaction(Arg.Any(), Arg.Any(), Arg.Any())) .Do(callback => transaction = callback.Arg()); var options = new SentryAspNetCoreOptions { @@ -598,7 +641,7 @@ public async Task Transaction_TransactionNameProviderSetUnset_TransactionNameSet Transaction transaction = null; var sentryClient = Substitute.For(); - sentryClient.When(x => x.CaptureTransaction(Arg.Any(), Arg.Any())) + sentryClient.When(x => x.CaptureTransaction(Arg.Any(), Arg.Any(), Arg.Any())) .Do(callback => transaction = callback.Arg()); var options = new SentryAspNetCoreOptions { diff --git a/test/Sentry.AspNetCore.Tests/ServiceCollectionExtensionsTests.cs b/test/Sentry.AspNetCore.Tests/ServiceCollectionExtensionsTests.cs index 255275ef70..2d17cba97d 100644 --- a/test/Sentry.AspNetCore.Tests/ServiceCollectionExtensionsTests.cs +++ b/test/Sentry.AspNetCore.Tests/ServiceCollectionExtensionsTests.cs @@ -68,13 +68,11 @@ public void AddSentry_DefaultRequestPayloadExtractor_LastRegistration() Assert.Same(typeof(DefaultRequestPayloadExtractor), last.ImplementationType); } -#pragma warning disable CS0618 [Fact] public void AddSentry_DefaultUserFactory_Registered() { _ = _sut.AddSentry(); - _sut.Received().Add(Arg.Is(d => d.ServiceType == typeof(IUserFactory) + _sut.Received().Add(Arg.Is(d => d.ServiceType == typeof(ISentryUserFactory) && d.ImplementationType == typeof(DefaultUserFactory))); } -#pragma warning restore CS0618 } diff --git a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet.DotNet8_0.verified.txt b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet.DotNet8_0.verified.txt new file mode 100644 index 0000000000..9abeb1309b --- /dev/null +++ b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet.DotNet8_0.verified.txt @@ -0,0 +1,87 @@ +{ + result: Hello world, + Payloads: [ + { + Source: { + Name: GET v1.1/Target, + NameSource: Route, + Platform: csharp, + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true, + SampleRate: 1.0, + Request: { + Method: GET, + QueryString: + }, + Contexts: { + trace: { + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true + } + }, + User: {}, + Environment: production, + Breadcrumbs: [ + { + Message: Request starting HTTP/1.1 GET http://localhost/v1.1/Target - - -, + Data: { + eventId: 1 + }, + Category: Microsoft.AspNetCore.Hosting.Diagnostics + }, + { + Message: Executing endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutingEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + }, + { + Message: Route matched with {action = "Method", controller = "Version"}. Executing controller action with signature System.String Method() on controller Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController (Sentry.AspNetCore.Tests)., + Data: { + eventId: ControllerActionExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executing ObjectResult, writing value of type 'System.String'., + Data: { + eventId: ObjectResultExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor + }, + { + Message: Executed action Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method, + Data: { + eventId: ActionExecuted + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executed endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutedEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + } + ], + Extra: { + http.request.method: GET, + http.response.status_code: 200 + }, + Tags: { + ActionId: Guid_1, + ActionName: Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests), + route.action: Method, + route.controller: Version, + route.version: 1.1 + }, + IsFinished: true + } + } + ] +} \ No newline at end of file diff --git a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet6_0.verified.txt b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet6_0.verified.txt new file mode 100644 index 0000000000..b132b2f346 --- /dev/null +++ b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet6_0.verified.txt @@ -0,0 +1,87 @@ +{ + result: Hello world, + Payloads: [ + { + Source: { + Name: GET /v1.1/Target, + NameSource: Route, + Platform: csharp, + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true, + SampleRate: 1.0, + Request: { + Method: GET, + QueryString: + }, + Contexts: { + trace: { + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true + } + }, + User: {}, + Environment: production, + Breadcrumbs: [ + { + Message: Request starting HTTP/1.1 GET http://localhost/v1.1/Target - -, + Data: { + eventId: 1 + }, + Category: Microsoft.AspNetCore.Hosting.Diagnostics + }, + { + Message: Executing endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutingEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + }, + { + Message: Route matched with {action = "Method", controller = "Version"}. Executing controller action with signature System.String Method() on controller Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController (Sentry.AspNetCore.Tests)., + Data: { + eventId: ControllerActionExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executing ObjectResult, writing value of type 'System.String'., + Data: { + eventId: ObjectResultExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor + }, + { + Message: Executed action Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method, + Data: { + eventId: ActionExecuted + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executed endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutedEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + } + ], + Extra: { + http.request.method: GET, + http.response.status_code: 200 + }, + Tags: { + ActionId: Guid_1, + ActionName: Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests), + route.action: Method, + route.controller: Version, + route.version: 1.1 + }, + IsFinished: true + } + } + ] +} \ No newline at end of file diff --git a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet7_0.verified.txt b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet7_0.verified.txt new file mode 100644 index 0000000000..b132b2f346 --- /dev/null +++ b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet7_0.verified.txt @@ -0,0 +1,87 @@ +{ + result: Hello world, + Payloads: [ + { + Source: { + Name: GET /v1.1/Target, + NameSource: Route, + Platform: csharp, + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true, + SampleRate: 1.0, + Request: { + Method: GET, + QueryString: + }, + Contexts: { + trace: { + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true + } + }, + User: {}, + Environment: production, + Breadcrumbs: [ + { + Message: Request starting HTTP/1.1 GET http://localhost/v1.1/Target - -, + Data: { + eventId: 1 + }, + Category: Microsoft.AspNetCore.Hosting.Diagnostics + }, + { + Message: Executing endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutingEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + }, + { + Message: Route matched with {action = "Method", controller = "Version"}. Executing controller action with signature System.String Method() on controller Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController (Sentry.AspNetCore.Tests)., + Data: { + eventId: ControllerActionExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executing ObjectResult, writing value of type 'System.String'., + Data: { + eventId: ObjectResultExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor + }, + { + Message: Executed action Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method, + Data: { + eventId: ActionExecuted + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executed endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutedEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + } + ], + Extra: { + http.request.method: GET, + http.response.status_code: 200 + }, + Tags: { + ActionId: Guid_1, + ActionName: Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests), + route.action: Method, + route.controller: Version, + route.version: 1.1 + }, + IsFinished: true + } + } + ] +} \ No newline at end of file diff --git a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet8_0.verified.txt b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet8_0.verified.txt new file mode 100644 index 0000000000..2a1ac6c971 --- /dev/null +++ b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.DotNet8_0.verified.txt @@ -0,0 +1,87 @@ +{ + result: Hello world, + Payloads: [ + { + Source: { + Name: GET /v1.1/Target, + NameSource: Route, + Platform: csharp, + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true, + SampleRate: 1.0, + Request: { + Method: GET, + QueryString: + }, + Contexts: { + trace: { + Operation: http.server, + Description: , + Status: Ok, + IsSampled: true + } + }, + User: {}, + Environment: production, + Breadcrumbs: [ + { + Message: Request starting HTTP/1.1 GET http://localhost/v1.1/Target - - -, + Data: { + eventId: 1 + }, + Category: Microsoft.AspNetCore.Hosting.Diagnostics + }, + { + Message: Executing endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutingEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + }, + { + Message: Route matched with {action = "Method", controller = "Version"}. Executing controller action with signature System.String Method() on controller Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController (Sentry.AspNetCore.Tests)., + Data: { + eventId: ControllerActionExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executing ObjectResult, writing value of type 'System.String'., + Data: { + eventId: ObjectResultExecuting + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor + }, + { + Message: Executed action Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method, + Data: { + eventId: ActionExecuted + }, + Category: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker + }, + { + Message: Executed endpoint 'Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests)', + Data: { + eventId: ExecutedEndpoint + }, + Category: Microsoft.AspNetCore.Routing.EndpointMiddleware + } + ], + Extra: { + http.request.method: GET, + http.response.status_code: 200 + }, + Tags: { + ActionId: Guid_1, + ActionName: Sentry.AspNetCore.Tests.WebIntegrationTests+VersionController.Method (Sentry.AspNetCore.Tests), + route.action: Method, + route.controller: Version, + route.version: 1.1 + }, + IsFinished: true + } + } + ] +} \ No newline at end of file diff --git a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.verified.txt b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.verified.txt index d9449e1f45..b132b2f346 100644 --- a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.verified.txt +++ b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.Versioning.verified.txt @@ -3,7 +3,7 @@ Payloads: [ { Source: { - Name: GET v1.1/Target, + Name: GET /v1.1/Target, NameSource: Route, Platform: csharp, Operation: http.server, diff --git a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.verify.cs b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.verify.cs index 295e5e7e42..250793000e 100644 --- a/test/Sentry.AspNetCore.Tests/WebIntegrationTests.verify.cs +++ b/test/Sentry.AspNetCore.Tests/WebIntegrationTests.verify.cs @@ -65,7 +65,8 @@ public async Task Versioning() await Verify(new {result, transport.Payloads}) .IgnoreStandardSentryMembers() - .ScrubAspMembers(); + .ScrubAspMembers() + .UniqueForTargetFrameworkAndVersion(); } [ApiController] diff --git a/test/Sentry.Azure.Functions.Worker.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt b/test/Sentry.Azure.Functions.Worker.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt new file mode 100644 index 0000000000..f6955863c0 --- /dev/null +++ b/test/Sentry.Azure.Functions.Worker.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -0,0 +1,13 @@ +namespace Sentry.Azure.Functions.Worker +{ + public class SentryAzureFunctionsOptions : Sentry.Extensions.Logging.SentryLoggingOptions + { + public SentryAzureFunctionsOptions() { } + } + public static class SentryFunctionsWorkerApplicationBuilderExtensions + { + public static Microsoft.Azure.Functions.Worker.IFunctionsWorkerApplicationBuilder UseSentry(this Microsoft.Azure.Functions.Worker.IFunctionsWorkerApplicationBuilder builder, Microsoft.Extensions.Hosting.HostBuilderContext context) { } + public static Microsoft.Azure.Functions.Worker.IFunctionsWorkerApplicationBuilder UseSentry(this Microsoft.Azure.Functions.Worker.IFunctionsWorkerApplicationBuilder builder, Microsoft.Extensions.Hosting.HostBuilderContext context, System.Action? optionsConfiguration) { } + public static Microsoft.Azure.Functions.Worker.IFunctionsWorkerApplicationBuilder UseSentry(this Microsoft.Azure.Functions.Worker.IFunctionsWorkerApplicationBuilder builder, Microsoft.Extensions.Hosting.HostBuilderContext context, string dsn) { } + } +} \ No newline at end of file diff --git a/test/Sentry.Azure.Functions.Worker.Tests/Sentry.Azure.Functions.Worker.Tests.csproj b/test/Sentry.Azure.Functions.Worker.Tests/Sentry.Azure.Functions.Worker.Tests.csproj index 6e6e9b0c5d..6bad6ee23e 100644 --- a/test/Sentry.Azure.Functions.Worker.Tests/Sentry.Azure.Functions.Worker.Tests.csproj +++ b/test/Sentry.Azure.Functions.Worker.Tests/Sentry.Azure.Functions.Worker.Tests.csproj @@ -1,7 +1,7 @@ - net7.0;net6.0;net48 + net8.0;net7.0;net6.0;net48 diff --git a/test/Sentry.Azure.Functions.Worker.Tests/SentryFunctionsWorkerMiddlewareTests.cs b/test/Sentry.Azure.Functions.Worker.Tests/SentryFunctionsWorkerMiddlewareTests.cs index bc37229524..b0aac44fa1 100644 --- a/test/Sentry.Azure.Functions.Worker.Tests/SentryFunctionsWorkerMiddlewareTests.cs +++ b/test/Sentry.Azure.Functions.Worker.Tests/SentryFunctionsWorkerMiddlewareTests.cs @@ -22,7 +22,7 @@ public Fixture() var client = Substitute.For(); var sessionManager = Substitute.For(); - client.When(x => x.CaptureTransaction(Arg.Any(), Arg.Any())) + client.When(x => x.CaptureTransaction(Arg.Any(), Arg.Any(), Arg.Any())) .Do(callback => Transaction = callback.Arg()); ScopeManager = new SentryScopeManager(options, client); diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/Sentry.DiagnosticSource.IntegrationTests.csproj b/test/Sentry.DiagnosticSource.IntegrationTests/Sentry.DiagnosticSource.IntegrationTests.csproj index e2a8eebe54..325ed0e9a2 100644 --- a/test/Sentry.DiagnosticSource.IntegrationTests/Sentry.DiagnosticSource.IntegrationTests.csproj +++ b/test/Sentry.DiagnosticSource.IntegrationTests/Sentry.DiagnosticSource.IntegrationTests.csproj @@ -1,9 +1,16 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 + + + + + + + - - - - - @@ -36,14 +37,7 @@ - - - - - + diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.LoggingAsync.DotNet8_0.verified.txt b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.LoggingAsync.DotNet8_0.verified.txt new file mode 100644 index 0000000000..abe305eb4c --- /dev/null +++ b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.LoggingAsync.DotNet8_0.verified.txt @@ -0,0 +1,61 @@ +[ + { + Source: { + Name: my transaction, + Platform: csharp, + Operation: my operation, + Description: , + Status: Ok, + IsSampled: true, + SampleRate: 1.0, + Request: {}, + Contexts: { + trace: { + Operation: my operation, + Description: , + Status: Ok, + IsSampled: true + } + }, + User: {}, + Spans: [ + { + IsFinished: true, + Operation: db.connection, + Description: SqlListenerTests.verify_LoggingAsync, + Status: Ok, + IsSampled: true, + Extra: { + bytes_sent : 376, + db.connection_id: Guid_1, + db.name: SqlListenerTests.verify_LoggingAsync, + db.operation_id: Guid_2, + db.server: (LocalDb)\SqlListenerTests, + db.system: sql, + rows_sent: 0 + } + }, + { + IsFinished: true, + Operation: db.query, + Description: +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [TestEntities] ([Property]) +OUTPUT INSERTED.[Id] +VALUES (@p0); +, + Status: Ok, + IsSampled: true, + Extra: { + db.connection_id: Guid_1, + db.name: SqlListenerTests.verify_LoggingAsync, + db.operation_id: Guid_3, + db.system: sql + } + } + ], + IsFinished: true + } + } +] \ No newline at end of file diff --git a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Core3_1.verified.txt b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt similarity index 92% rename from test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Core3_1.verified.txt rename to test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt index 78692f8ffa..92775423b2 100644 --- a/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.Core3_1.verified.txt +++ b/test/Sentry.DiagnosticSource.IntegrationTests/SqlListenerTests.RecordsEfAsync.DotNet8_0.verified.txt @@ -51,8 +51,8 @@ Status: Ok, IsSampled: true, Extra: { - bytes_received: 304, - bytes_sent : 704, + bytes_received: 225, + bytes_sent : 570, db.connection_id: Guid_1, db.name: SqlListenerTests.verify_RecordsEfAsync, db.operation_id: Guid_2, @@ -65,13 +65,11 @@ IsFinished: true, Operation: db.query, Description: +SET IMPLICIT_TRANSACTIONS OFF; SET NOCOUNT ON; INSERT INTO [TestEntities] ([Property]) +OUTPUT INSERTED.[Id] VALUES (@p0); -SELECT [Id] -FROM [TestEntities] -WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity(); - , Status: Ok, IsSampled: true, @@ -87,7 +85,10 @@ WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity(); Operation: db.query.compile, Description: 'DbSet()', Status: Ok, - IsSampled: true + IsSampled: true, + Extra: { + db.system: mssql + } }, { IsFinished: true, diff --git a/test/Sentry.DiagnosticSource.Tests/Integration/SQLite/SentryDiagnosticListenerTests.cs b/test/Sentry.DiagnosticSource.Tests/Integration/SQLite/SentryDiagnosticListenerTests.cs index 2346795cdd..c73e62d50d 100644 --- a/test/Sentry.DiagnosticSource.Tests/Integration/SQLite/SentryDiagnosticListenerTests.cs +++ b/test/Sentry.DiagnosticSource.Tests/Integration/SQLite/SentryDiagnosticListenerTests.cs @@ -48,7 +48,7 @@ public Fixture() public ISpan GetSpan() => ScopeManager.GetCurrent().Key.Span; - public ITransaction StartTransaction(IHub hub, ITransactionContext context) + public ITransactionTracer StartTransaction(IHub hub, ITransactionContext context) { var transaction = new TransactionTracer(hub, context) { diff --git a/test/Sentry.DiagnosticSource.Tests/Sentry.DiagnosticSource.Tests.csproj b/test/Sentry.DiagnosticSource.Tests/Sentry.DiagnosticSource.Tests.csproj index fef3577f1b..bf6224ec40 100644 --- a/test/Sentry.DiagnosticSource.Tests/Sentry.DiagnosticSource.Tests.csproj +++ b/test/Sentry.DiagnosticSource.Tests/Sentry.DiagnosticSource.Tests.csproj @@ -1,42 +1,36 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 + + + + + + - - - - - - - - - - - - - + - + diff --git a/test/Sentry.DiagnosticSource.Tests/SentryEFCoreListenerTests.cs b/test/Sentry.DiagnosticSource.Tests/SentryEFCoreListenerTests.cs index f1ae73a615..516e7242e9 100644 --- a/test/Sentry.DiagnosticSource.Tests/SentryEFCoreListenerTests.cs +++ b/test/Sentry.DiagnosticSource.Tests/SentryEFCoreListenerTests.cs @@ -416,7 +416,7 @@ public void OnNext_HappyPathWithError_TransactionWithErroredCompiler() // Act interceptor.OnNext(new(EFQueryCompiling, efSql)); - hub.CaptureEvent(new SentryEvent(), null as Scope); + hub.CaptureEvent(new SentryEvent()); // Assert var compilerSpan = _fixture.Spans.First(s => GetValidator(EFQueryCompiling)(s)); diff --git a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt index 2a9066abe0..53cafe92cc 100644 --- a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt +++ b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -28,12 +28,6 @@ namespace Sentry.EntityFramework public void ScalarExecuted(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } public void ScalarExecuting(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } } - public static class SentryDatabaseLogging - { - [System.Obsolete("This method is called automatically by options.AddEntityFramework. This method wi" + - "ll be removed in future versions.")] - public static Sentry.EntityFramework.SentryCommandInterceptor? UseBreadcrumbs(Sentry.EntityFramework.IQueryLogger? logger = null) { } - } } namespace Sentry { diff --git a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt index 2a9066abe0..53cafe92cc 100644 --- a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt +++ b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt @@ -28,12 +28,6 @@ namespace Sentry.EntityFramework public void ScalarExecuted(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } public void ScalarExecuting(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } } - public static class SentryDatabaseLogging - { - [System.Obsolete("This method is called automatically by options.AddEntityFramework. This method wi" + - "ll be removed in future versions.")] - public static Sentry.EntityFramework.SentryCommandInterceptor? UseBreadcrumbs(Sentry.EntityFramework.IQueryLogger? logger = null) { } - } } namespace Sentry { diff --git a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 87% rename from test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index ca34a26894..53cafe92cc 100644 --- a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -1,4 +1,4 @@ -namespace Sentry.EntityFramework.ErrorProcessors +namespace Sentry.EntityFramework.ErrorProcessors { public class DbConcurrencyExceptionProcessor : Sentry.Extensibility.SentryEventExceptionProcessor { @@ -28,12 +28,6 @@ namespace Sentry.EntityFramework public void ScalarExecuted(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } public void ScalarExecuting(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } } - public static class SentryDatabaseLogging - { - [System.Obsolete("This method is called automatically by options.AddEntityFramework. This method wi" + - "ll be removed in future versions.")] - public static Sentry.EntityFramework.SentryCommandInterceptor? UseBreadcrumbs(Sentry.EntityFramework.IQueryLogger? logger = null) { } - } } namespace Sentry { diff --git a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index 2a9066abe0..53cafe92cc 100644 --- a/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.EntityFramework.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -28,12 +28,6 @@ namespace Sentry.EntityFramework public void ScalarExecuted(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } public void ScalarExecuting(System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) { } } - public static class SentryDatabaseLogging - { - [System.Obsolete("This method is called automatically by options.AddEntityFramework. This method wi" + - "ll be removed in future versions.")] - public static Sentry.EntityFramework.SentryCommandInterceptor? UseBreadcrumbs(Sentry.EntityFramework.IQueryLogger? logger = null) { } - } } namespace Sentry { diff --git a/test/Sentry.EntityFramework.Tests/Sentry.EntityFramework.Tests.csproj b/test/Sentry.EntityFramework.Tests/Sentry.EntityFramework.Tests.csproj index a4cb7ed32e..056ff3ca41 100644 --- a/test/Sentry.EntityFramework.Tests/Sentry.EntityFramework.Tests.csproj +++ b/test/Sentry.EntityFramework.Tests/Sentry.EntityFramework.Tests.csproj @@ -1,7 +1,7 @@  - net7.0;net6.0;netcoreapp3.1 + net8.0;net7.0;net6.0 diff --git a/test/Sentry.EntityFramework.Tests/SentryQueryPerformanceListenerTests.cs b/test/Sentry.EntityFramework.Tests/SentryQueryPerformanceListenerTests.cs index 0db055f85c..0e74973d0c 100644 --- a/test/Sentry.EntityFramework.Tests/SentryQueryPerformanceListenerTests.cs +++ b/test/Sentry.EntityFramework.Tests/SentryQueryPerformanceListenerTests.cs @@ -12,7 +12,7 @@ private class Fixture public DbConnection DbConnection { get; } public TestDbContext DbContext { get; } public IHub Hub { get; } - public ITransaction Tracer { get; } + public ITransactionTracer Tracer { get; } public ConcurrentBag Spans = new(); @@ -21,7 +21,7 @@ public Fixture() DbConnection = Effort.DbConnectionFactory.CreateTransient(); DbContext = new TestDbContext(DbConnection, true); Hub = Substitute.For(); - Tracer = Substitute.For(); + Tracer = Substitute.For(); Tracer.StartChild(Arg.Any()).ReturnsForAnyArgs(AddSpan); Hub.GetSpan().ReturnsForAnyArgs(Tracer); } diff --git a/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 100% rename from test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.Extensions.Logging.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt diff --git a/test/Sentry.Extensions.Logging.Tests/ConfigurationOptionsTests.cs b/test/Sentry.Extensions.Logging.Tests/ConfigurationOptionsTests.cs index f05fb87b43..2c66765548 100644 --- a/test/Sentry.Extensions.Logging.Tests/ConfigurationOptionsTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/ConfigurationOptionsTests.cs @@ -47,9 +47,12 @@ public void SentryLoggingOptions_ValuesFromAppSettings() var provider = _fixture.GetSut(); var sentryLoggingOptions = provider.GetRequiredService>().Value; - Assert.False(sentryLoggingOptions.InitializeSdk); - Assert.Equal(LogLevel.Warning, sentryLoggingOptions.MinimumBreadcrumbLevel); - Assert.Equal(LogLevel.Critical, sentryLoggingOptions.MinimumEventLevel); + using (new AssertionScope()) + { + sentryLoggingOptions.InitializeSdk.Should().BeFalse(); + sentryLoggingOptions.MinimumBreadcrumbLevel.Should().Be(LogLevel.Warning); + sentryLoggingOptions.MinimumEventLevel.Should().Be(LogLevel.Critical); + } } [Fact] @@ -85,7 +88,8 @@ public void SentryOptions_DefaultTags_ValuesApplied() var provider = _fixture.GetSut(); var sentryLoggingOptions = provider.GetRequiredService>().Value; - Assert.Equal(expectedValue, sentryLoggingOptions.DefaultTags[expectedKey]); + sentryLoggingOptions.DefaultTags.Should().ContainKey(expectedKey); + sentryLoggingOptions.DefaultTags[expectedKey].Should().Be(expectedValue); } [Fact] diff --git a/test/Sentry.Extensions.Logging.Tests/Sentry.Extensions.Logging.Tests.csproj b/test/Sentry.Extensions.Logging.Tests/Sentry.Extensions.Logging.Tests.csproj index 85a9e8f7a2..ea160bea24 100644 --- a/test/Sentry.Extensions.Logging.Tests/Sentry.Extensions.Logging.Tests.csproj +++ b/test/Sentry.Extensions.Logging.Tests/Sentry.Extensions.Logging.Tests.csproj @@ -1,7 +1,7 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 $(TargetFrameworks);net7.0-android $(TargetFrameworks);net7.0-ios $(TargetFrameworks);net7.0-maccatalyst diff --git a/test/Sentry.Extensions.Logging.Tests/SentryLoggerFactoryExtensionsTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryLoggerFactoryExtensionsTests.cs index 9cb7689a49..ca1d1f4717 100644 --- a/test/Sentry.Extensions.Logging.Tests/SentryLoggerFactoryExtensionsTests.cs +++ b/test/Sentry.Extensions.Logging.Tests/SentryLoggerFactoryExtensionsTests.cs @@ -64,6 +64,7 @@ public void AddSentry_NoDiagnosticSet_MelSet() var sut = Substitute.For(); _ = sut.AddSentry(o => { + o.Dsn = Sentry.Constants.DisableSdkDsnValue; o.Debug = true; options = o; }); @@ -79,6 +80,7 @@ public void AddSentry_DiagnosticSet_NoOverriden() var diagnosticLogger = Substitute.For(); _ = sut.AddSentry(o => { + o.Dsn = Sentry.Constants.DisableSdkDsnValue; o.Debug = true; Assert.Null(o.DiagnosticLogger); o.DiagnosticLogger = diagnosticLogger; @@ -93,7 +95,11 @@ public void AddSentry_WithOptionsCallback_CallbackInvoked() { var callbackInvoked = false; var expected = Substitute.For(); - _ = expected.AddSentry(_ => callbackInvoked = true); + _ = expected.AddSentry(o => + { + o.Dsn = Sentry.Constants.DisableSdkDsnValue; + callbackInvoked = true; + }); Assert.True(callbackInvoked); } @@ -112,7 +118,7 @@ public void AddSentry_NoOptionsDelegate_ProviderAdded() public void AddSentry_ReturnsSameFactory() { var expected = Substitute.For(); - var actual = expected.AddSentry(); + var actual = expected.AddSentry(o => o.Dsn = Sentry.Constants.DisableSdkDsnValue); Assert.Same(expected, actual); } @@ -121,7 +127,7 @@ public void AddSentry_ReturnsSameFactory() public void AddSentry_ConfigureOptionsOverload_ReturnsSameFactory() { var expected = Substitute.For(); - var actual = expected.AddSentry(_ => { }); + var actual = expected.AddSentry(o => o.Dsn = Sentry.Constants.DisableSdkDsnValue); Assert.Same(expected, actual); } @@ -134,6 +140,7 @@ public void AddSentry_ConfigureOptionsOverload_InvokesCallback() var invoked = false; _ = expected.AddSentry(o => { + o.Dsn = Sentry.Constants.DisableSdkDsnValue; Assert.NotNull(o); invoked = true; }); diff --git a/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs new file mode 100644 index 0000000000..4660ec85d0 --- /dev/null +++ b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsSetupTests.cs @@ -0,0 +1,171 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Configuration; + +namespace Sentry.Extensions.Logging.Tests; + +public class SentryLoggingOptionsSetupTests +{ + [Fact] + public void Configure_BindsConfigurationToOptions() + { + // Arrange + var expected = new SentryLoggingOptions + { + IsGlobalModeEnabled = true, + EnableScopeSync = true, + TagFilters = new List { "tag1", "tag2" }, + SendDefaultPii = true, + IsEnvironmentUser = true, + ServerName = "FakeServerName", + AttachStacktrace = true, + MaxBreadcrumbs = 7, + SampleRate = 0.7f, + Release = "FakeRelease", + Distribution = "FakeDistribution", + Environment = "Test", + Dsn = "https://d4d82fc1c2c4032a83f3a29aa3a3aff@fake-sentry.io:65535/2147483647", + MaxQueueItems = 8, + MaxCacheItems = 9, + ShutdownTimeout = TimeSpan.FromSeconds(13), + FlushTimeout = TimeSpan.FromSeconds(17), + DecompressionMethods = DecompressionMethods.GZip | DecompressionMethods.Deflate, + RequestBodyCompressionLevel = CompressionLevel.Fastest, + RequestBodyCompressionBuffered = true, + SendClientReports = true, + Debug = true, + DiagnosticLevel = SentryLevel.Warning, + ReportAssembliesMode = ReportAssembliesMode.InformationalVersion, + DeduplicateMode = DeduplicateMode.AggregateException, + CacheDirectoryPath = "~/test", + CaptureFailedRequests = true, + // FailedRequestStatusCodes = IList, + FailedRequestTargets = new List { "target1", "target2" }, + InitCacheFlushTimeout = TimeSpan.FromSeconds(27), + // DefaultTags = Dictionary, + EnableTracing = true, + TracesSampleRate = 0.8f, + TracePropagationTargets = new List { "target3", "target4" }, + StackTraceMode = StackTraceMode.Enhanced, + MaxAttachmentSize = 21478, + DetectStartupTime = StartupTimeDetectionMode.Fast, + AutoSessionTrackingInterval = TimeSpan.FromHours(3), + AutoSessionTracking = true, + UseAsyncFileIO = true, + JsonPreserveReferences = true, + + MinimumBreadcrumbLevel = LogLevel.Debug, + MinimumEventLevel = LogLevel.Error, + InitializeSdk = true + }; + var config = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["IsGlobalModeEnabled"] = expected.IsGlobalModeEnabled.ToString(), + ["EnableScopeSync"] = expected.EnableScopeSync.ToString(), + ["TagFilters:0"] = "tag1", + ["TagFilters:1"] = "tag2", + ["SendDefaultPii"] = expected.SendDefaultPii.ToString(), + ["IsEnvironmentUser"] = expected.IsEnvironmentUser.ToString(), + ["ServerName"] = expected.ServerName, + ["AttachStacktrace"] = expected.AttachStacktrace.ToString(), + ["MaxBreadcrumbs"] = expected.MaxBreadcrumbs.ToString(), + ["SampleRate"] = expected.SampleRate.Value.ToString(CultureInfo.InvariantCulture), + ["Release"] = expected.Release, + ["Distribution"] = expected.Distribution, + ["Environment"] = expected.Environment, + ["Dsn"] = expected.Dsn, + ["MaxQueueItems"] = expected.MaxQueueItems.ToString(), + ["MaxCacheItems"] = expected.MaxCacheItems.ToString(), + ["ShutdownTimeout"] = expected.ShutdownTimeout.ToString(), + ["FlushTimeout"] = expected.FlushTimeout.ToString(), + ["DecompressionMethods"] = expected.DecompressionMethods.ToString(), + ["RequestBodyCompressionLevel"] = expected.RequestBodyCompressionLevel.ToString(), + ["RequestBodyCompressionBuffered"] = expected.RequestBodyCompressionBuffered.ToString(), + ["SendClientReports"] = expected.SendClientReports.ToString(), + ["Debug"] = expected.Debug.ToString(), + ["DiagnosticLevel"] = expected.DiagnosticLevel.ToString(), + ["ReportAssembliesMode"] = expected.ReportAssembliesMode.ToString(), + ["DeduplicateMode"] = expected.DeduplicateMode.ToString(), + ["CacheDirectoryPath"] = expected.CacheDirectoryPath.ToString(), + ["CaptureFailedRequests"] = expected.CaptureFailedRequests.ToString(), + ["FailedRequestStatusCodes"] = expected.FailedRequestStatusCodes.ToString(), + ["FailedRequestTargets:0"] = expected.FailedRequestTargets.First().ToString(), + ["FailedRequestTargets:1"] = expected.FailedRequestTargets.Last().ToString(), + ["InitCacheFlushTimeout"] = expected.InitCacheFlushTimeout.ToString(), + ["DefaultTags"] = expected.DefaultTags.ToString(), + ["EnableTracing"] = expected.EnableTracing.ToString(), + ["TracesSampleRate"] = expected.TracesSampleRate.Value.ToString(CultureInfo.InvariantCulture), + ["TracePropagationTargets:0"] = expected.TracePropagationTargets.First().ToString(), + ["TracePropagationTargets:1"] = expected.TracePropagationTargets.Last().ToString(), + ["StackTraceMode"] = expected.StackTraceMode.ToString(), + ["MaxAttachmentSize"] = expected.MaxAttachmentSize.ToString(), + ["DetectStartupTime"] = expected.DetectStartupTime.ToString(), + ["AutoSessionTrackingInterval"] = expected.AutoSessionTrackingInterval.ToString(), + ["AutoSessionTracking"] = expected.AutoSessionTracking.ToString(), + ["UseAsyncFileIO"] = expected.UseAsyncFileIO.ToString(), + ["JsonPreserveReferences"] = expected.JsonPreserveReferences.ToString(), + ["MinimumBreadcrumbLevel"] = expected.MinimumBreadcrumbLevel.ToString(), + ["MinimumEventLevel"] = expected.MinimumEventLevel.ToString(), + ["InitializeSdk"] = expected.InitializeSdk.ToString(), + }) + .Build(); + + var providerConfig = Substitute.For>(); + providerConfig.Configuration.Returns(config); + var actual = new SentryLoggingOptions(); + + var setup = new SentryLoggingOptionsSetup(providerConfig); + + // Act + setup.Configure(actual); + + // Assert + using (new AssertionScope()) + { + actual.IsGlobalModeEnabled.Should().Be(expected.IsGlobalModeEnabled); + actual.EnableScopeSync.Should().Be(expected.EnableScopeSync); + actual.TagFilters.Should().BeEquivalentTo(expected.TagFilters); + actual.SendDefaultPii.Should().Be(expected.SendDefaultPii); + actual.IsEnvironmentUser.Should().Be(expected.IsEnvironmentUser); + actual.ServerName.Should().Be(expected.ServerName); + actual.AttachStacktrace.Should().Be(expected.AttachStacktrace); + actual.MaxBreadcrumbs.Should().Be(expected.MaxBreadcrumbs); + actual.SampleRate.Should().Be(expected.SampleRate); + actual.Release.Should().Be(expected.Release); + actual.Distribution.Should().Be(expected.Distribution); + actual.Environment.Should().Be(expected.Environment); + actual.Dsn.Should().Be(expected.Dsn); + actual.MaxQueueItems.Should().Be(expected.MaxQueueItems); + actual.MaxCacheItems.Should().Be(expected.MaxCacheItems); + actual.ShutdownTimeout.Should().Be(expected.ShutdownTimeout); + actual.FlushTimeout.Should().Be(expected.FlushTimeout); + actual.DecompressionMethods.Should().Be(expected.DecompressionMethods); + actual.RequestBodyCompressionLevel.Should().Be(expected.RequestBodyCompressionLevel); + actual.RequestBodyCompressionBuffered.Should().Be(expected.RequestBodyCompressionBuffered); + actual.SendClientReports.Should().Be(expected.SendClientReports); + actual.Debug.Should().Be(expected.Debug); + actual.DiagnosticLevel.Should().Be(expected.DiagnosticLevel); + actual.ReportAssembliesMode.Should().Be(expected.ReportAssembliesMode); + actual.DeduplicateMode.Should().Be(expected.DeduplicateMode); + actual.CacheDirectoryPath.Should().Be(expected.CacheDirectoryPath); + actual.CaptureFailedRequests.Should().Be(expected.CaptureFailedRequests); + actual.FailedRequestTargets.Should().BeEquivalentTo(expected.FailedRequestTargets); + actual.InitCacheFlushTimeout.Should().Be(expected.InitCacheFlushTimeout); + actual.EnableTracing.Should().Be(expected.EnableTracing); + actual.TracesSampleRate.Should().Be(expected.TracesSampleRate); + actual.TracePropagationTargets.Should().BeEquivalentTo(expected.TracePropagationTargets); + actual.StackTraceMode.Should().Be(expected.StackTraceMode); + actual.MaxAttachmentSize.Should().Be(expected.MaxAttachmentSize); + actual.DetectStartupTime.Should().Be(expected.DetectStartupTime); + actual.AutoSessionTrackingInterval.Should().Be(expected.AutoSessionTrackingInterval); + actual.AutoSessionTracking.Should().Be(expected.AutoSessionTracking); + actual.UseAsyncFileIO.Should().Be(expected.UseAsyncFileIO); + actual.JsonPreserveReferences.Should().Be(expected.JsonPreserveReferences); + + actual.MinimumBreadcrumbLevel.Should().Be(expected.MinimumBreadcrumbLevel); + actual.MinimumEventLevel.Should().Be(expected.MinimumEventLevel); + actual.InitializeSdk.Should().Be(expected.InitializeSdk); + } + } +} diff --git a/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsTests.cs b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsTests.cs new file mode 100644 index 0000000000..772473b267 --- /dev/null +++ b/test/Sentry.Extensions.Logging.Tests/SentryLoggingOptionsTests.cs @@ -0,0 +1,31 @@ +#if !NETFRAMEWORK +using Microsoft.Extensions.Configuration; + +namespace Sentry.Extensions.Logging.Tests; + +public class SentryLoggingOptionsTests : BindableTests +{ + [Fact] + public void BindableProperties_MatchOptionsProperties() + { + var propertyNames = GetPropertyNames(); + AssertContainsAllOptionsProperties(propertyNames); + } + + [Fact] + public void ApplyTo_SetsOptionsFromConfig() + { + // Arrange + var actual = new SentryLoggingOptions(); + var bindable = new BindableSentryLoggingOptions(); + + // Act + Fixture.Config.Bind(bindable); + bindable.ApplyTo(actual); + + // Assert + AssertContainsExpectedPropertyValues(actual); + } +} +#endif + diff --git a/test/Sentry.Google.Cloud.Functions.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Google.Cloud.Functions.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 93% rename from test/Sentry.Google.Cloud.Functions.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.Google.Cloud.Functions.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index 34a7e58afd..acc2519014 100644 --- a/test/Sentry.Google.Cloud.Functions.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.Google.Cloud.Functions.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -1,4 +1,4 @@ -namespace Google.Cloud.Functions.Framework +namespace Google.Cloud.Functions.Framework { public class SentryStartup : Google.Cloud.Functions.Hosting.FunctionsStartup { diff --git a/test/Sentry.Google.Cloud.Functions.Tests/Sentry.Google.Cloud.Functions.Tests.csproj b/test/Sentry.Google.Cloud.Functions.Tests/Sentry.Google.Cloud.Functions.Tests.csproj index d5447be293..87bbc988bd 100644 --- a/test/Sentry.Google.Cloud.Functions.Tests/Sentry.Google.Cloud.Functions.Tests.csproj +++ b/test/Sentry.Google.Cloud.Functions.Tests/Sentry.Google.Cloud.Functions.Tests.csproj @@ -1,7 +1,7 @@ - net7.0;net6.0;netcoreapp3.1 + net8.0;net7.0;net6.0 diff --git a/test/Sentry.Log4Net.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Log4Net.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 100% rename from test/Sentry.Log4Net.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.Log4Net.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt diff --git a/test/Sentry.Log4Net.Tests/Sentry.Log4Net.Tests.csproj b/test/Sentry.Log4Net.Tests/Sentry.Log4Net.Tests.csproj index 0d29e4dade..896c417872 100644 --- a/test/Sentry.Log4Net.Tests/Sentry.Log4Net.Tests.csproj +++ b/test/Sentry.Log4Net.Tests/Sentry.Log4Net.Tests.csproj @@ -1,7 +1,7 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 diff --git a/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj b/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj index 7615043815..bb1170e40c 100644 --- a/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj +++ b/test/Sentry.Maui.Device.TestApp/Sentry.Maui.Device.TestApp.csproj @@ -4,13 +4,17 @@ $(TargetFrameworks);net7.0-android $(TargetFrameworks);net7.0-ios - $(TargetFrameworks);net7.0-maccatalyst + Exe true Sentry.Maui.Device.TestApp Sentry.Maui.Device.TestApp true + true Sentry.Maui.Device.TestApp @@ -41,8 +45,14 @@ $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) - iossimulator-arm64 - maccatalyst-arm64 + + android-arm64 + iossimulator-arm64 + maccatalyst-arm64 + + android-x64 + iossimulator-x64 + maccatalyst-x64 @@ -64,6 +74,7 @@ + diff --git a/test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 100% rename from test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt rename to test/Sentry.Maui.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt diff --git a/test/Sentry.Maui.Tests/Sentry.Maui.Tests.csproj b/test/Sentry.Maui.Tests/Sentry.Maui.Tests.csproj index 616f08d92f..63ce3a9229 100644 --- a/test/Sentry.Maui.Tests/Sentry.Maui.Tests.csproj +++ b/test/Sentry.Maui.Tests/Sentry.Maui.Tests.csproj @@ -1,16 +1,17 @@ - net7.0;net6.0 - $(TargetFrameworks);net7.0-android - $(TargetFrameworks);net7.0-ios - $(TargetFrameworks);net7.0-maccatalyst + net7.0;net8.0 + $(TargetFrameworks);net7.0-android;net8.0-android + $(TargetFrameworks);net7.0-ios;net8.0-ios + $(TargetFrameworks);net7.0-maccatalyst;net8.0-maccatalyst true + diff --git a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt index bebbe4425e..00a36bc53b 100644 --- a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt +++ b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -67,7 +67,6 @@ namespace Sentry.NLog public bool InitializeSdk { get; set; } public string MinimumBreadcrumbLevel { get; set; } public string MinimumEventLevel { get; set; } - [NLog.Config.Advanced] public Sentry.NLog.SentryNLogOptions Options { get; } public NLog.Layouts.Layout? Release { get; set; } public int ShutdownTimeoutSeconds { get; set; } diff --git a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt index bebbe4425e..00a36bc53b 100644 --- a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt +++ b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt @@ -67,7 +67,6 @@ namespace Sentry.NLog public bool InitializeSdk { get; set; } public string MinimumBreadcrumbLevel { get; set; } public string MinimumEventLevel { get; set; } - [NLog.Config.Advanced] public Sentry.NLog.SentryNLogOptions Options { get; } public NLog.Layouts.Layout? Release { get; set; } public int ShutdownTimeoutSeconds { get; set; } diff --git a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 99% rename from test/Sentry.NLog.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index bebbe4425e..00a36bc53b 100644 --- a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -67,7 +67,6 @@ namespace Sentry.NLog public bool InitializeSdk { get; set; } public string MinimumBreadcrumbLevel { get; set; } public string MinimumEventLevel { get; set; } - [NLog.Config.Advanced] public Sentry.NLog.SentryNLogOptions Options { get; } public NLog.Layouts.Layout? Release { get; set; } public int ShutdownTimeoutSeconds { get; set; } diff --git a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index bebbe4425e..00a36bc53b 100644 --- a/test/Sentry.NLog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.NLog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -67,7 +67,6 @@ namespace Sentry.NLog public bool InitializeSdk { get; set; } public string MinimumBreadcrumbLevel { get; set; } public string MinimumEventLevel { get; set; } - [NLog.Config.Advanced] public Sentry.NLog.SentryNLogOptions Options { get; } public NLog.Layouts.Layout? Release { get; set; } public int ShutdownTimeoutSeconds { get; set; } diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt index 8592621b82..3fbf402184 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt @@ -47,12 +47,11 @@ InApp: false, Package: Sentry.NLog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt index 8592621b82..3fbf402184 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt @@ -47,12 +47,11 @@ InApp: false, Package: Sentry.NLog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Core3_1.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt similarity index 94% rename from test/Sentry.NLog.Tests/IntegrationTests.Simple.Core3_1.verified.txt rename to test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt index 8592621b82..3fbf402184 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Core3_1.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt @@ -47,12 +47,11 @@ InApp: false, Package: Sentry.NLog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt index 5b4398486b..e81d25a17e 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt @@ -47,12 +47,11 @@ InApp: false, Package: Sentry.NLog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt index 8592621b82..3fbf402184 100644 --- a/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt +++ b/test/Sentry.NLog.Tests/IntegrationTests.Simple.Net4_8.verified.txt @@ -47,12 +47,11 @@ InApp: false, Package: Sentry.NLog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.NLog.Tests/Sentry.NLog.Tests.csproj b/test/Sentry.NLog.Tests/Sentry.NLog.Tests.csproj index 0702c21efe..99d1ddcc79 100644 --- a/test/Sentry.NLog.Tests/Sentry.NLog.Tests.csproj +++ b/test/Sentry.NLog.Tests/Sentry.NLog.Tests.csproj @@ -1,11 +1,11 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 - + diff --git a/test/Sentry.NLog.Tests/SentryTargetTests.cs b/test/Sentry.NLog.Tests/SentryTargetTests.cs index 946c7b38e4..1380a4ec04 100644 --- a/test/Sentry.NLog.Tests/SentryTargetTests.cs +++ b/test/Sentry.NLog.Tests/SentryTargetTests.cs @@ -454,7 +454,7 @@ void Continuation(Exception _) [Fact] public void InitializeTarget_InitializesSdk() { - _fixture.Options.Dsn = null; + _fixture.Options.Dsn = Sentry.Constants.DisableSdkDsnValue; _fixture.SdkDisposeHandle = null; _fixture.Options.InitializeSdk = true; @@ -468,7 +468,7 @@ public void InitializeTarget_InitializesSdk() _fixture.GetLoggerFactory(); var logOutput = logWriter.ToString(); - Assert.Contains("Init was called but no DSN was provided nor located. Sentry SDK will be disabled.", logOutput); + Assert.Contains("Init called with an empty string as the DSN. Sentry SDK will be disabled.", logOutput); } finally { diff --git a/test/Sentry.OpenTelemetry.Tests/Sentry.OpenTelemetry.Tests.csproj b/test/Sentry.OpenTelemetry.Tests/Sentry.OpenTelemetry.Tests.csproj index 1a6b390365..c58aa8da53 100644 --- a/test/Sentry.OpenTelemetry.Tests/Sentry.OpenTelemetry.Tests.csproj +++ b/test/Sentry.OpenTelemetry.Tests/Sentry.OpenTelemetry.Tests.csproj @@ -1,7 +1,7 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 @@ -9,17 +9,12 @@ - - - - - - - + + diff --git a/test/Sentry.OpenTelemetry.Tests/SentryPropagatorTests.cs b/test/Sentry.OpenTelemetry.Tests/SentryPropagatorTests.cs index 3e3be52cd7..592562c818 100644 --- a/test/Sentry.OpenTelemetry.Tests/SentryPropagatorTests.cs +++ b/test/Sentry.OpenTelemetry.Tests/SentryPropagatorTests.cs @@ -76,7 +76,7 @@ public void Inject_PropagationContext_To_Baggage() { carrier.Should().ContainKey("baggage"); var baggageDictionary = (BaggageHeader.TryParse(carrier["baggage"])?.Members is {} members) - ? members.ToDictionary() + ? members.ToDict() : new Dictionary(); baggageDictionary.Should().Equal(new Dictionary() { @@ -112,7 +112,7 @@ public void Inject_SentryRequest_DoesNothing() var options = new SentryOptions(){Dsn = "https://123@o456.ingest.sentry.io/789"}; SentryClientExtensions.SentryOptionsForTestingOnly = options; - var hub = Substitute.For(); + var hub = Substitute.For(); var setter = Substitute.For>(); diff --git a/test/Sentry.Profiling.Tests/Sentry.Profiling.Tests.csproj b/test/Sentry.Profiling.Tests/Sentry.Profiling.Tests.csproj index f36a1ca1c1..c0e121a262 100644 --- a/test/Sentry.Profiling.Tests/Sentry.Profiling.Tests.csproj +++ b/test/Sentry.Profiling.Tests/Sentry.Profiling.Tests.csproj @@ -1,7 +1,7 @@  - net7.0;net6.0 + net8.0;net7.0;net6.0 @@ -9,4 +9,12 @@ + + + + + + + + diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt index 42ac3d8c67..a518be36cc 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -37,7 +37,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } @@ -64,7 +64,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt index 42ac3d8c67..a518be36cc 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt @@ -37,7 +37,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } @@ -64,7 +64,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 95% rename from test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index 7139ea3c7c..a518be36cc 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -1,4 +1,4 @@ -[assembly: System.CLSCompliant(true)] +[assembly: System.CLSCompliant(true)] namespace Sentry.Serilog { public class SentrySerilogOptions : Sentry.SentryOptions @@ -37,7 +37,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } @@ -64,7 +64,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } diff --git a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index 42ac3d8c67..a518be36cc 100644 --- a/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Serilog.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -37,7 +37,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } @@ -64,7 +64,7 @@ namespace Serilog bool? requestBodyCompressionBuffered = default, bool? debug = default, Sentry.SentryLevel? diagnosticLevel = default, - bool? reportAssemblies = default, + Sentry.ReportAssembliesMode? reportAssembliesMode = default, Sentry.DeduplicateMode? deduplicateMode = default, bool? initializeSdk = default, System.Collections.Generic.Dictionary? defaultTags = null) { } diff --git a/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs b/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs index 4045308f3f..8088548272 100644 --- a/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs +++ b/test/Sentry.Serilog.Tests/AspNetCoreIntegrationTests.cs @@ -1,3 +1,4 @@ +#if NET6_0_OR_GREATER using Sentry.AspNetCore.TestUtils; namespace Sentry.Serilog.Tests; @@ -22,3 +23,4 @@ public async Task UnhandledException_MarkedAsUnhandled() Assert.Collection(Events, @event => Assert.Collection(@event.SentryExceptions, x => Assert.False(x.Mechanism?.Handled))); } } +#endif diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt index e7b68e6710..5680be0134 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet6_0.verified.txt @@ -200,19 +200,18 @@ FileName: IntegrationTests.verify.cs, Function: Task IntegrationTests.Simple(), Module: null, - LineNumber: 47, + LineNumber: 48, ColumnNumber: 17, AbsolutePath: {ProjectDirectory}IntegrationTests.verify.cs, ContextLine: null, InApp: false, Package: Sentry.Serilog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt index e7b68e6710..5680be0134 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet7_0.verified.txt @@ -200,19 +200,18 @@ FileName: IntegrationTests.verify.cs, Function: Task IntegrationTests.Simple(), Module: null, - LineNumber: 47, + LineNumber: 48, ColumnNumber: 17, AbsolutePath: {ProjectDirectory}IntegrationTests.verify.cs, ContextLine: null, InApp: false, Package: Sentry.Serilog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Core3_1.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt similarity index 97% rename from test/Sentry.Serilog.Tests/IntegrationTests.Simple.Core3_1.verified.txt rename to test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt index e7b68e6710..5680be0134 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Core3_1.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.DotNet8_0.verified.txt @@ -200,19 +200,18 @@ FileName: IntegrationTests.verify.cs, Function: Task IntegrationTests.Simple(), Module: null, - LineNumber: 47, + LineNumber: 48, ColumnNumber: 17, AbsolutePath: {ProjectDirectory}IntegrationTests.verify.cs, ContextLine: null, InApp: false, Package: Sentry.Serilog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt index df00db54ed..91c55b2b72 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Mono4_0.verified.txt @@ -207,12 +207,11 @@ InApp: false, Package: Sentry.Serilog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Net4_8.verified.txt b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Net4_8.verified.txt index e7b68e6710..cdbf189ff2 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Net4_8.verified.txt +++ b/test/Sentry.Serilog.Tests/IntegrationTests.Simple.Net4_8.verified.txt @@ -207,12 +207,11 @@ InApp: false, Package: Sentry.Serilog.Tests, Version=SCRUBBED, Culture=SCRUBBED, PublicKeyToken=SCRUBBED, Platform: null, - ImageAddress: 0, + ImageAddress: null, SymbolAddress: null, - InstructionAddress: ____, - InstructionOffset: null, + InstructionAddress: 2, AddressMode: rel:0, - FunctionId: ____ + FunctionId: 1 } ] }, diff --git a/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs b/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs index f63f852fd2..9bd73fef6d 100644 --- a/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs +++ b/test/Sentry.Serilog.Tests/IntegrationTests.verify.cs @@ -1,4 +1,5 @@ -namespace Sentry.Serilog.Tests; +#if NET6_0_OR_GREATER +namespace Sentry.Serilog.Tests; [UsesVerify] [Collection(nameof(SentrySdkCollection))] @@ -101,3 +102,4 @@ public Task LoggingInsideTheContextOfLogging() .IgnoreStandardSentryMembers(); } } +#endif diff --git a/test/Sentry.Serilog.Tests/Sentry.Serilog.Tests.csproj b/test/Sentry.Serilog.Tests/Sentry.Serilog.Tests.csproj index f74486f102..49e4c06539 100644 --- a/test/Sentry.Serilog.Tests/Sentry.Serilog.Tests.csproj +++ b/test/Sentry.Serilog.Tests/Sentry.Serilog.Tests.csproj @@ -1,18 +1,16 @@  - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 + - - - @@ -20,4 +18,10 @@ + + + + + + diff --git a/test/Sentry.Serilog.Tests/SentrySdkCollection.cs b/test/Sentry.Serilog.Tests/SentrySdkCollection.cs index 3fb6110ff3..882dd3d93c 100644 --- a/test/Sentry.Serilog.Tests/SentrySdkCollection.cs +++ b/test/Sentry.Serilog.Tests/SentrySdkCollection.cs @@ -1,3 +1,4 @@ +#if NET6_0_OR_GREATER namespace Sentry.Serilog.Tests; [CollectionDefinition(nameof(SerilogAspNetSentrySdkTestFixture))] @@ -8,3 +9,4 @@ public sealed class SentrySdkCollection : ICollectionFixture interfaces. // See: https://xunit.net/docs/shared-context#collection-fixture } +#endif diff --git a/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs b/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs index 006c17b748..6e68a4ee64 100644 --- a/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs +++ b/test/Sentry.Serilog.Tests/SentrySerilogSinkExtensionsTests.cs @@ -23,7 +23,7 @@ private class Fixture public bool RequestBodyCompressionBuffered { get; } = false; public bool Debug { get; } = true; public SentryLevel DiagnosticLevel { get; } = SentryLevel.Warning; - public bool ReportAssemblies { get; } = false; + public ReportAssembliesMode ReportAssembliesMode { get; } = ReportAssembliesMode.None; public DeduplicateMode DeduplicateMode { get; } = DeduplicateMode.SameExceptionInstance; public bool InitializeSdk { get; } = false; public LogEventLevel MinimumEventLevel { get; } = LogEventLevel.Verbose; @@ -71,7 +71,7 @@ public void ConfigureSentrySerilogOptions_WithMultipleParameters_MakesAppropriat var sut = Fixture.GetSut(); SentrySinkExtensions.ConfigureSentrySerilogOptions(sut, sendDefaultPii: _fixture.SendDefaultPii, - decompressionMethods: _fixture.DecompressionMethods, reportAssemblies: _fixture.ReportAssemblies, sampleRate: _fixture.SampleRate); + decompressionMethods: _fixture.DecompressionMethods, reportAssembliesMode: _fixture.ReportAssembliesMode, sampleRate: _fixture.SampleRate); // Fail early AssertNotEqualDeep(_fixture.Options, sut); @@ -79,9 +79,7 @@ public void ConfigureSentrySerilogOptions_WithMultipleParameters_MakesAppropriat // Compare individual properties Assert.Equal(_fixture.SendDefaultPii, sut.SendDefaultPii); Assert.Equal(_fixture.DecompressionMethods, sut.DecompressionMethods); -#pragma warning disable CS0618 // Type or member is obsolete - Assert.Equal(_fixture.ReportAssemblies, sut.ReportAssemblies); -#pragma warning restore CS0618 // Type or member is obsolete + Assert.Equal(_fixture.ReportAssembliesMode, sut.ReportAssembliesMode); Assert.Equal(_fixture.SampleRate, sut.SampleRate); } @@ -96,7 +94,7 @@ public void ConfigureSentrySerilogOptions_WithAllParameters_MakesAppropriateChan _fixture.SampleRate, _fixture.Release, _fixture.Environment, _fixture.MaxQueueItems, _fixture.ShutdownTimeout, _fixture.DecompressionMethods, _fixture.RequestBodyCompressionLevel, _fixture.RequestBodyCompressionBuffered, _fixture.Debug, _fixture.DiagnosticLevel, - _fixture.ReportAssemblies, _fixture.DeduplicateMode, _fixture.InitializeSdk); + _fixture.ReportAssembliesMode, _fixture.DeduplicateMode, _fixture.InitializeSdk); // Fail early AssertNotEqualDeep(_fixture.Options, sut); @@ -118,9 +116,7 @@ public void ConfigureSentrySerilogOptions_WithAllParameters_MakesAppropriateChan Assert.Equal(_fixture.RequestBodyCompressionBuffered, sut.RequestBodyCompressionBuffered); Assert.Equal(_fixture.Debug, sut.Debug); Assert.Equal(_fixture.DiagnosticLevel, sut.DiagnosticLevel); -#pragma warning disable CS0618 // Type or member is obsolete - Assert.Equal(_fixture.ReportAssemblies, sut.ReportAssemblies); -#pragma warning restore CS0618 // Type or member is obsolete + Assert.Equal(_fixture.ReportAssembliesMode, sut.ReportAssembliesMode); Assert.Equal(_fixture.DeduplicateMode, sut.DeduplicateMode); Assert.Equal(_fixture.InitializeSdk, sut.InitializeSdk); Assert.Equal(_fixture.MinimumEventLevel, sut.MinimumEventLevel); diff --git a/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs b/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs index 8f3c49f4d3..4510240ceb 100644 --- a/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs +++ b/test/Sentry.Serilog.Tests/SerilogAspNetSentrySdkTestFixture.cs @@ -1,3 +1,4 @@ +#if NET6_0_OR_GREATER using Sentry.AspNetCore.TestUtils; namespace Sentry.Serilog.Tests; @@ -18,9 +19,7 @@ protected override void ConfigureBuilder(WebHostBuilder builder) { app.UseExceptionHandler(new ExceptionHandlerOptions { -#if NET6_0_OR_GREATER AllowStatusCode404Response = true, -#endif ExceptionHandlingPath = "/error" }); }; @@ -28,7 +27,7 @@ protected override void ConfigureBuilder(WebHostBuilder builder) builder.ConfigureLogging(loggingBuilder => { var logger = new LoggerConfiguration() - .WriteTo.Sentry() + .WriteTo.Sentry(ValidDsn) .CreateLogger(); loggingBuilder.AddSerilog(logger); }); @@ -36,3 +35,4 @@ protected override void ConfigureBuilder(WebHostBuilder builder) base.ConfigureBuilder(builder); } } +#endif diff --git a/test/Sentry.Testing.CrashableApp/Program.cs b/test/Sentry.Testing.CrashableApp/Program.cs index 129f953d61..df7dc095f7 100644 --- a/test/Sentry.Testing.CrashableApp/Program.cs +++ b/test/Sentry.Testing.CrashableApp/Program.cs @@ -1,12 +1,12 @@ -#pragma warning disable CS0618 - namespace Sentry.Testing.CrashableApp; public static class Program { public static void Main(string[] args) { +#pragma warning disable CS0618 var crashType = (CrashType)Enum.Parse(typeof(CrashType), args[0]); SentrySdk.CauseCrash(crashType); +#pragma warning restore CS0618 } } diff --git a/test/Sentry.Testing.CrashableApp/Sentry.Testing.CrashableApp.csproj b/test/Sentry.Testing.CrashableApp/Sentry.Testing.CrashableApp.csproj index 4309f9bd79..4a2fdcd63b 100644 --- a/test/Sentry.Testing.CrashableApp/Sentry.Testing.CrashableApp.csproj +++ b/test/Sentry.Testing.CrashableApp/Sentry.Testing.CrashableApp.csproj @@ -2,7 +2,7 @@ Exe - net7.0;net6.0;netcoreapp3.1;net48 + net8.0;net7.0;net6.0;net48 diff --git a/test/Sentry.Testing/BindableTests.cs b/test/Sentry.Testing/BindableTests.cs new file mode 100644 index 0000000000..acc87690d6 --- /dev/null +++ b/test/Sentry.Testing/BindableTests.cs @@ -0,0 +1,121 @@ +#if !NETFRAMEWORK +using Microsoft.Extensions.Configuration; + +namespace Sentry.Testing; + +public abstract class BindableTests(params string[] skipProperties) +{ + public class TextFixture + { + public IEnumerable ExpectedPropertyNames { get; } + public List> ExpectedPropertyValues { get; } + + public IConfigurationRoot Config { get; } + + public TextFixture(params string[] skipProperties) + { + ExpectedPropertyNames = GetBindableProperties(skipProperties).Select(x => x.Name); + ExpectedPropertyValues = GetBindableProperties(skipProperties).Select(GetDummyBindableValue).ToList(); + Config = new ConfigurationBuilder() + .AddInMemoryCollection(ExpectedPropertyValues.SelectMany(ToConfigValues)) + .Build(); + } + } + + protected TextFixture Fixture { get; } = new(skipProperties); + + private static IEnumerable GetBindableProperties(IEnumerable skipProperties) + { + return typeof(TOptions).GetProperties() + .Where(p => + !p.PropertyType.IsSubclassOf(typeof(Delegate)) // Exclude delegate properties + && !p.PropertyType.IsInterface // Exclude interface properties + && !skipProperties.Contains(p.Name) // Exclude any properties explicitly excluded by derived classes +#if ANDROID + && !(p.PropertyType == typeof(SentryOptions.AndroidOptions)) // Exclude the Mobile sub-property +#elif __IOS__ + && !(p.PropertyType == typeof(SentryOptions.IosOptions)) // Exclude the Mobile sub-property +#endif + ); + } + + protected IEnumerable GetPropertyNames() => typeof(T).GetProperties().Select(x => x.Name).ToList(); + + private static KeyValuePair GetDummyBindableValue(PropertyInfo propertyInfo) + { + var propertyType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType; + var value = propertyType switch + { + not null when propertyType == typeof(bool) => true, + not null when propertyType == typeof(string) => $"fake {propertyInfo.Name}", + not null when propertyType == typeof(int) => 7, + not null when propertyType == typeof(long) => 7, + not null when propertyType == typeof(float) => 0.3f, + not null when propertyType == typeof(double) => 0.6, + not null when propertyType == typeof(TimeSpan) => TimeSpan.FromSeconds(3), + not null when propertyType.IsEnum => GetNonDefaultEnumValue(propertyType), + not null when propertyType == typeof(Dictionary) => + new Dictionary + { + {$"key1", $"{propertyInfo.Name}value1"}, + {$"key2", $"{propertyInfo.Name}value2"} + }, + _ => throw new NotSupportedException($"Unsupported property type on property {propertyInfo.Name}") + }; + return new KeyValuePair(propertyInfo, value); + } + + private static IEnumerable> ToConfigValues(KeyValuePair item) + { + var (prop, value) = item; + var propertyType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; + if (propertyType == typeof(Dictionary)) + { + foreach (var kvp in (Dictionary)value) + { + yield return new KeyValuePair($"{prop.Name}:{kvp.Key}", kvp.Value); + } + } + else + { + yield return new KeyValuePair(prop.Name, value.ToString()); + } + } + + private static object GetNonDefaultEnumValue(Type enumType) + { + var enumValues = Enum.GetValues(enumType); + if (enumValues.Length > 1) + { + return enumValues.GetValue(1); // return second value + } + throw new InvalidOperationException("Enum has no non-default values"); + } + + protected void AssertContainsAllOptionsProperties(IEnumerable actual) + { + var missing = Fixture.ExpectedPropertyNames.Where(x => !actual.Contains(x)); + + missing.Should().BeEmpty(); + } + + protected void AssertContainsExpectedPropertyValues(TOptions actual) + { + using (new AssertionScope()) + { + foreach (var (prop, expectedValue) in Fixture.ExpectedPropertyValues) + { + var actualValue = actual.GetProperty(prop.Name); + if (prop.PropertyType == typeof(Dictionary)) + { + actualValue.Should().BeEquivalentTo(expectedValue); + } + else + { + actualValue.Should().Be(expectedValue); + } + } + } + } +} +#endif diff --git a/test/Sentry.Testing/DsnSamples.cs b/test/Sentry.Testing/DsnSamples.cs index 0aa57ac0b4..6ad50d1598 100644 --- a/test/Sentry.Testing/DsnSamples.cs +++ b/test/Sentry.Testing/DsnSamples.cs @@ -8,12 +8,6 @@ public static class DsnSamples /// public const string ValidDsn = "https://d4d82fc1c2c4032a83f3a29aa3a3aff@fake-sentry.io:65535/2147483647"; - /// - /// DSN with secret. Used only to test backwards compatibility. - /// - [Obsolete("Sentry has dropped the use of secrets.")] - public const string ValidDsnWithSecret = "https://d4d82fc1c2c4032a83f3a29aa3a3aff:ed0a8589a0bb4d4793ac4c70375f3d65@fake-sentry.io:65535/2147483647"; - /// /// Missing ProjectId /// diff --git a/test/Sentry.Testing/Sentry.Testing.csproj b/test/Sentry.Testing/Sentry.Testing.csproj index 65a23e1159..7508c96ed8 100644 --- a/test/Sentry.Testing/Sentry.Testing.csproj +++ b/test/Sentry.Testing/Sentry.Testing.csproj @@ -1,10 +1,10 @@  - net7.0;net6.0;netcoreapp3.1;net48 - $(TargetFrameworks);net7.0-android - $(TargetFrameworks);net7.0-ios - $(TargetFrameworks);net7.0-maccatalyst + net8.0;net7.0;net6.0;net48 + $(TargetFrameworks);net7.0-android;net8.0-android + $(TargetFrameworks);net7.0-ios;net8.0-ios + $(TargetFrameworks);net7.0-maccatalyst;net8.0-maccatalyst false @@ -22,4 +22,8 @@ + + + + diff --git a/test/Sentry.Testing/VerifyExtensions.cs b/test/Sentry.Testing/VerifyExtensions.cs index 914f0165a8..b35d8bb8fa 100644 --- a/test/Sentry.Testing/VerifyExtensions.cs +++ b/test/Sentry.Testing/VerifyExtensions.cs @@ -76,7 +76,7 @@ public override void Write(VerifyJsonWriter writer, Contexts contexts) _.Key != "Memory Info" && _.Key != "Dynamic Code") .OrderBy(x => x.Key) - .ToDictionary(); + .ToDict(); writer.Serialize(items); } } @@ -103,8 +103,8 @@ private class StackFrameConverter : WriteOnlyJsonConverter public override void Write(VerifyJsonWriter writer, SentryStackFrame obj) { - obj.FunctionId = ScrubAlphaNum(obj.FunctionId); - obj.InstructionAddress = ScrubAlphaNum(obj.InstructionAddress); + obj.FunctionId = obj.FunctionId is null ? null : 1; + obj.InstructionAddress = obj.InstructionAddress is null ? null : 2; obj.Package = obj.Package.Replace(PackageRegex, "=SCRUBBED"); if (RuntimeInfo.GetRuntime().IsMono()) diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt index 35c9c5b579..02c6e3474e 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet6_0.verified.txt @@ -61,17 +61,32 @@ namespace Sentry public const string Platform = "csharp"; public const int ProtocolVersion = 7; } - public sealed class Contexts : System.Collections.Concurrent.ConcurrentDictionary, Sentry.IJsonSerializable + public sealed class Contexts : Sentry.IJsonSerializable, System.Collections.Generic.ICollection>, System.Collections.Generic.IDictionary, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable { public Contexts() { } public Sentry.Protocol.App App { get; } public Sentry.Protocol.Browser Browser { get; } + public int Count { get; } public Sentry.Protocol.Device Device { get; } public Sentry.Protocol.Gpu Gpu { get; } + public bool IsReadOnly { get; } + public object this[string key] { get; set; } + public System.Collections.Generic.ICollection Keys { get; } public Sentry.Protocol.OperatingSystem OperatingSystem { get; } public Sentry.Protocol.Response Response { get; } public Sentry.Protocol.Runtime Runtime { get; } public Sentry.Protocol.Trace Trace { get; } + public System.Collections.Generic.ICollection Values { get; } + public void Add(System.Collections.Generic.KeyValuePair item) { } + public void Add(string key, object value) { } + public void Clear() { } + public bool Contains(System.Collections.Generic.KeyValuePair item) { } + public bool ContainsKey(string key) { } + public void CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { } + public System.Collections.Generic.IEnumerator> GetEnumerator() { } + public bool Remove(System.Collections.Generic.KeyValuePair item) { } + public bool Remove(string key) { } + public bool TryGetValue(string key, out object value) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Contexts FromJson(System.Text.Json.JsonElement json) { } } @@ -82,20 +97,6 @@ namespace Sentry Managed = 0, ManagedBackgroundThread = 1, } - public sealed class DebugImage : Sentry.IJsonSerializable - { - public DebugImage() { } - public string? CodeFile { get; set; } - public string? CodeId { get; set; } - public string? DebugChecksum { get; set; } - public string? DebugFile { get; set; } - public string? DebugId { get; set; } - public string? ImageAddress { get; set; } - public long? ImageSize { get; set; } - public string? Type { get; set; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - public static Sentry.DebugImage FromJson(System.Text.Json.JsonElement json) { } - } [System.Flags] public enum DeduplicateMode { @@ -118,6 +119,9 @@ namespace Sentry } public static class EventLikeExtensions { + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category, string? type, System.ValueTuple? dataPair = default, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static bool HasUser(this Sentry.IEventLike eventLike) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, System.Collections.Generic.IEnumerable fingerprint) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, params string[] fingerprint) { } @@ -128,12 +132,6 @@ namespace Sentry public FileAttachmentContent(string filePath, bool readFileAsynchronously) { } public System.IO.Stream GetStream() { } } - public static class HasBreadcrumbsExtensions - { - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category, string? type, System.ValueTuple? dataPair = default, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - } public static class HasExtraExtensions { public static void SetExtras(this Sentry.IHasExtra hasExtra, System.Collections.Generic.IEnumerable> values) { } @@ -182,32 +180,29 @@ namespace Sentry public static Sentry.SentryId CaptureMessage(this Sentry.IHub hub, string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void LockScope(this Sentry.IHub hub) { } public static System.IDisposable PushAndLockScope(this Sentry.IHub hub) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } public static void UnlockScope(this Sentry.IHub hub) { } } public interface IAttachmentContent { System.IO.Stream GetStream(); } - public interface IEventLike : Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public interface IEventLike : Sentry.IHasExtra, Sentry.IHasTags { + System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } Sentry.Contexts Contexts { get; set; } + string? Distribution { get; set; } string? Environment { get; set; } System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } Sentry.SentryLevel? Level { get; set; } - string? Platform { get; set; } string? Release { get; set; } Sentry.Request Request { get; set; } Sentry.SdkVersion Sdk { get; } string? TransactionName { get; set; } Sentry.User User { get; set; } - } - public interface IHasBreadcrumbs - { - System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } void AddBreadcrumb(Sentry.Breadcrumb breadcrumb); } public interface IHasExtra @@ -221,15 +216,12 @@ namespace Sentry void SetTag(string key, string value); void UnsetTag(string key); } - public interface IHasTransactionNameSource - { - Sentry.TransactionNameSource NameSource { get; } - } public interface IHub : Sentry.ISentryClient, Sentry.ISentryScopeManager { Sentry.SentryId LastEventId { get; } void BindException(System.Exception exception, Sentry.ISpan span); Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope); Sentry.TransactionContext ContinueTrace(Sentry.SentryTraceHeader? traceHeader, Sentry.BaggageHeader? baggageHeader, string? name = null, string? operation = null); Sentry.TransactionContext ContinueTrace(string? traceHeader, string? baggageHeader, string? name = null, string? operation = null); void EndSession(Sentry.SessionEndStatus status = 0); @@ -239,7 +231,7 @@ namespace Sentry void PauseSession(); void ResumeSession(); void StartSession(); - Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); + Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); } public interface IJsonSerializable { @@ -256,11 +248,10 @@ namespace Sentry public interface ISentryClient { bool IsEnabled { get; } - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null); - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null); void CaptureSession(Sentry.SessionUpdate sessionUpdate); void CaptureTransaction(Sentry.Transaction transaction); - void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint); + void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint); void CaptureUserFeedback(Sentry.UserFeedback userFeedback); System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout); } @@ -271,9 +262,6 @@ namespace Sentry System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope); System.IDisposable PushScope(); System.IDisposable PushScope(TState state); - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - void WithScope(System.Action scopeCallback); } public interface ISentryScopeStateProcessor { @@ -294,7 +282,7 @@ namespace Sentry System.DateTimeOffset StartTimestamp { get; } string? UserAgent { get; } } - public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext { new string? Description { get; set; } new string Operation { get; set; } @@ -305,27 +293,32 @@ namespace Sentry void Finish(System.Exception exception, Sentry.SpanStatus status); Sentry.ISpan StartChild(string operation); } - public interface ISpanContext : Sentry.Protocol.ITraceContext { } - public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.Protocol.ITraceContext { System.DateTimeOffset? EndTimestamp { get; } bool IsFinished { get; } + System.Collections.Generic.IReadOnlyDictionary Measurements { get; } System.DateTimeOffset StartTimestamp { get; } Sentry.SentryTraceHeader GetTraceHeader(); + void SetMeasurement(string name, Sentry.Protocol.Measurement measurement); + } + public interface ITransactionContext : Sentry.Protocol.ITraceContext + { + bool? IsParentSampled { get; } + string Name { get; } + Sentry.TransactionNameSource NameSource { get; } } - public interface ITransaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public interface ITransactionData : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + { + string? Platform { get; set; } + } + public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { new bool? IsParentSampled { get; set; } new string Name { get; set; } System.Collections.Generic.IReadOnlyCollection Spans { get; } Sentry.ISpan? GetLastActiveSpan(); } - public interface ITransactionContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext - { - bool? IsParentSampled { get; } - string Name { get; } - } - public interface ITransactionData : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { } public enum InstructionAddressAdjustment { Auto = 0, @@ -338,14 +331,6 @@ namespace Sentry Sentry = 0, OpenTelemetry = 1, } - public static class MeasurementExtensions - { - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, double value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, int value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, long value, Sentry.MeasurementUnit unit = default) { } - [System.CLSCompliant(false)] - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, ulong value, Sentry.MeasurementUnit unit = default) { } - } public readonly struct MeasurementUnit : System.IEquatable { public static Sentry.MeasurementUnit None; @@ -425,7 +410,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Request FromJson(System.Text.Json.JsonElement json) { } } - public class Scope : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public class Scope : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags { public Scope(Sentry.SentryOptions? options) { } public System.Collections.Generic.IReadOnlyCollection Attachments { get; } @@ -436,13 +421,12 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } public Sentry.SentryLevel? Level { get; set; } - public string? Platform { get; set; } public string? Release { get; set; } public Sentry.Request Request { get; set; } public Sentry.SdkVersion Sdk { get; } public Sentry.ISpan? Span { get; set; } public System.Collections.Generic.IReadOnlyDictionary Tags { get; } - public Sentry.ITransaction? Transaction { get; set; } + public Sentry.ITransactionTracer? Transaction { get; set; } public string? TransactionName { get; set; } public Sentry.User User { get; set; } public void AddAttachment(Sentry.Attachment attachment) { } @@ -455,8 +439,6 @@ namespace Sentry public void ClearAttachments() { } public void ClearBreadcrumbs() { } public Sentry.Scope Clone() { } - [System.Obsolete("Use the Span property instead. This method will be removed in a future release.")] - public Sentry.ISpan? GetSpan() { } public void SetExtra(string key, object? value) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } @@ -493,14 +475,11 @@ namespace Sentry { public SentryClient(Sentry.SentryOptions options) { } public bool IsEnabled { get; } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } - [System.Obsolete("Sentry client should not be explicitly disposed of. This method will be removed i" + - "n version 4.")] public void Dispose() { } public System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout) { } } @@ -514,13 +493,13 @@ namespace Sentry public static System.Threading.Tasks.Task FlushAsync(this Sentry.ISentryClient client) { } } [System.Diagnostics.DebuggerDisplay("{GetType().Name,nq}: {EventId,nq}")] - public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable + public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable { public SentryEvent() { } public SentryEvent(System.Exception? exception) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } - public System.Collections.Generic.List? DebugImages { get; set; } + public System.Collections.Generic.List? DebugImages { get; set; } public string? Distribution { get; set; } public string? Environment { get; set; } public Sentry.SentryId EventId { get; } @@ -624,20 +603,10 @@ namespace Sentry public bool AutoSessionTracking { get; set; } public System.TimeSpan AutoSessionTrackingInterval { get; set; } public Sentry.Extensibility.IBackgroundWorker? BackgroundWorker { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeBreadcrumb instea" + - "d.")] - public System.Func? BeforeBreadcrumb { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSend instead.")] - public System.Func? BeforeSend { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSendTransaction i" + - "nstead.")] - public System.Func? BeforeSendTransaction { get; set; } public string? CacheDirectoryPath { get; set; } public bool CaptureFailedRequests { get; set; } public System.Action? ConfigureClient { get; set; } public System.Func? CrashedLastRun { get; set; } - [System.Obsolete("Use CreateHttpMessageHandler instead")] - public System.Func? CreateHttpClientHandler { get; set; } public System.Func? CreateHttpMessageHandler { get; set; } public bool Debug { get; set; } public System.Net.DecompressionMethods DecompressionMethods { get; set; } @@ -659,16 +628,12 @@ namespace Sentry public bool IsEnvironmentUser { get; set; } public bool IsGlobalModeEnabled { get; set; } public bool JsonPreserveReferences { get; set; } - [System.Obsolete("This property is no longer used. It will be removed in a future version.")] - public bool KeepAggregateException { get; set; } public long MaxAttachmentSize { get; set; } public int MaxBreadcrumbs { get; set; } public int MaxCacheItems { get; set; } public int MaxQueueItems { get; set; } public Sentry.Extensibility.INetworkStatusListener? NetworkStatusListener { get; set; } public string? Release { get; set; } - [System.Obsolete("Use ReportAssembliesMode instead", false)] - public bool ReportAssemblies { get; set; } public Sentry.ReportAssembliesMode ReportAssembliesMode { get; set; } public bool RequestBodyCompressionBuffered { get; set; } public System.IO.Compression.CompressionLevel RequestBodyCompressionLevel { get; set; } @@ -681,12 +646,14 @@ namespace Sentry public System.TimeSpan ShutdownTimeout { get; set; } public Sentry.StackTraceMode StackTraceMode { get; set; } public System.Collections.Generic.ICollection TagFilters { get; set; } - public System.Collections.Generic.IList TracePropagationTargets { get; set; } + public System.Collections.Generic.IList TracePropagationTargets { get; set; } public double? TracesSampleRate { get; set; } public System.Func? TracesSampler { get; set; } public Sentry.Extensibility.ITransport? Transport { get; set; } public bool UseAsyncFileIO { get; set; } public void AddJsonConverter(System.Text.Json.Serialization.JsonConverter converter) { } + public void AddJsonSerializerContext(System.Func contextBuilder) + where T : System.Text.Json.Serialization.JsonSerializerContext { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } @@ -716,9 +683,6 @@ namespace Sentry public static void DisableAppDomainUnhandledExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableDiagnosticSourceIntegration(this Sentry.SentryOptions options) { } public static void DisableDuplicateEventDetection(this Sentry.SentryOptions options) { } - [System.Obsolete("Method has been renamed to DisableUnobservedTaskExceptionCapture. Please update " + - "usage.")] - public static void DisableTaskUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableWinUiUnhandledExceptionIntegration(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllEventProcessors(this Sentry.SentryOptions options) { } @@ -734,12 +698,6 @@ namespace Sentry where TProcessor : Sentry.Extensibility.ISentryTransactionProcessor { } public static Sentry.SentryOptions UseStackTraceFactory(this Sentry.SentryOptions options, Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } } - public static class SentryScopeManagerExtensions - { - public static T? WithScope(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func> scopeCallback) { } - } public static class SentrySdk { public static bool IsEnabled { get; } @@ -749,17 +707,16 @@ namespace Sentry public static void AddBreadcrumb(Sentry.Infrastructure.ISystemClock? clock, string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static void BindClient(Sentry.ISentryClient client) { } public static void BindException(System.Exception exception, Sentry.ISpan span) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public static Sentry.SentryId CaptureException(System.Exception exception) { } public static Sentry.SentryId CaptureException(System.Exception exception, System.Action configureScope) { } public static Sentry.SentryId CaptureMessage(string message, Sentry.SentryLevel level = 1) { } public static Sentry.SentryId CaptureMessage(string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public static void CaptureTransaction(Sentry.Transaction transaction) { } - public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public static void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public static void CaptureUserFeedback(Sentry.SentryId eventId, string email, string comments, string? name = null) { } [System.Obsolete("WARNING: This method deliberately causes a crash, and should not be used in a rea" + @@ -787,23 +744,11 @@ namespace Sentry public static System.IDisposable PushScope(TState state) { } public static void ResumeSession() { } public static void StartSession() { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public static Sentry.ITransaction StartTransaction(string name, string operation) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, string? description) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, string? description) { } } public sealed class SentryStackFrame : Sentry.IJsonSerializable { @@ -815,12 +760,10 @@ namespace Sentry public string? FileName { get; set; } public System.Collections.Generic.IList FramesOmitted { get; } public string? Function { get; set; } - public string? FunctionId { get; set; } - public long ImageAddress { get; set; } + public long? FunctionId { get; set; } + public long? ImageAddress { get; set; } public bool? InApp { get; set; } - public string? InstructionAddress { get; set; } - [System.Obsolete("This property is unused and will be removed in the future.")] - public long? InstructionOffset { get; set; } + public long? InstructionAddress { get; set; } public int? LineNumber { get; set; } public string? Module { get; set; } public string? Package { get; set; } @@ -861,12 +804,6 @@ namespace Sentry public override string ToString() { } public static Sentry.SentryTraceHeader Parse(string value) { } } - public sealed class SentryValues : Sentry.IJsonSerializable - { - public SentryValues(System.Collections.Generic.IEnumerable? values) { } - public System.Collections.Generic.IEnumerable Values { get; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - } public class Session : Sentry.ISession { public Session(string? distinctId, string release, string? environment) { } @@ -908,7 +845,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.SessionUpdate FromJson(System.Text.Json.JsonElement json) { } } - public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public Span(Sentry.ISpan tracer) { } public Span(Sentry.SpanId? parentSpanId, string operation) { } @@ -917,6 +854,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -926,14 +864,15 @@ namespace Sentry public Sentry.SentryId TraceId { get; } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Span FromJson(System.Text.Json.JsonElement json) { } } - public class SpanContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public class SpanContext : Sentry.Protocol.ITraceContext { - public SpanContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled) { } + public SpanContext(string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = null, Sentry.SpanStatus? status = default, bool? isSampled = default) { } public string? Description { get; } public Sentry.Instrumenter Instrumenter { get; } public bool? IsSampled { get; } @@ -943,9 +882,17 @@ namespace Sentry public Sentry.SpanStatus? Status { get; } public Sentry.SentryId TraceId { get; } } + public static class SpanDataExtensions + { + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, double value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, int value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, long value, Sentry.MeasurementUnit unit = default) { } + [System.CLSCompliant(false)] + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, ulong value, Sentry.MeasurementUnit unit = default) { } + } public static class SpanExtensions { - public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } + public static Sentry.ITransactionTracer GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable @@ -985,7 +932,7 @@ namespace Sentry OutOfRange = 15, DataLoss = 16, } - public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { } public string? Description { get; set; } @@ -993,6 +940,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -1006,6 +954,7 @@ namespace Sentry public void Finish(System.Exception exception, Sentry.SpanStatus status) { } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public Sentry.ISpan StartChild(string operation) { } public void UnsetTag(string key) { } @@ -1036,15 +985,9 @@ namespace Sentry public override string ToString() { } public static Sentry.SubstringOrRegexPattern op_Implicit(string substringOrRegexPattern) { } } - [System.ComponentModel.TypeConverter(typeof(Sentry.TracePropagationTargetTypeConverter))] - public class TracePropagationTarget : Sentry.SubstringOrRegexPattern + public class Transaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { - public TracePropagationTarget(System.Text.RegularExpressions.Regex regex) { } - public TracePropagationTarget(string substringOrRegexPattern, System.StringComparison comparison = 5) { } - } - public class Transaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext - { - public Transaction(Sentry.ITransaction tracer) { } + public Transaction(Sentry.ITransactionTracer tracer) { } public Transaction(string name, string operation) { } public Transaction(string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } @@ -1086,16 +1029,9 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Transaction FromJson(System.Text.Json.JsonElement json) { } } - public class TransactionContext : Sentry.SpanContext, Sentry.IHasTransactionNameSource, Sentry.ISpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + public class TransactionContext : Sentry.SpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { - public TransactionContext(string name, string operation) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public TransactionContext(string name, string operation, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(string name, string operation, bool? isSampled) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled, Sentry.TransactionNameSource nameSource) { } + public TransactionContext(string name, string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = "", Sentry.SpanStatus? status = default, bool? isSampled = default, bool? isParentSampled = default, Sentry.TransactionNameSource nameSource = 0) { } public bool? IsParentSampled { get; } public string Name { get; set; } public Sentry.TransactionNameSource NameSource { get; set; } @@ -1115,11 +1051,9 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; } public Sentry.ITransactionContext TransactionContext { get; } } - public class TransactionTracer : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransaction, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public class TransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext { public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } public string? Description { get; set; } @@ -1225,12 +1159,14 @@ namespace Sentry.Extensibility public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2) { } public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } - public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } @@ -1246,12 +1182,12 @@ namespace Sentry.Extensibility public Sentry.SentryId LastEventId { get; } public void BindClient(Sentry.ISentryClient client) { } public void BindException(System.Exception exception, Sentry.ISpan span) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1268,8 +1204,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public void WithScope(System.Action scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public class FormRequestPayloadExtractor : Sentry.Extensibility.BaseRequestPayloadExtractor { @@ -1289,11 +1224,12 @@ namespace Sentry.Extensibility public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope, Sentry.Hint? hint = null) { } public Sentry.SentryId CaptureException(System.Exception exception) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback sentryUserFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1309,19 +1245,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public interface IBackgroundWorker { @@ -1430,13 +1354,6 @@ namespace Sentry.Infrastructure public ConsoleDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } protected override void LogMessage(string message) { } } - [System.Obsolete("Logger doesn\'t work outside of Sentry SDK. Please use TraceDiagnosticLogger inste" + - "ad")] - public class DebugDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger - { - public DebugDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } - protected override void LogMessage(string message) { } - } public abstract class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger { protected DiagnosticLogger(Sentry.SentryLevel minimalLevel) { } @@ -1457,9 +1374,6 @@ namespace Sentry.Infrastructure public sealed class SystemClock : Sentry.Infrastructure.ISystemClock { public static readonly Sentry.Infrastructure.SystemClock Clock; - [System.Obsolete("This constructor will become private in a future major version. Use the `SystemCl" + - "ock.Clock` singleton instead.")] - public SystemClock() { } public System.DateTimeOffset GetUtcNow() { } } public class TraceDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger @@ -1501,8 +1415,7 @@ namespace Sentry.PlatformAbstractions public class Runtime : System.IEquatable { public Runtime(string? name = null, string? version = null, string? raw = null, string? identifier = null) { } - [set: System.Obsolete("This setter is nonfunctional, and will be removed in a future version.")] - public string? Identifier { get; set; } + public string? Identifier { get; } public string? Name { get; } public string? Raw { get; } public string? Version { get; } @@ -1544,6 +1457,20 @@ namespace Sentry.Protocol public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Browser FromJson(System.Text.Json.JsonElement json) { } } + public sealed class DebugImage : Sentry.IJsonSerializable + { + public DebugImage() { } + public string? CodeFile { get; set; } + public string? CodeId { get; set; } + public string? DebugChecksum { get; set; } + public string? DebugFile { get; set; } + public string? DebugId { get; set; } + public long? ImageAddress { get; set; } + public long? ImageSize { get; set; } + public string? Type { get; set; } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } + public static Sentry.Protocol.DebugImage FromJson(System.Text.Json.JsonElement json) { } + } public sealed class Device : Sentry.IJsonSerializable { public const string Type = "device"; @@ -1690,17 +1617,12 @@ namespace Sentry.Protocol public string? Name { get; set; } public string? RawDescription { get; set; } public string? Version { get; set; } - [System.Obsolete("This method will be made internal in a future version.")] - public Sentry.Protocol.Runtime Clone() { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Runtime FromJson(System.Text.Json.JsonElement json) { } } public sealed class SentryException : Sentry.IJsonSerializable { public SentryException() { } - [System.Obsolete("Use SentryException.Mechanism.Data instead. This property will be removed in a fu" + - "ture version.")] - public System.Collections.Generic.IDictionary Data { get; } public Sentry.Protocol.Mechanism? Mechanism { get; set; } public string? Module { get; set; } public Sentry.SentryStackTrace? Stacktrace { get; set; } @@ -1766,14 +1688,6 @@ namespace Sentry.Protocol.Envelopes System.Threading.Tasks.Task SerializeAsync(System.IO.Stream stream, Sentry.Extensibility.IDiagnosticLogger? logger, System.Threading.CancellationToken cancellationToken = default); } } -namespace Sentry.Reflection -{ - [System.Obsolete("Should not be public. This method will be removed in version 4.")] - public static class AssemblyExtensions - { - public static Sentry.SdkVersion GetNameAndVersion(this System.Reflection.Assembly asm) { } - } -} public static class SentryExceptionExtensions { public static void AddSentryContext(this System.Exception ex, string name, System.Collections.Generic.IReadOnlyDictionary data) { } diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt index 35c9c5b579..02c6e3474e 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet7_0.verified.txt @@ -61,17 +61,32 @@ namespace Sentry public const string Platform = "csharp"; public const int ProtocolVersion = 7; } - public sealed class Contexts : System.Collections.Concurrent.ConcurrentDictionary, Sentry.IJsonSerializable + public sealed class Contexts : Sentry.IJsonSerializable, System.Collections.Generic.ICollection>, System.Collections.Generic.IDictionary, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable { public Contexts() { } public Sentry.Protocol.App App { get; } public Sentry.Protocol.Browser Browser { get; } + public int Count { get; } public Sentry.Protocol.Device Device { get; } public Sentry.Protocol.Gpu Gpu { get; } + public bool IsReadOnly { get; } + public object this[string key] { get; set; } + public System.Collections.Generic.ICollection Keys { get; } public Sentry.Protocol.OperatingSystem OperatingSystem { get; } public Sentry.Protocol.Response Response { get; } public Sentry.Protocol.Runtime Runtime { get; } public Sentry.Protocol.Trace Trace { get; } + public System.Collections.Generic.ICollection Values { get; } + public void Add(System.Collections.Generic.KeyValuePair item) { } + public void Add(string key, object value) { } + public void Clear() { } + public bool Contains(System.Collections.Generic.KeyValuePair item) { } + public bool ContainsKey(string key) { } + public void CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { } + public System.Collections.Generic.IEnumerator> GetEnumerator() { } + public bool Remove(System.Collections.Generic.KeyValuePair item) { } + public bool Remove(string key) { } + public bool TryGetValue(string key, out object value) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Contexts FromJson(System.Text.Json.JsonElement json) { } } @@ -82,20 +97,6 @@ namespace Sentry Managed = 0, ManagedBackgroundThread = 1, } - public sealed class DebugImage : Sentry.IJsonSerializable - { - public DebugImage() { } - public string? CodeFile { get; set; } - public string? CodeId { get; set; } - public string? DebugChecksum { get; set; } - public string? DebugFile { get; set; } - public string? DebugId { get; set; } - public string? ImageAddress { get; set; } - public long? ImageSize { get; set; } - public string? Type { get; set; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - public static Sentry.DebugImage FromJson(System.Text.Json.JsonElement json) { } - } [System.Flags] public enum DeduplicateMode { @@ -118,6 +119,9 @@ namespace Sentry } public static class EventLikeExtensions { + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category, string? type, System.ValueTuple? dataPair = default, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static bool HasUser(this Sentry.IEventLike eventLike) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, System.Collections.Generic.IEnumerable fingerprint) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, params string[] fingerprint) { } @@ -128,12 +132,6 @@ namespace Sentry public FileAttachmentContent(string filePath, bool readFileAsynchronously) { } public System.IO.Stream GetStream() { } } - public static class HasBreadcrumbsExtensions - { - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category, string? type, System.ValueTuple? dataPair = default, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - } public static class HasExtraExtensions { public static void SetExtras(this Sentry.IHasExtra hasExtra, System.Collections.Generic.IEnumerable> values) { } @@ -182,32 +180,29 @@ namespace Sentry public static Sentry.SentryId CaptureMessage(this Sentry.IHub hub, string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void LockScope(this Sentry.IHub hub) { } public static System.IDisposable PushAndLockScope(this Sentry.IHub hub) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } public static void UnlockScope(this Sentry.IHub hub) { } } public interface IAttachmentContent { System.IO.Stream GetStream(); } - public interface IEventLike : Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public interface IEventLike : Sentry.IHasExtra, Sentry.IHasTags { + System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } Sentry.Contexts Contexts { get; set; } + string? Distribution { get; set; } string? Environment { get; set; } System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } Sentry.SentryLevel? Level { get; set; } - string? Platform { get; set; } string? Release { get; set; } Sentry.Request Request { get; set; } Sentry.SdkVersion Sdk { get; } string? TransactionName { get; set; } Sentry.User User { get; set; } - } - public interface IHasBreadcrumbs - { - System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } void AddBreadcrumb(Sentry.Breadcrumb breadcrumb); } public interface IHasExtra @@ -221,15 +216,12 @@ namespace Sentry void SetTag(string key, string value); void UnsetTag(string key); } - public interface IHasTransactionNameSource - { - Sentry.TransactionNameSource NameSource { get; } - } public interface IHub : Sentry.ISentryClient, Sentry.ISentryScopeManager { Sentry.SentryId LastEventId { get; } void BindException(System.Exception exception, Sentry.ISpan span); Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope); Sentry.TransactionContext ContinueTrace(Sentry.SentryTraceHeader? traceHeader, Sentry.BaggageHeader? baggageHeader, string? name = null, string? operation = null); Sentry.TransactionContext ContinueTrace(string? traceHeader, string? baggageHeader, string? name = null, string? operation = null); void EndSession(Sentry.SessionEndStatus status = 0); @@ -239,7 +231,7 @@ namespace Sentry void PauseSession(); void ResumeSession(); void StartSession(); - Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); + Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); } public interface IJsonSerializable { @@ -256,11 +248,10 @@ namespace Sentry public interface ISentryClient { bool IsEnabled { get; } - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null); - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null); void CaptureSession(Sentry.SessionUpdate sessionUpdate); void CaptureTransaction(Sentry.Transaction transaction); - void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint); + void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint); void CaptureUserFeedback(Sentry.UserFeedback userFeedback); System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout); } @@ -271,9 +262,6 @@ namespace Sentry System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope); System.IDisposable PushScope(); System.IDisposable PushScope(TState state); - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - void WithScope(System.Action scopeCallback); } public interface ISentryScopeStateProcessor { @@ -294,7 +282,7 @@ namespace Sentry System.DateTimeOffset StartTimestamp { get; } string? UserAgent { get; } } - public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext { new string? Description { get; set; } new string Operation { get; set; } @@ -305,27 +293,32 @@ namespace Sentry void Finish(System.Exception exception, Sentry.SpanStatus status); Sentry.ISpan StartChild(string operation); } - public interface ISpanContext : Sentry.Protocol.ITraceContext { } - public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.Protocol.ITraceContext { System.DateTimeOffset? EndTimestamp { get; } bool IsFinished { get; } + System.Collections.Generic.IReadOnlyDictionary Measurements { get; } System.DateTimeOffset StartTimestamp { get; } Sentry.SentryTraceHeader GetTraceHeader(); + void SetMeasurement(string name, Sentry.Protocol.Measurement measurement); + } + public interface ITransactionContext : Sentry.Protocol.ITraceContext + { + bool? IsParentSampled { get; } + string Name { get; } + Sentry.TransactionNameSource NameSource { get; } } - public interface ITransaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public interface ITransactionData : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + { + string? Platform { get; set; } + } + public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { new bool? IsParentSampled { get; set; } new string Name { get; set; } System.Collections.Generic.IReadOnlyCollection Spans { get; } Sentry.ISpan? GetLastActiveSpan(); } - public interface ITransactionContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext - { - bool? IsParentSampled { get; } - string Name { get; } - } - public interface ITransactionData : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { } public enum InstructionAddressAdjustment { Auto = 0, @@ -338,14 +331,6 @@ namespace Sentry Sentry = 0, OpenTelemetry = 1, } - public static class MeasurementExtensions - { - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, double value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, int value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, long value, Sentry.MeasurementUnit unit = default) { } - [System.CLSCompliant(false)] - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, ulong value, Sentry.MeasurementUnit unit = default) { } - } public readonly struct MeasurementUnit : System.IEquatable { public static Sentry.MeasurementUnit None; @@ -425,7 +410,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Request FromJson(System.Text.Json.JsonElement json) { } } - public class Scope : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public class Scope : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags { public Scope(Sentry.SentryOptions? options) { } public System.Collections.Generic.IReadOnlyCollection Attachments { get; } @@ -436,13 +421,12 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } public Sentry.SentryLevel? Level { get; set; } - public string? Platform { get; set; } public string? Release { get; set; } public Sentry.Request Request { get; set; } public Sentry.SdkVersion Sdk { get; } public Sentry.ISpan? Span { get; set; } public System.Collections.Generic.IReadOnlyDictionary Tags { get; } - public Sentry.ITransaction? Transaction { get; set; } + public Sentry.ITransactionTracer? Transaction { get; set; } public string? TransactionName { get; set; } public Sentry.User User { get; set; } public void AddAttachment(Sentry.Attachment attachment) { } @@ -455,8 +439,6 @@ namespace Sentry public void ClearAttachments() { } public void ClearBreadcrumbs() { } public Sentry.Scope Clone() { } - [System.Obsolete("Use the Span property instead. This method will be removed in a future release.")] - public Sentry.ISpan? GetSpan() { } public void SetExtra(string key, object? value) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } @@ -493,14 +475,11 @@ namespace Sentry { public SentryClient(Sentry.SentryOptions options) { } public bool IsEnabled { get; } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } - [System.Obsolete("Sentry client should not be explicitly disposed of. This method will be removed i" + - "n version 4.")] public void Dispose() { } public System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout) { } } @@ -514,13 +493,13 @@ namespace Sentry public static System.Threading.Tasks.Task FlushAsync(this Sentry.ISentryClient client) { } } [System.Diagnostics.DebuggerDisplay("{GetType().Name,nq}: {EventId,nq}")] - public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable + public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable { public SentryEvent() { } public SentryEvent(System.Exception? exception) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } - public System.Collections.Generic.List? DebugImages { get; set; } + public System.Collections.Generic.List? DebugImages { get; set; } public string? Distribution { get; set; } public string? Environment { get; set; } public Sentry.SentryId EventId { get; } @@ -624,20 +603,10 @@ namespace Sentry public bool AutoSessionTracking { get; set; } public System.TimeSpan AutoSessionTrackingInterval { get; set; } public Sentry.Extensibility.IBackgroundWorker? BackgroundWorker { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeBreadcrumb instea" + - "d.")] - public System.Func? BeforeBreadcrumb { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSend instead.")] - public System.Func? BeforeSend { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSendTransaction i" + - "nstead.")] - public System.Func? BeforeSendTransaction { get; set; } public string? CacheDirectoryPath { get; set; } public bool CaptureFailedRequests { get; set; } public System.Action? ConfigureClient { get; set; } public System.Func? CrashedLastRun { get; set; } - [System.Obsolete("Use CreateHttpMessageHandler instead")] - public System.Func? CreateHttpClientHandler { get; set; } public System.Func? CreateHttpMessageHandler { get; set; } public bool Debug { get; set; } public System.Net.DecompressionMethods DecompressionMethods { get; set; } @@ -659,16 +628,12 @@ namespace Sentry public bool IsEnvironmentUser { get; set; } public bool IsGlobalModeEnabled { get; set; } public bool JsonPreserveReferences { get; set; } - [System.Obsolete("This property is no longer used. It will be removed in a future version.")] - public bool KeepAggregateException { get; set; } public long MaxAttachmentSize { get; set; } public int MaxBreadcrumbs { get; set; } public int MaxCacheItems { get; set; } public int MaxQueueItems { get; set; } public Sentry.Extensibility.INetworkStatusListener? NetworkStatusListener { get; set; } public string? Release { get; set; } - [System.Obsolete("Use ReportAssembliesMode instead", false)] - public bool ReportAssemblies { get; set; } public Sentry.ReportAssembliesMode ReportAssembliesMode { get; set; } public bool RequestBodyCompressionBuffered { get; set; } public System.IO.Compression.CompressionLevel RequestBodyCompressionLevel { get; set; } @@ -681,12 +646,14 @@ namespace Sentry public System.TimeSpan ShutdownTimeout { get; set; } public Sentry.StackTraceMode StackTraceMode { get; set; } public System.Collections.Generic.ICollection TagFilters { get; set; } - public System.Collections.Generic.IList TracePropagationTargets { get; set; } + public System.Collections.Generic.IList TracePropagationTargets { get; set; } public double? TracesSampleRate { get; set; } public System.Func? TracesSampler { get; set; } public Sentry.Extensibility.ITransport? Transport { get; set; } public bool UseAsyncFileIO { get; set; } public void AddJsonConverter(System.Text.Json.Serialization.JsonConverter converter) { } + public void AddJsonSerializerContext(System.Func contextBuilder) + where T : System.Text.Json.Serialization.JsonSerializerContext { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } @@ -716,9 +683,6 @@ namespace Sentry public static void DisableAppDomainUnhandledExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableDiagnosticSourceIntegration(this Sentry.SentryOptions options) { } public static void DisableDuplicateEventDetection(this Sentry.SentryOptions options) { } - [System.Obsolete("Method has been renamed to DisableUnobservedTaskExceptionCapture. Please update " + - "usage.")] - public static void DisableTaskUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableWinUiUnhandledExceptionIntegration(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllEventProcessors(this Sentry.SentryOptions options) { } @@ -734,12 +698,6 @@ namespace Sentry where TProcessor : Sentry.Extensibility.ISentryTransactionProcessor { } public static Sentry.SentryOptions UseStackTraceFactory(this Sentry.SentryOptions options, Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } } - public static class SentryScopeManagerExtensions - { - public static T? WithScope(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func> scopeCallback) { } - } public static class SentrySdk { public static bool IsEnabled { get; } @@ -749,17 +707,16 @@ namespace Sentry public static void AddBreadcrumb(Sentry.Infrastructure.ISystemClock? clock, string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static void BindClient(Sentry.ISentryClient client) { } public static void BindException(System.Exception exception, Sentry.ISpan span) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public static Sentry.SentryId CaptureException(System.Exception exception) { } public static Sentry.SentryId CaptureException(System.Exception exception, System.Action configureScope) { } public static Sentry.SentryId CaptureMessage(string message, Sentry.SentryLevel level = 1) { } public static Sentry.SentryId CaptureMessage(string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public static void CaptureTransaction(Sentry.Transaction transaction) { } - public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public static void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public static void CaptureUserFeedback(Sentry.SentryId eventId, string email, string comments, string? name = null) { } [System.Obsolete("WARNING: This method deliberately causes a crash, and should not be used in a rea" + @@ -787,23 +744,11 @@ namespace Sentry public static System.IDisposable PushScope(TState state) { } public static void ResumeSession() { } public static void StartSession() { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public static Sentry.ITransaction StartTransaction(string name, string operation) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, string? description) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, string? description) { } } public sealed class SentryStackFrame : Sentry.IJsonSerializable { @@ -815,12 +760,10 @@ namespace Sentry public string? FileName { get; set; } public System.Collections.Generic.IList FramesOmitted { get; } public string? Function { get; set; } - public string? FunctionId { get; set; } - public long ImageAddress { get; set; } + public long? FunctionId { get; set; } + public long? ImageAddress { get; set; } public bool? InApp { get; set; } - public string? InstructionAddress { get; set; } - [System.Obsolete("This property is unused and will be removed in the future.")] - public long? InstructionOffset { get; set; } + public long? InstructionAddress { get; set; } public int? LineNumber { get; set; } public string? Module { get; set; } public string? Package { get; set; } @@ -861,12 +804,6 @@ namespace Sentry public override string ToString() { } public static Sentry.SentryTraceHeader Parse(string value) { } } - public sealed class SentryValues : Sentry.IJsonSerializable - { - public SentryValues(System.Collections.Generic.IEnumerable? values) { } - public System.Collections.Generic.IEnumerable Values { get; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - } public class Session : Sentry.ISession { public Session(string? distinctId, string release, string? environment) { } @@ -908,7 +845,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.SessionUpdate FromJson(System.Text.Json.JsonElement json) { } } - public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public Span(Sentry.ISpan tracer) { } public Span(Sentry.SpanId? parentSpanId, string operation) { } @@ -917,6 +854,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -926,14 +864,15 @@ namespace Sentry public Sentry.SentryId TraceId { get; } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Span FromJson(System.Text.Json.JsonElement json) { } } - public class SpanContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public class SpanContext : Sentry.Protocol.ITraceContext { - public SpanContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled) { } + public SpanContext(string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = null, Sentry.SpanStatus? status = default, bool? isSampled = default) { } public string? Description { get; } public Sentry.Instrumenter Instrumenter { get; } public bool? IsSampled { get; } @@ -943,9 +882,17 @@ namespace Sentry public Sentry.SpanStatus? Status { get; } public Sentry.SentryId TraceId { get; } } + public static class SpanDataExtensions + { + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, double value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, int value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, long value, Sentry.MeasurementUnit unit = default) { } + [System.CLSCompliant(false)] + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, ulong value, Sentry.MeasurementUnit unit = default) { } + } public static class SpanExtensions { - public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } + public static Sentry.ITransactionTracer GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable @@ -985,7 +932,7 @@ namespace Sentry OutOfRange = 15, DataLoss = 16, } - public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { } public string? Description { get; set; } @@ -993,6 +940,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -1006,6 +954,7 @@ namespace Sentry public void Finish(System.Exception exception, Sentry.SpanStatus status) { } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public Sentry.ISpan StartChild(string operation) { } public void UnsetTag(string key) { } @@ -1036,15 +985,9 @@ namespace Sentry public override string ToString() { } public static Sentry.SubstringOrRegexPattern op_Implicit(string substringOrRegexPattern) { } } - [System.ComponentModel.TypeConverter(typeof(Sentry.TracePropagationTargetTypeConverter))] - public class TracePropagationTarget : Sentry.SubstringOrRegexPattern + public class Transaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { - public TracePropagationTarget(System.Text.RegularExpressions.Regex regex) { } - public TracePropagationTarget(string substringOrRegexPattern, System.StringComparison comparison = 5) { } - } - public class Transaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext - { - public Transaction(Sentry.ITransaction tracer) { } + public Transaction(Sentry.ITransactionTracer tracer) { } public Transaction(string name, string operation) { } public Transaction(string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } @@ -1086,16 +1029,9 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Transaction FromJson(System.Text.Json.JsonElement json) { } } - public class TransactionContext : Sentry.SpanContext, Sentry.IHasTransactionNameSource, Sentry.ISpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + public class TransactionContext : Sentry.SpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { - public TransactionContext(string name, string operation) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public TransactionContext(string name, string operation, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(string name, string operation, bool? isSampled) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled, Sentry.TransactionNameSource nameSource) { } + public TransactionContext(string name, string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = "", Sentry.SpanStatus? status = default, bool? isSampled = default, bool? isParentSampled = default, Sentry.TransactionNameSource nameSource = 0) { } public bool? IsParentSampled { get; } public string Name { get; set; } public Sentry.TransactionNameSource NameSource { get; set; } @@ -1115,11 +1051,9 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; } public Sentry.ITransactionContext TransactionContext { get; } } - public class TransactionTracer : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransaction, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public class TransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext { public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } public string? Description { get; set; } @@ -1225,12 +1159,14 @@ namespace Sentry.Extensibility public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2) { } public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } - public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } @@ -1246,12 +1182,12 @@ namespace Sentry.Extensibility public Sentry.SentryId LastEventId { get; } public void BindClient(Sentry.ISentryClient client) { } public void BindException(System.Exception exception, Sentry.ISpan span) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1268,8 +1204,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public void WithScope(System.Action scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public class FormRequestPayloadExtractor : Sentry.Extensibility.BaseRequestPayloadExtractor { @@ -1289,11 +1224,12 @@ namespace Sentry.Extensibility public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope, Sentry.Hint? hint = null) { } public Sentry.SentryId CaptureException(System.Exception exception) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback sentryUserFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1309,19 +1245,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public interface IBackgroundWorker { @@ -1430,13 +1354,6 @@ namespace Sentry.Infrastructure public ConsoleDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } protected override void LogMessage(string message) { } } - [System.Obsolete("Logger doesn\'t work outside of Sentry SDK. Please use TraceDiagnosticLogger inste" + - "ad")] - public class DebugDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger - { - public DebugDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } - protected override void LogMessage(string message) { } - } public abstract class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger { protected DiagnosticLogger(Sentry.SentryLevel minimalLevel) { } @@ -1457,9 +1374,6 @@ namespace Sentry.Infrastructure public sealed class SystemClock : Sentry.Infrastructure.ISystemClock { public static readonly Sentry.Infrastructure.SystemClock Clock; - [System.Obsolete("This constructor will become private in a future major version. Use the `SystemCl" + - "ock.Clock` singleton instead.")] - public SystemClock() { } public System.DateTimeOffset GetUtcNow() { } } public class TraceDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger @@ -1501,8 +1415,7 @@ namespace Sentry.PlatformAbstractions public class Runtime : System.IEquatable { public Runtime(string? name = null, string? version = null, string? raw = null, string? identifier = null) { } - [set: System.Obsolete("This setter is nonfunctional, and will be removed in a future version.")] - public string? Identifier { get; set; } + public string? Identifier { get; } public string? Name { get; } public string? Raw { get; } public string? Version { get; } @@ -1544,6 +1457,20 @@ namespace Sentry.Protocol public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Browser FromJson(System.Text.Json.JsonElement json) { } } + public sealed class DebugImage : Sentry.IJsonSerializable + { + public DebugImage() { } + public string? CodeFile { get; set; } + public string? CodeId { get; set; } + public string? DebugChecksum { get; set; } + public string? DebugFile { get; set; } + public string? DebugId { get; set; } + public long? ImageAddress { get; set; } + public long? ImageSize { get; set; } + public string? Type { get; set; } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } + public static Sentry.Protocol.DebugImage FromJson(System.Text.Json.JsonElement json) { } + } public sealed class Device : Sentry.IJsonSerializable { public const string Type = "device"; @@ -1690,17 +1617,12 @@ namespace Sentry.Protocol public string? Name { get; set; } public string? RawDescription { get; set; } public string? Version { get; set; } - [System.Obsolete("This method will be made internal in a future version.")] - public Sentry.Protocol.Runtime Clone() { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Runtime FromJson(System.Text.Json.JsonElement json) { } } public sealed class SentryException : Sentry.IJsonSerializable { public SentryException() { } - [System.Obsolete("Use SentryException.Mechanism.Data instead. This property will be removed in a fu" + - "ture version.")] - public System.Collections.Generic.IDictionary Data { get; } public Sentry.Protocol.Mechanism? Mechanism { get; set; } public string? Module { get; set; } public Sentry.SentryStackTrace? Stacktrace { get; set; } @@ -1766,14 +1688,6 @@ namespace Sentry.Protocol.Envelopes System.Threading.Tasks.Task SerializeAsync(System.IO.Stream stream, Sentry.Extensibility.IDiagnosticLogger? logger, System.Threading.CancellationToken cancellationToken = default); } } -namespace Sentry.Reflection -{ - [System.Obsolete("Should not be public. This method will be removed in version 4.")] - public static class AssemblyExtensions - { - public static Sentry.SdkVersion GetNameAndVersion(this System.Reflection.Assembly asm) { } - } -} public static class SentryExceptionExtensions { public static void AddSentryContext(this System.Exception ex, string name, System.Collections.Generic.IReadOnlyDictionary data) { } diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt similarity index 85% rename from test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt rename to test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt index a2dfb8a22f..02c6e3474e 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.Core3_1.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.DotNet8_0.verified.txt @@ -61,17 +61,32 @@ namespace Sentry public const string Platform = "csharp"; public const int ProtocolVersion = 7; } - public sealed class Contexts : System.Collections.Concurrent.ConcurrentDictionary, Sentry.IJsonSerializable + public sealed class Contexts : Sentry.IJsonSerializable, System.Collections.Generic.ICollection>, System.Collections.Generic.IDictionary, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable { public Contexts() { } public Sentry.Protocol.App App { get; } public Sentry.Protocol.Browser Browser { get; } + public int Count { get; } public Sentry.Protocol.Device Device { get; } public Sentry.Protocol.Gpu Gpu { get; } + public bool IsReadOnly { get; } + public object this[string key] { get; set; } + public System.Collections.Generic.ICollection Keys { get; } public Sentry.Protocol.OperatingSystem OperatingSystem { get; } public Sentry.Protocol.Response Response { get; } public Sentry.Protocol.Runtime Runtime { get; } public Sentry.Protocol.Trace Trace { get; } + public System.Collections.Generic.ICollection Values { get; } + public void Add(System.Collections.Generic.KeyValuePair item) { } + public void Add(string key, object value) { } + public void Clear() { } + public bool Contains(System.Collections.Generic.KeyValuePair item) { } + public bool ContainsKey(string key) { } + public void CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { } + public System.Collections.Generic.IEnumerator> GetEnumerator() { } + public bool Remove(System.Collections.Generic.KeyValuePair item) { } + public bool Remove(string key) { } + public bool TryGetValue(string key, out object value) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Contexts FromJson(System.Text.Json.JsonElement json) { } } @@ -82,20 +97,6 @@ namespace Sentry Managed = 0, ManagedBackgroundThread = 1, } - public sealed class DebugImage : Sentry.IJsonSerializable - { - public DebugImage() { } - public string? CodeFile { get; set; } - public string? CodeId { get; set; } - public string? DebugChecksum { get; set; } - public string? DebugFile { get; set; } - public string? DebugId { get; set; } - public string? ImageAddress { get; set; } - public long? ImageSize { get; set; } - public string? Type { get; set; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - public static Sentry.DebugImage FromJson(System.Text.Json.JsonElement json) { } - } [System.Flags] public enum DeduplicateMode { @@ -118,6 +119,9 @@ namespace Sentry } public static class EventLikeExtensions { + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category, string? type, System.ValueTuple? dataPair = default, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static bool HasUser(this Sentry.IEventLike eventLike) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, System.Collections.Generic.IEnumerable fingerprint) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, params string[] fingerprint) { } @@ -128,12 +132,6 @@ namespace Sentry public FileAttachmentContent(string filePath, bool readFileAsynchronously) { } public System.IO.Stream GetStream() { } } - public static class HasBreadcrumbsExtensions - { - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category, string? type, System.ValueTuple? dataPair = default, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - } public static class HasExtraExtensions { public static void SetExtras(this Sentry.IHasExtra hasExtra, System.Collections.Generic.IEnumerable> values) { } @@ -182,32 +180,29 @@ namespace Sentry public static Sentry.SentryId CaptureMessage(this Sentry.IHub hub, string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void LockScope(this Sentry.IHub hub) { } public static System.IDisposable PushAndLockScope(this Sentry.IHub hub) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } public static void UnlockScope(this Sentry.IHub hub) { } } public interface IAttachmentContent { System.IO.Stream GetStream(); } - public interface IEventLike : Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public interface IEventLike : Sentry.IHasExtra, Sentry.IHasTags { + System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } Sentry.Contexts Contexts { get; set; } + string? Distribution { get; set; } string? Environment { get; set; } System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } Sentry.SentryLevel? Level { get; set; } - string? Platform { get; set; } string? Release { get; set; } Sentry.Request Request { get; set; } Sentry.SdkVersion Sdk { get; } string? TransactionName { get; set; } Sentry.User User { get; set; } - } - public interface IHasBreadcrumbs - { - System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } void AddBreadcrumb(Sentry.Breadcrumb breadcrumb); } public interface IHasExtra @@ -221,15 +216,12 @@ namespace Sentry void SetTag(string key, string value); void UnsetTag(string key); } - public interface IHasTransactionNameSource - { - Sentry.TransactionNameSource NameSource { get; } - } public interface IHub : Sentry.ISentryClient, Sentry.ISentryScopeManager { Sentry.SentryId LastEventId { get; } void BindException(System.Exception exception, Sentry.ISpan span); Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope); Sentry.TransactionContext ContinueTrace(Sentry.SentryTraceHeader? traceHeader, Sentry.BaggageHeader? baggageHeader, string? name = null, string? operation = null); Sentry.TransactionContext ContinueTrace(string? traceHeader, string? baggageHeader, string? name = null, string? operation = null); void EndSession(Sentry.SessionEndStatus status = 0); @@ -239,7 +231,7 @@ namespace Sentry void PauseSession(); void ResumeSession(); void StartSession(); - Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); + Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); } public interface IJsonSerializable { @@ -256,11 +248,10 @@ namespace Sentry public interface ISentryClient { bool IsEnabled { get; } - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null); - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null); void CaptureSession(Sentry.SessionUpdate sessionUpdate); void CaptureTransaction(Sentry.Transaction transaction); - void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint); + void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint); void CaptureUserFeedback(Sentry.UserFeedback userFeedback); System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout); } @@ -271,9 +262,6 @@ namespace Sentry System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope); System.IDisposable PushScope(); System.IDisposable PushScope(TState state); - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - void WithScope(System.Action scopeCallback); } public interface ISentryScopeStateProcessor { @@ -294,7 +282,7 @@ namespace Sentry System.DateTimeOffset StartTimestamp { get; } string? UserAgent { get; } } - public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext { new string? Description { get; set; } new string Operation { get; set; } @@ -305,27 +293,32 @@ namespace Sentry void Finish(System.Exception exception, Sentry.SpanStatus status); Sentry.ISpan StartChild(string operation); } - public interface ISpanContext : Sentry.Protocol.ITraceContext { } - public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.Protocol.ITraceContext { System.DateTimeOffset? EndTimestamp { get; } bool IsFinished { get; } + System.Collections.Generic.IReadOnlyDictionary Measurements { get; } System.DateTimeOffset StartTimestamp { get; } Sentry.SentryTraceHeader GetTraceHeader(); + void SetMeasurement(string name, Sentry.Protocol.Measurement measurement); + } + public interface ITransactionContext : Sentry.Protocol.ITraceContext + { + bool? IsParentSampled { get; } + string Name { get; } + Sentry.TransactionNameSource NameSource { get; } } - public interface ITransaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public interface ITransactionData : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + { + string? Platform { get; set; } + } + public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { new bool? IsParentSampled { get; set; } new string Name { get; set; } System.Collections.Generic.IReadOnlyCollection Spans { get; } Sentry.ISpan? GetLastActiveSpan(); } - public interface ITransactionContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext - { - bool? IsParentSampled { get; } - string Name { get; } - } - public interface ITransactionData : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { } public enum InstructionAddressAdjustment { Auto = 0, @@ -338,14 +331,6 @@ namespace Sentry Sentry = 0, OpenTelemetry = 1, } - public static class MeasurementExtensions - { - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, double value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, int value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, long value, Sentry.MeasurementUnit unit = default) { } - [System.CLSCompliant(false)] - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, ulong value, Sentry.MeasurementUnit unit = default) { } - } public readonly struct MeasurementUnit : System.IEquatable { public static Sentry.MeasurementUnit None; @@ -425,7 +410,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Request FromJson(System.Text.Json.JsonElement json) { } } - public class Scope : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public class Scope : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags { public Scope(Sentry.SentryOptions? options) { } public System.Collections.Generic.IReadOnlyCollection Attachments { get; } @@ -436,13 +421,12 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } public Sentry.SentryLevel? Level { get; set; } - public string? Platform { get; set; } public string? Release { get; set; } public Sentry.Request Request { get; set; } public Sentry.SdkVersion Sdk { get; } public Sentry.ISpan? Span { get; set; } public System.Collections.Generic.IReadOnlyDictionary Tags { get; } - public Sentry.ITransaction? Transaction { get; set; } + public Sentry.ITransactionTracer? Transaction { get; set; } public string? TransactionName { get; set; } public Sentry.User User { get; set; } public void AddAttachment(Sentry.Attachment attachment) { } @@ -455,8 +439,6 @@ namespace Sentry public void ClearAttachments() { } public void ClearBreadcrumbs() { } public Sentry.Scope Clone() { } - [System.Obsolete("Use the Span property instead. This method will be removed in a future release.")] - public Sentry.ISpan? GetSpan() { } public void SetExtra(string key, object? value) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } @@ -493,14 +475,11 @@ namespace Sentry { public SentryClient(Sentry.SentryOptions options) { } public bool IsEnabled { get; } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } - [System.Obsolete("Sentry client should not be explicitly disposed of. This method will be removed i" + - "n version 4.")] public void Dispose() { } public System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout) { } } @@ -514,13 +493,13 @@ namespace Sentry public static System.Threading.Tasks.Task FlushAsync(this Sentry.ISentryClient client) { } } [System.Diagnostics.DebuggerDisplay("{GetType().Name,nq}: {EventId,nq}")] - public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable + public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable { public SentryEvent() { } public SentryEvent(System.Exception? exception) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } - public System.Collections.Generic.List? DebugImages { get; set; } + public System.Collections.Generic.List? DebugImages { get; set; } public string? Distribution { get; set; } public string? Environment { get; set; } public Sentry.SentryId EventId { get; } @@ -612,6 +591,7 @@ namespace Sentry protected SentryMessageHandler(System.Net.Http.HttpMessageHandler innerHandler, Sentry.IHub hub) { } protected abstract void HandleResponse(System.Net.Http.HttpResponseMessage response, Sentry.ISpan? span, string method, string url); protected abstract Sentry.ISpan? ProcessRequest(System.Net.Http.HttpRequestMessage request, string method, string url); + protected override System.Net.Http.HttpResponseMessage Send(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { } protected override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { } } public class SentryOptions @@ -623,20 +603,10 @@ namespace Sentry public bool AutoSessionTracking { get; set; } public System.TimeSpan AutoSessionTrackingInterval { get; set; } public Sentry.Extensibility.IBackgroundWorker? BackgroundWorker { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeBreadcrumb instea" + - "d.")] - public System.Func? BeforeBreadcrumb { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSend instead.")] - public System.Func? BeforeSend { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSendTransaction i" + - "nstead.")] - public System.Func? BeforeSendTransaction { get; set; } public string? CacheDirectoryPath { get; set; } public bool CaptureFailedRequests { get; set; } public System.Action? ConfigureClient { get; set; } public System.Func? CrashedLastRun { get; set; } - [System.Obsolete("Use CreateHttpMessageHandler instead")] - public System.Func? CreateHttpClientHandler { get; set; } public System.Func? CreateHttpMessageHandler { get; set; } public bool Debug { get; set; } public System.Net.DecompressionMethods DecompressionMethods { get; set; } @@ -658,16 +628,12 @@ namespace Sentry public bool IsEnvironmentUser { get; set; } public bool IsGlobalModeEnabled { get; set; } public bool JsonPreserveReferences { get; set; } - [System.Obsolete("This property is no longer used. It will be removed in a future version.")] - public bool KeepAggregateException { get; set; } public long MaxAttachmentSize { get; set; } public int MaxBreadcrumbs { get; set; } public int MaxCacheItems { get; set; } public int MaxQueueItems { get; set; } public Sentry.Extensibility.INetworkStatusListener? NetworkStatusListener { get; set; } public string? Release { get; set; } - [System.Obsolete("Use ReportAssembliesMode instead", false)] - public bool ReportAssemblies { get; set; } public Sentry.ReportAssembliesMode ReportAssembliesMode { get; set; } public bool RequestBodyCompressionBuffered { get; set; } public System.IO.Compression.CompressionLevel RequestBodyCompressionLevel { get; set; } @@ -680,12 +646,14 @@ namespace Sentry public System.TimeSpan ShutdownTimeout { get; set; } public Sentry.StackTraceMode StackTraceMode { get; set; } public System.Collections.Generic.ICollection TagFilters { get; set; } - public System.Collections.Generic.IList TracePropagationTargets { get; set; } + public System.Collections.Generic.IList TracePropagationTargets { get; set; } public double? TracesSampleRate { get; set; } public System.Func? TracesSampler { get; set; } public Sentry.Extensibility.ITransport? Transport { get; set; } public bool UseAsyncFileIO { get; set; } public void AddJsonConverter(System.Text.Json.Serialization.JsonConverter converter) { } + public void AddJsonSerializerContext(System.Func contextBuilder) + where T : System.Text.Json.Serialization.JsonSerializerContext { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } @@ -715,10 +683,8 @@ namespace Sentry public static void DisableAppDomainUnhandledExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableDiagnosticSourceIntegration(this Sentry.SentryOptions options) { } public static void DisableDuplicateEventDetection(this Sentry.SentryOptions options) { } - [System.Obsolete("Method has been renamed to DisableUnobservedTaskExceptionCapture. Please update " + - "usage.")] - public static void DisableTaskUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } + public static void DisableWinUiUnhandledExceptionIntegration(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllEventProcessors(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllExceptionProcessors(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllTransactionProcessors(this Sentry.SentryOptions options) { } @@ -732,12 +698,6 @@ namespace Sentry where TProcessor : Sentry.Extensibility.ISentryTransactionProcessor { } public static Sentry.SentryOptions UseStackTraceFactory(this Sentry.SentryOptions options, Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } } - public static class SentryScopeManagerExtensions - { - public static T? WithScope(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func> scopeCallback) { } - } public static class SentrySdk { public static bool IsEnabled { get; } @@ -747,17 +707,16 @@ namespace Sentry public static void AddBreadcrumb(Sentry.Infrastructure.ISystemClock? clock, string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static void BindClient(Sentry.ISentryClient client) { } public static void BindException(System.Exception exception, Sentry.ISpan span) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public static Sentry.SentryId CaptureException(System.Exception exception) { } public static Sentry.SentryId CaptureException(System.Exception exception, System.Action configureScope) { } public static Sentry.SentryId CaptureMessage(string message, Sentry.SentryLevel level = 1) { } public static Sentry.SentryId CaptureMessage(string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public static void CaptureTransaction(Sentry.Transaction transaction) { } - public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public static void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public static void CaptureUserFeedback(Sentry.SentryId eventId, string email, string comments, string? name = null) { } [System.Obsolete("WARNING: This method deliberately causes a crash, and should not be used in a rea" + @@ -785,23 +744,11 @@ namespace Sentry public static System.IDisposable PushScope(TState state) { } public static void ResumeSession() { } public static void StartSession() { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public static Sentry.ITransaction StartTransaction(string name, string operation) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, string? description) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, string? description) { } } public sealed class SentryStackFrame : Sentry.IJsonSerializable { @@ -813,12 +760,10 @@ namespace Sentry public string? FileName { get; set; } public System.Collections.Generic.IList FramesOmitted { get; } public string? Function { get; set; } - public string? FunctionId { get; set; } - public long ImageAddress { get; set; } + public long? FunctionId { get; set; } + public long? ImageAddress { get; set; } public bool? InApp { get; set; } - public string? InstructionAddress { get; set; } - [System.Obsolete("This property is unused and will be removed in the future.")] - public long? InstructionOffset { get; set; } + public long? InstructionAddress { get; set; } public int? LineNumber { get; set; } public string? Module { get; set; } public string? Package { get; set; } @@ -859,12 +804,6 @@ namespace Sentry public override string ToString() { } public static Sentry.SentryTraceHeader Parse(string value) { } } - public sealed class SentryValues : Sentry.IJsonSerializable - { - public SentryValues(System.Collections.Generic.IEnumerable? values) { } - public System.Collections.Generic.IEnumerable Values { get; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - } public class Session : Sentry.ISession { public Session(string? distinctId, string release, string? environment) { } @@ -906,7 +845,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.SessionUpdate FromJson(System.Text.Json.JsonElement json) { } } - public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public Span(Sentry.ISpan tracer) { } public Span(Sentry.SpanId? parentSpanId, string operation) { } @@ -915,6 +854,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -924,14 +864,15 @@ namespace Sentry public Sentry.SentryId TraceId { get; } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Span FromJson(System.Text.Json.JsonElement json) { } } - public class SpanContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public class SpanContext : Sentry.Protocol.ITraceContext { - public SpanContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled) { } + public SpanContext(string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = null, Sentry.SpanStatus? status = default, bool? isSampled = default) { } public string? Description { get; } public Sentry.Instrumenter Instrumenter { get; } public bool? IsSampled { get; } @@ -941,9 +882,17 @@ namespace Sentry public Sentry.SpanStatus? Status { get; } public Sentry.SentryId TraceId { get; } } + public static class SpanDataExtensions + { + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, double value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, int value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, long value, Sentry.MeasurementUnit unit = default) { } + [System.CLSCompliant(false)] + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, ulong value, Sentry.MeasurementUnit unit = default) { } + } public static class SpanExtensions { - public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } + public static Sentry.ITransactionTracer GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable @@ -983,7 +932,7 @@ namespace Sentry OutOfRange = 15, DataLoss = 16, } - public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { } public string? Description { get; set; } @@ -991,6 +940,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -1004,6 +954,7 @@ namespace Sentry public void Finish(System.Exception exception, Sentry.SpanStatus status) { } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public Sentry.ISpan StartChild(string operation) { } public void UnsetTag(string key) { } @@ -1034,15 +985,9 @@ namespace Sentry public override string ToString() { } public static Sentry.SubstringOrRegexPattern op_Implicit(string substringOrRegexPattern) { } } - [System.ComponentModel.TypeConverter(typeof(Sentry.TracePropagationTargetTypeConverter))] - public class TracePropagationTarget : Sentry.SubstringOrRegexPattern + public class Transaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { - public TracePropagationTarget(System.Text.RegularExpressions.Regex regex) { } - public TracePropagationTarget(string substringOrRegexPattern, System.StringComparison comparison = 5) { } - } - public class Transaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext - { - public Transaction(Sentry.ITransaction tracer) { } + public Transaction(Sentry.ITransactionTracer tracer) { } public Transaction(string name, string operation) { } public Transaction(string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } @@ -1084,16 +1029,9 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Transaction FromJson(System.Text.Json.JsonElement json) { } } - public class TransactionContext : Sentry.SpanContext, Sentry.IHasTransactionNameSource, Sentry.ISpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + public class TransactionContext : Sentry.SpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { - public TransactionContext(string name, string operation) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public TransactionContext(string name, string operation, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(string name, string operation, bool? isSampled) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled, Sentry.TransactionNameSource nameSource) { } + public TransactionContext(string name, string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = "", Sentry.SpanStatus? status = default, bool? isSampled = default, bool? isParentSampled = default, Sentry.TransactionNameSource nameSource = 0) { } public bool? IsParentSampled { get; } public string Name { get; set; } public Sentry.TransactionNameSource NameSource { get; set; } @@ -1113,11 +1051,9 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; } public Sentry.ITransactionContext TransactionContext { get; } } - public class TransactionTracer : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransaction, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public class TransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext { public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } public string? Description { get; set; } @@ -1223,12 +1159,14 @@ namespace Sentry.Extensibility public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2) { } public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } - public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } @@ -1244,12 +1182,12 @@ namespace Sentry.Extensibility public Sentry.SentryId LastEventId { get; } public void BindClient(Sentry.ISentryClient client) { } public void BindException(System.Exception exception, Sentry.ISpan span) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1266,8 +1204,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public void WithScope(System.Action scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public class FormRequestPayloadExtractor : Sentry.Extensibility.BaseRequestPayloadExtractor { @@ -1287,11 +1224,12 @@ namespace Sentry.Extensibility public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope, Sentry.Hint? hint = null) { } public Sentry.SentryId CaptureException(System.Exception exception) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback sentryUserFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1307,19 +1245,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public interface IBackgroundWorker { @@ -1428,13 +1354,6 @@ namespace Sentry.Infrastructure public ConsoleDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } protected override void LogMessage(string message) { } } - [System.Obsolete("Logger doesn\'t work outside of Sentry SDK. Please use TraceDiagnosticLogger inste" + - "ad")] - public class DebugDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger - { - public DebugDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } - protected override void LogMessage(string message) { } - } public abstract class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger { protected DiagnosticLogger(Sentry.SentryLevel minimalLevel) { } @@ -1455,9 +1374,6 @@ namespace Sentry.Infrastructure public sealed class SystemClock : Sentry.Infrastructure.ISystemClock { public static readonly Sentry.Infrastructure.SystemClock Clock; - [System.Obsolete("This constructor will become private in a future major version. Use the `SystemCl" + - "ock.Clock` singleton instead.")] - public SystemClock() { } public System.DateTimeOffset GetUtcNow() { } } public class TraceDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger @@ -1499,8 +1415,7 @@ namespace Sentry.PlatformAbstractions public class Runtime : System.IEquatable { public Runtime(string? name = null, string? version = null, string? raw = null, string? identifier = null) { } - [set: System.Obsolete("This setter is nonfunctional, and will be removed in a future version.")] - public string? Identifier { get; set; } + public string? Identifier { get; } public string? Name { get; } public string? Raw { get; } public string? Version { get; } @@ -1542,6 +1457,20 @@ namespace Sentry.Protocol public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Browser FromJson(System.Text.Json.JsonElement json) { } } + public sealed class DebugImage : Sentry.IJsonSerializable + { + public DebugImage() { } + public string? CodeFile { get; set; } + public string? CodeId { get; set; } + public string? DebugChecksum { get; set; } + public string? DebugFile { get; set; } + public string? DebugId { get; set; } + public long? ImageAddress { get; set; } + public long? ImageSize { get; set; } + public string? Type { get; set; } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } + public static Sentry.Protocol.DebugImage FromJson(System.Text.Json.JsonElement json) { } + } public sealed class Device : Sentry.IJsonSerializable { public const string Type = "device"; @@ -1688,17 +1617,12 @@ namespace Sentry.Protocol public string? Name { get; set; } public string? RawDescription { get; set; } public string? Version { get; set; } - [System.Obsolete("This method will be made internal in a future version.")] - public Sentry.Protocol.Runtime Clone() { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Runtime FromJson(System.Text.Json.JsonElement json) { } } public sealed class SentryException : Sentry.IJsonSerializable { public SentryException() { } - [System.Obsolete("Use SentryException.Mechanism.Data instead. This property will be removed in a fu" + - "ture version.")] - public System.Collections.Generic.IDictionary Data { get; } public Sentry.Protocol.Mechanism? Mechanism { get; set; } public string? Module { get; set; } public Sentry.SentryStackTrace? Stacktrace { get; set; } @@ -1764,14 +1688,6 @@ namespace Sentry.Protocol.Envelopes System.Threading.Tasks.Task SerializeAsync(System.IO.Stream stream, Sentry.Extensibility.IDiagnosticLogger? logger, System.Threading.CancellationToken cancellationToken = default); } } -namespace Sentry.Reflection -{ - [System.Obsolete("Should not be public. This method will be removed in version 4.")] - public static class AssemblyExtensions - { - public static Sentry.SdkVersion GetNameAndVersion(this System.Reflection.Assembly asm) { } - } -} public static class SentryExceptionExtensions { public static void AddSentryContext(this System.Exception ex, string name, System.Collections.Generic.IReadOnlyDictionary data) { } diff --git a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt index de410455df..c1beabccf8 100644 --- a/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt +++ b/test/Sentry.Tests/ApiApprovalTests.Run.Net4_8.verified.txt @@ -61,17 +61,32 @@ namespace Sentry public const string Platform = "csharp"; public const int ProtocolVersion = 7; } - public sealed class Contexts : System.Collections.Concurrent.ConcurrentDictionary, Sentry.IJsonSerializable + public sealed class Contexts : Sentry.IJsonSerializable, System.Collections.Generic.ICollection>, System.Collections.Generic.IDictionary, System.Collections.Generic.IEnumerable>, System.Collections.IEnumerable { public Contexts() { } public Sentry.Protocol.App App { get; } public Sentry.Protocol.Browser Browser { get; } + public int Count { get; } public Sentry.Protocol.Device Device { get; } public Sentry.Protocol.Gpu Gpu { get; } + public bool IsReadOnly { get; } + public object this[string key] { get; set; } + public System.Collections.Generic.ICollection Keys { get; } public Sentry.Protocol.OperatingSystem OperatingSystem { get; } public Sentry.Protocol.Response Response { get; } public Sentry.Protocol.Runtime Runtime { get; } public Sentry.Protocol.Trace Trace { get; } + public System.Collections.Generic.ICollection Values { get; } + public void Add(System.Collections.Generic.KeyValuePair item) { } + public void Add(string key, object value) { } + public void Clear() { } + public bool Contains(System.Collections.Generic.KeyValuePair item) { } + public bool ContainsKey(string key) { } + public void CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { } + public System.Collections.Generic.IEnumerator> GetEnumerator() { } + public bool Remove(System.Collections.Generic.KeyValuePair item) { } + public bool Remove(string key) { } + public bool TryGetValue(string key, out object value) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Contexts FromJson(System.Text.Json.JsonElement json) { } } @@ -82,20 +97,6 @@ namespace Sentry Managed = 0, ManagedBackgroundThread = 1, } - public sealed class DebugImage : Sentry.IJsonSerializable - { - public DebugImage() { } - public string? CodeFile { get; set; } - public string? CodeId { get; set; } - public string? DebugChecksum { get; set; } - public string? DebugFile { get; set; } - public string? DebugId { get; set; } - public string? ImageAddress { get; set; } - public long? ImageSize { get; set; } - public string? Type { get; set; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - public static Sentry.DebugImage FromJson(System.Text.Json.JsonElement json) { } - } [System.Flags] public enum DeduplicateMode { @@ -118,6 +119,8 @@ namespace Sentry } public static class EventLikeExtensions { + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } + public static void AddBreadcrumb(this Sentry.IEventLike eventLike, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static bool HasUser(this Sentry.IEventLike eventLike) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, System.Collections.Generic.IEnumerable fingerprint) { } public static void SetFingerprint(this Sentry.IEventLike eventLike, params string[] fingerprint) { } @@ -128,11 +131,6 @@ namespace Sentry public FileAttachmentContent(string filePath, bool readFileAsynchronously) { } public System.IO.Stream GetStream() { } } - public static class HasBreadcrumbsExtensions - { - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - public static void AddBreadcrumb(this Sentry.IHasBreadcrumbs hasBreadcrumbs, System.DateTimeOffset? timestamp, string message, string? category = null, string? type = null, System.Collections.Generic.IReadOnlyDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } - } public static class HasExtraExtensions { public static void SetExtras(this Sentry.IHasExtra hasExtra, System.Collections.Generic.IEnumerable> values) { } @@ -181,32 +179,29 @@ namespace Sentry public static Sentry.SentryId CaptureMessage(this Sentry.IHub hub, string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void LockScope(this Sentry.IHub hub) { } public static System.IDisposable PushAndLockScope(this Sentry.IHub hub) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(this Sentry.IHub hub, string name, string operation, string? description) { } public static void UnlockScope(this Sentry.IHub hub) { } } public interface IAttachmentContent { System.IO.Stream GetStream(); } - public interface IEventLike : Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public interface IEventLike : Sentry.IHasExtra, Sentry.IHasTags { + System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } Sentry.Contexts Contexts { get; set; } + string? Distribution { get; set; } string? Environment { get; set; } System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } Sentry.SentryLevel? Level { get; set; } - string? Platform { get; set; } string? Release { get; set; } Sentry.Request Request { get; set; } Sentry.SdkVersion Sdk { get; } string? TransactionName { get; set; } Sentry.User User { get; set; } - } - public interface IHasBreadcrumbs - { - System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } void AddBreadcrumb(Sentry.Breadcrumb breadcrumb); } public interface IHasExtra @@ -220,15 +215,12 @@ namespace Sentry void SetTag(string key, string value); void UnsetTag(string key); } - public interface IHasTransactionNameSource - { - Sentry.TransactionNameSource NameSource { get; } - } public interface IHub : Sentry.ISentryClient, Sentry.ISentryScopeManager { Sentry.SentryId LastEventId { get; } void BindException(System.Exception exception, Sentry.ISpan span); Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope); Sentry.TransactionContext ContinueTrace(Sentry.SentryTraceHeader? traceHeader, Sentry.BaggageHeader? baggageHeader, string? name = null, string? operation = null); Sentry.TransactionContext ContinueTrace(string? traceHeader, string? baggageHeader, string? name = null, string? operation = null); void EndSession(Sentry.SessionEndStatus status = 0); @@ -238,7 +230,7 @@ namespace Sentry void PauseSession(); void ResumeSession(); void StartSession(); - Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); + Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext); } public interface IJsonSerializable { @@ -255,11 +247,10 @@ namespace Sentry public interface ISentryClient { bool IsEnabled { get; } - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null); - Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null); + Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null); void CaptureSession(Sentry.SessionUpdate sessionUpdate); void CaptureTransaction(Sentry.Transaction transaction); - void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint); + void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint); void CaptureUserFeedback(Sentry.UserFeedback userFeedback); System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout); } @@ -270,9 +261,6 @@ namespace Sentry System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope); System.IDisposable PushScope(); System.IDisposable PushScope(TState state); - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - void WithScope(System.Action scopeCallback); } public interface ISentryScopeStateProcessor { @@ -293,7 +281,7 @@ namespace Sentry System.DateTimeOffset StartTimestamp { get; } string? UserAgent { get; } } - public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public interface ISpan : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.Protocol.ITraceContext { new string? Description { get; set; } new string Operation { get; set; } @@ -304,27 +292,32 @@ namespace Sentry void Finish(System.Exception exception, Sentry.SpanStatus status); Sentry.ISpan StartChild(string operation); } - public interface ISpanContext : Sentry.Protocol.ITraceContext { } - public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public interface ISpanData : Sentry.IHasExtra, Sentry.IHasTags, Sentry.Protocol.ITraceContext { System.DateTimeOffset? EndTimestamp { get; } bool IsFinished { get; } + System.Collections.Generic.IReadOnlyDictionary Measurements { get; } System.DateTimeOffset StartTimestamp { get; } Sentry.SentryTraceHeader GetTraceHeader(); + void SetMeasurement(string name, Sentry.Protocol.Measurement measurement); + } + public interface ITransactionContext : Sentry.Protocol.ITraceContext + { + bool? IsParentSampled { get; } + string Name { get; } + Sentry.TransactionNameSource NameSource { get; } } - public interface ITransaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public interface ITransactionData : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + { + string? Platform { get; set; } + } + public interface ITransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { new bool? IsParentSampled { get; set; } new string Name { get; set; } System.Collections.Generic.IReadOnlyCollection Spans { get; } Sentry.ISpan? GetLastActiveSpan(); } - public interface ITransactionContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext - { - bool? IsParentSampled { get; } - string Name { get; } - } - public interface ITransactionData : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { } public enum InstructionAddressAdjustment { Auto = 0, @@ -337,14 +330,6 @@ namespace Sentry Sentry = 0, OpenTelemetry = 1, } - public static class MeasurementExtensions - { - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, double value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, int value, Sentry.MeasurementUnit unit = default) { } - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, long value, Sentry.MeasurementUnit unit = default) { } - [System.CLSCompliant(false)] - public static void SetMeasurement(this Sentry.ITransactionData transaction, string name, ulong value, Sentry.MeasurementUnit unit = default) { } - } public readonly struct MeasurementUnit : System.IEquatable { public static Sentry.MeasurementUnit None; @@ -424,7 +409,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Request FromJson(System.Text.Json.JsonElement json) { } } - public class Scope : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags + public class Scope : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags { public Scope(Sentry.SentryOptions? options) { } public System.Collections.Generic.IReadOnlyCollection Attachments { get; } @@ -435,13 +420,12 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public System.Collections.Generic.IReadOnlyList Fingerprint { get; set; } public Sentry.SentryLevel? Level { get; set; } - public string? Platform { get; set; } public string? Release { get; set; } public Sentry.Request Request { get; set; } public Sentry.SdkVersion Sdk { get; } public Sentry.ISpan? Span { get; set; } public System.Collections.Generic.IReadOnlyDictionary Tags { get; } - public Sentry.ITransaction? Transaction { get; set; } + public Sentry.ITransactionTracer? Transaction { get; set; } public string? TransactionName { get; set; } public Sentry.User User { get; set; } public void AddAttachment(Sentry.Attachment attachment) { } @@ -454,8 +438,6 @@ namespace Sentry public void ClearAttachments() { } public void ClearBreadcrumbs() { } public Sentry.Scope Clone() { } - [System.Obsolete("Use the Span property instead. This method will be removed in a future release.")] - public Sentry.ISpan? GetSpan() { } public void SetExtra(string key, object? value) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } @@ -492,14 +474,11 @@ namespace Sentry { public SentryClient(Sentry.SentryOptions options) { } public bool IsEnabled { get; } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent? @event, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } - [System.Obsolete("Sentry client should not be explicitly disposed of. This method will be removed i" + - "n version 4.")] public void Dispose() { } public System.Threading.Tasks.Task FlushAsync(System.TimeSpan timeout) { } } @@ -513,13 +492,13 @@ namespace Sentry public static System.Threading.Tasks.Task FlushAsync(this Sentry.ISentryClient client) { } } [System.Diagnostics.DebuggerDisplay("{GetType().Name,nq}: {EventId,nq}")] - public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable + public sealed class SentryEvent : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable { public SentryEvent() { } public SentryEvent(System.Exception? exception) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } - public System.Collections.Generic.List? DebugImages { get; set; } + public System.Collections.Generic.List? DebugImages { get; set; } public string? Distribution { get; set; } public string? Environment { get; set; } public Sentry.SentryId EventId { get; } @@ -622,20 +601,10 @@ namespace Sentry public bool AutoSessionTracking { get; set; } public System.TimeSpan AutoSessionTrackingInterval { get; set; } public Sentry.Extensibility.IBackgroundWorker? BackgroundWorker { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeBreadcrumb instea" + - "d.")] - public System.Func? BeforeBreadcrumb { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSend instead.")] - public System.Func? BeforeSend { get; set; } - [System.Obsolete("This property will be removed in a future version. Use SetBeforeSendTransaction i" + - "nstead.")] - public System.Func? BeforeSendTransaction { get; set; } public string? CacheDirectoryPath { get; set; } public bool CaptureFailedRequests { get; set; } public System.Action? ConfigureClient { get; set; } public System.Func? CrashedLastRun { get; set; } - [System.Obsolete("Use CreateHttpMessageHandler instead")] - public System.Func? CreateHttpClientHandler { get; set; } public System.Func? CreateHttpMessageHandler { get; set; } public bool Debug { get; set; } public System.Net.DecompressionMethods DecompressionMethods { get; set; } @@ -657,16 +626,12 @@ namespace Sentry public bool IsEnvironmentUser { get; set; } public bool IsGlobalModeEnabled { get; set; } public bool JsonPreserveReferences { get; set; } - [System.Obsolete("This property is no longer used. It will be removed in a future version.")] - public bool KeepAggregateException { get; set; } public long MaxAttachmentSize { get; set; } public int MaxBreadcrumbs { get; set; } public int MaxCacheItems { get; set; } public int MaxQueueItems { get; set; } public Sentry.Extensibility.INetworkStatusListener? NetworkStatusListener { get; set; } public string? Release { get; set; } - [System.Obsolete("Use ReportAssembliesMode instead", false)] - public bool ReportAssemblies { get; set; } public Sentry.ReportAssembliesMode ReportAssembliesMode { get; set; } public bool RequestBodyCompressionBuffered { get; set; } public System.IO.Compression.CompressionLevel RequestBodyCompressionLevel { get; set; } @@ -679,12 +644,14 @@ namespace Sentry public System.TimeSpan ShutdownTimeout { get; set; } public Sentry.StackTraceMode StackTraceMode { get; set; } public System.Collections.Generic.ICollection TagFilters { get; set; } - public System.Collections.Generic.IList TracePropagationTargets { get; set; } + public System.Collections.Generic.IList TracePropagationTargets { get; set; } public double? TracesSampleRate { get; set; } public System.Func? TracesSampler { get; set; } public Sentry.Extensibility.ITransport? Transport { get; set; } public bool UseAsyncFileIO { get; set; } public void AddJsonConverter(System.Text.Json.Serialization.JsonConverter converter) { } + public void AddJsonSerializerContext(System.Func contextBuilder) + where T : System.Text.Json.Serialization.JsonSerializerContext { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeBreadcrumb(System.Func beforeBreadcrumb) { } public void SetBeforeSend(System.Func beforeSend) { } @@ -714,9 +681,6 @@ namespace Sentry public static void DisableAppDomainUnhandledExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableDuplicateEventDetection(this Sentry.SentryOptions options) { } public static void DisableNetFxInstallationsIntegration(this Sentry.SentryOptions options) { } - [System.Obsolete("Method has been renamed to DisableUnobservedTaskExceptionCapture. Please update " + - "usage.")] - public static void DisableTaskUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static void DisableUnobservedTaskExceptionCapture(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllEventProcessors(this Sentry.SentryOptions options) { } public static System.Collections.Generic.IEnumerable GetAllExceptionProcessors(this Sentry.SentryOptions options) { } @@ -731,12 +695,6 @@ namespace Sentry where TProcessor : Sentry.Extensibility.ISentryTransactionProcessor { } public static Sentry.SentryOptions UseStackTraceFactory(this Sentry.SentryOptions options, Sentry.Extensibility.ISentryStackTraceFactory sentryStackTraceFactory) { } } - public static class SentryScopeManagerExtensions - { - public static T? WithScope(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func scopeCallback) { } - public static System.Threading.Tasks.Task WithScopeAsync(this Sentry.ISentryScopeManager scopeManager, System.Func> scopeCallback) { } - } public static class SentrySdk { public static bool IsEnabled { get; } @@ -746,17 +704,16 @@ namespace Sentry public static void AddBreadcrumb(Sentry.Infrastructure.ISystemClock? clock, string message, string? category = null, string? type = null, System.Collections.Generic.IDictionary? data = null, Sentry.BreadcrumbLevel level = 0) { } public static void BindClient(Sentry.ISentryClient client) { } public static void BindException(System.Exception exception, Sentry.ISpan span) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public static Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public static Sentry.SentryId CaptureException(System.Exception exception) { } public static Sentry.SentryId CaptureException(System.Exception exception, System.Action configureScope) { } public static Sentry.SentryId CaptureMessage(string message, Sentry.SentryLevel level = 1) { } public static Sentry.SentryId CaptureMessage(string message, System.Action configureScope, Sentry.SentryLevel level = 1) { } public static void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public static void CaptureTransaction(Sentry.Transaction transaction) { } - public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public static void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public static void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public static void CaptureUserFeedback(Sentry.SentryId eventId, string email, string comments, string? name = null) { } [System.Obsolete("WARNING: This method deliberately causes a crash, and should not be used in a rea" + @@ -784,23 +741,11 @@ namespace Sentry public static System.IDisposable PushScope(TState state) { } public static void ResumeSession() { } public static void StartSession() { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context) { } - public static Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public static Sentry.ITransaction StartTransaction(string name, string operation) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public static Sentry.ITransaction StartTransaction(string name, string operation, string? description) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public static System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context) { } + public static Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } + public static Sentry.ITransactionTracer StartTransaction(string name, string operation, string? description) { } } public sealed class SentryStackFrame : Sentry.IJsonSerializable { @@ -812,12 +757,10 @@ namespace Sentry public string? FileName { get; set; } public System.Collections.Generic.IList FramesOmitted { get; } public string? Function { get; set; } - public string? FunctionId { get; set; } - public long ImageAddress { get; set; } + public long? FunctionId { get; set; } + public long? ImageAddress { get; set; } public bool? InApp { get; set; } - public string? InstructionAddress { get; set; } - [System.Obsolete("This property is unused and will be removed in the future.")] - public long? InstructionOffset { get; set; } + public long? InstructionAddress { get; set; } public int? LineNumber { get; set; } public string? Module { get; set; } public string? Package { get; set; } @@ -858,12 +801,6 @@ namespace Sentry public override string ToString() { } public static Sentry.SentryTraceHeader Parse(string value) { } } - public sealed class SentryValues : Sentry.IJsonSerializable - { - public SentryValues(System.Collections.Generic.IEnumerable? values) { } - public System.Collections.Generic.IEnumerable Values { get; } - public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } - } public class Session : Sentry.ISession { public Session(string? distinctId, string release, string? environment) { } @@ -905,7 +842,7 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.SessionUpdate FromJson(System.Text.Json.JsonElement json) { } } - public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class Span : Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public Span(Sentry.ISpan tracer) { } public Span(Sentry.SpanId? parentSpanId, string operation) { } @@ -914,6 +851,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -923,14 +861,15 @@ namespace Sentry public Sentry.SentryId TraceId { get; } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public void UnsetTag(string key) { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Span FromJson(System.Text.Json.JsonElement json) { } } - public class SpanContext : Sentry.ISpanContext, Sentry.Protocol.ITraceContext + public class SpanContext : Sentry.Protocol.ITraceContext { - public SpanContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled) { } + public SpanContext(string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = null, Sentry.SpanStatus? status = default, bool? isSampled = default) { } public string? Description { get; } public Sentry.Instrumenter Instrumenter { get; } public bool? IsSampled { get; } @@ -940,9 +879,17 @@ namespace Sentry public Sentry.SpanStatus? Status { get; } public Sentry.SentryId TraceId { get; } } + public static class SpanDataExtensions + { + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, double value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, int value, Sentry.MeasurementUnit unit = default) { } + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, long value, Sentry.MeasurementUnit unit = default) { } + [System.CLSCompliant(false)] + public static void SetMeasurement(this Sentry.ISpanData spanData, string name, ulong value, Sentry.MeasurementUnit unit = default) { } + } public static class SpanExtensions { - public static Sentry.ITransaction GetTransaction(this Sentry.ISpan span) { } + public static Sentry.ITransactionTracer GetTransaction(this Sentry.ISpan span) { } public static Sentry.ISpan StartChild(this Sentry.ISpan span, string operation, string? description) { } } public readonly struct SpanId : Sentry.IJsonSerializable, System.IEquatable @@ -982,7 +929,7 @@ namespace Sentry OutOfRange = 15, DataLoss = 16, } - public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.Protocol.ITraceContext + public class SpanTracer : Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.Protocol.ITraceContext { public SpanTracer(Sentry.IHub hub, Sentry.TransactionTracer transaction, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string operation) { } public string? Description { get; set; } @@ -990,6 +937,7 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary Extra { get; } public bool IsFinished { get; } public bool? IsSampled { get; } + public System.Collections.Generic.IReadOnlyDictionary Measurements { get; } public string Operation { get; set; } public Sentry.SpanId? ParentSpanId { get; } public Sentry.SpanId SpanId { get; } @@ -1003,6 +951,7 @@ namespace Sentry public void Finish(System.Exception exception, Sentry.SpanStatus status) { } public Sentry.SentryTraceHeader GetTraceHeader() { } public void SetExtra(string key, object? value) { } + public void SetMeasurement(string name, Sentry.Protocol.Measurement measurement) { } public void SetTag(string key, string value) { } public Sentry.ISpan StartChild(string operation) { } public void UnsetTag(string key) { } @@ -1033,15 +982,9 @@ namespace Sentry public override string ToString() { } public static Sentry.SubstringOrRegexPattern op_Implicit(string substringOrRegexPattern) { } } - [System.ComponentModel.TypeConverter(typeof(Sentry.TracePropagationTargetTypeConverter))] - public class TracePropagationTarget : Sentry.SubstringOrRegexPattern + public class Transaction : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IJsonSerializable, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext { - public TracePropagationTarget(System.Text.RegularExpressions.Regex regex) { } - public TracePropagationTarget(string substringOrRegexPattern, System.StringComparison comparison = 5) { } - } - public class Transaction : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.IJsonSerializable, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext - { - public Transaction(Sentry.ITransaction tracer) { } + public Transaction(Sentry.ITransactionTracer tracer) { } public Transaction(string name, string operation) { } public Transaction(string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } @@ -1083,16 +1026,9 @@ namespace Sentry public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } public static Sentry.Transaction FromJson(System.Text.Json.JsonElement json) { } } - public class TransactionContext : Sentry.SpanContext, Sentry.IHasTransactionNameSource, Sentry.ISpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext + public class TransactionContext : Sentry.SpanContext, Sentry.ITransactionContext, Sentry.Protocol.ITraceContext { - public TransactionContext(string name, string operation) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader) { } - public TransactionContext(string name, string operation, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(string name, string operation, bool? isSampled) { } - public TransactionContext(string name, string operation, Sentry.SentryTraceHeader traceHeader, Sentry.TransactionNameSource nameSource) { } - public TransactionContext(Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled) { } - public TransactionContext(Sentry.SpanId spanId, Sentry.SpanId? parentSpanId, Sentry.SentryId traceId, string name, string operation, string? description, Sentry.SpanStatus? status, bool? isSampled, bool? isParentSampled, Sentry.TransactionNameSource nameSource) { } + public TransactionContext(string name, string operation, Sentry.SpanId? spanId = default, Sentry.SpanId? parentSpanId = default, Sentry.SentryId? traceId = default, string? description = "", Sentry.SpanStatus? status = default, bool? isSampled = default, bool? isParentSampled = default, Sentry.TransactionNameSource nameSource = 0) { } public bool? IsParentSampled { get; } public string Name { get; set; } public Sentry.TransactionNameSource NameSource { get; set; } @@ -1112,11 +1048,9 @@ namespace Sentry public System.Collections.Generic.IReadOnlyDictionary CustomSamplingContext { get; } public Sentry.ITransactionContext TransactionContext { get; } } - public class TransactionTracer : Sentry.IEventLike, Sentry.IHasBreadcrumbs, Sentry.IHasExtra, Sentry.IHasTags, Sentry.IHasTransactionNameSource, Sentry.ISpan, Sentry.ISpanContext, Sentry.ISpanData, Sentry.ITransaction, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.Protocol.ITraceContext + public class TransactionTracer : Sentry.IEventLike, Sentry.IHasExtra, Sentry.IHasTags, Sentry.ISpan, Sentry.ISpanData, Sentry.ITransactionContext, Sentry.ITransactionData, Sentry.ITransactionTracer, Sentry.Protocol.ITraceContext { public TransactionTracer(Sentry.IHub hub, Sentry.ITransactionContext context) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation) { } - public TransactionTracer(Sentry.IHub hub, string name, string operation, Sentry.TransactionNameSource nameSource) { } public System.Collections.Generic.IReadOnlyCollection Breadcrumbs { get; } public Sentry.Contexts Contexts { get; set; } public string? Description { get; set; } @@ -1222,12 +1156,14 @@ namespace Sentry.Extensibility public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogDebug(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2) { } public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3) { } - public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception exception, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } - public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message, System.Exception? exception = null) { } + public static void LogError(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message, TArg arg, TArg2 arg2, TArg3 arg3, TArg4 arg4) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } + public static void LogFatal(this Sentry.Extensibility.IDiagnosticLogger logger, System.Exception exception, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg) { } public static void LogInfo(this Sentry.Extensibility.IDiagnosticLogger logger, string message, TArg arg, TArg2 arg2) { } @@ -1243,12 +1179,12 @@ namespace Sentry.Extensibility public Sentry.SentryId LastEventId { get; } public void BindClient(Sentry.ISentryClient client) { } public void BindException(System.Exception exception, Sentry.ISpan span) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope = null) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope = null, Sentry.Hint? hint = null) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback userFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1265,8 +1201,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - public void WithScope(System.Action scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public class FormRequestPayloadExtractor : Sentry.Extensibility.BaseRequestPayloadExtractor { @@ -1286,11 +1221,12 @@ namespace Sentry.Extensibility public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope) { } public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, System.Action configureScope) { } - public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, Sentry.Scope? scope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Hint? hint, System.Action configureScope) { } + public Sentry.SentryId CaptureEvent(Sentry.SentryEvent evt, Sentry.Scope? scope, Sentry.Hint? hint = null) { } public Sentry.SentryId CaptureException(System.Exception exception) { } public void CaptureSession(Sentry.SessionUpdate sessionUpdate) { } public void CaptureTransaction(Sentry.Transaction transaction) { } - public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Hint? hint) { } + public void CaptureTransaction(Sentry.Transaction transaction, Sentry.Scope? scope, Sentry.Hint? hint) { } public void CaptureUserFeedback(Sentry.UserFeedback sentryUserFeedback) { } public void ConfigureScope(System.Action configureScope) { } public System.Threading.Tasks.Task ConfigureScopeAsync(System.Func configureScope) { } @@ -1306,19 +1242,7 @@ namespace Sentry.Extensibility public System.IDisposable PushScope(TState state) { } public void ResumeSession() { } public void StartSession() { } - public Sentry.ITransaction StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public void WithScope(System.Action scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public T? WithScope(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func scopeCallback) { } - [System.Obsolete("This method is deprecated in favor of overloads of CaptureEvent, CaptureMessage a" + - "nd CaptureException that provide a callback to a configurable scope.")] - public System.Threading.Tasks.Task WithScopeAsync(System.Func> scopeCallback) { } + public Sentry.ITransactionTracer StartTransaction(Sentry.ITransactionContext context, System.Collections.Generic.IReadOnlyDictionary customSamplingContext) { } } public interface IBackgroundWorker { @@ -1427,13 +1351,6 @@ namespace Sentry.Infrastructure public ConsoleDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } protected override void LogMessage(string message) { } } - [System.Obsolete("Logger doesn\'t work outside of Sentry SDK. Please use TraceDiagnosticLogger inste" + - "ad")] - public class DebugDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger - { - public DebugDiagnosticLogger(Sentry.SentryLevel minimalLevel) { } - protected override void LogMessage(string message) { } - } public abstract class DiagnosticLogger : Sentry.Extensibility.IDiagnosticLogger { protected DiagnosticLogger(Sentry.SentryLevel minimalLevel) { } @@ -1454,9 +1371,6 @@ namespace Sentry.Infrastructure public sealed class SystemClock : Sentry.Infrastructure.ISystemClock { public static readonly Sentry.Infrastructure.SystemClock Clock; - [System.Obsolete("This constructor will become private in a future major version. Use the `SystemCl" + - "ock.Clock` singleton instead.")] - public SystemClock() { } public System.DateTimeOffset GetUtcNow() { } } public class TraceDiagnosticLogger : Sentry.Infrastructure.DiagnosticLogger @@ -1499,8 +1413,7 @@ namespace Sentry.PlatformAbstractions { public Runtime(string? name = null, string? version = null, Sentry.PlatformAbstractions.FrameworkInstallation? frameworkInstallation = null, string? raw = null) { } public Sentry.PlatformAbstractions.FrameworkInstallation? FrameworkInstallation { get; } - [set: System.Obsolete("This setter is nonfunctional, and will be removed in a future version.")] - public string? Identifier { get; set; } + public string? Identifier { get; } public string? Name { get; } public string? Raw { get; } public string? Version { get; } @@ -1542,6 +1455,20 @@ namespace Sentry.Protocol public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Browser FromJson(System.Text.Json.JsonElement json) { } } + public sealed class DebugImage : Sentry.IJsonSerializable + { + public DebugImage() { } + public string? CodeFile { get; set; } + public string? CodeId { get; set; } + public string? DebugChecksum { get; set; } + public string? DebugFile { get; set; } + public string? DebugId { get; set; } + public long? ImageAddress { get; set; } + public long? ImageSize { get; set; } + public string? Type { get; set; } + public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? logger) { } + public static Sentry.Protocol.DebugImage FromJson(System.Text.Json.JsonElement json) { } + } public sealed class Device : Sentry.IJsonSerializable { public const string Type = "device"; @@ -1688,17 +1615,12 @@ namespace Sentry.Protocol public string? Name { get; set; } public string? RawDescription { get; set; } public string? Version { get; set; } - [System.Obsolete("This method will be made internal in a future version.")] - public Sentry.Protocol.Runtime Clone() { } public void WriteTo(System.Text.Json.Utf8JsonWriter writer, Sentry.Extensibility.IDiagnosticLogger? _) { } public static Sentry.Protocol.Runtime FromJson(System.Text.Json.JsonElement json) { } } public sealed class SentryException : Sentry.IJsonSerializable { public SentryException() { } - [System.Obsolete("Use SentryException.Mechanism.Data instead. This property will be removed in a fu" + - "ture version.")] - public System.Collections.Generic.IDictionary Data { get; } public Sentry.Protocol.Mechanism? Mechanism { get; set; } public string? Module { get; set; } public Sentry.SentryStackTrace? Stacktrace { get; set; } @@ -1764,14 +1686,6 @@ namespace Sentry.Protocol.Envelopes System.Threading.Tasks.Task SerializeAsync(System.IO.Stream stream, Sentry.Extensibility.IDiagnosticLogger? logger, System.Threading.CancellationToken cancellationToken = default); } } -namespace Sentry.Reflection -{ - [System.Obsolete("Should not be public. This method will be removed in version 4.")] - public static class AssemblyExtensions - { - public static Sentry.SdkVersion GetNameAndVersion(this System.Reflection.Assembly asm) { } - } -} public static class SentryExceptionExtensions { public static void AddSentryContext(this System.Exception ex, string name, System.Collections.Generic.IReadOnlyDictionary data) { } diff --git a/test/Sentry.Tests/AppDomainUnhandledExceptionIntegrationTests.cs b/test/Sentry.Tests/AppDomainUnhandledExceptionIntegrationTests.cs index d67b15426f..fef8bb575e 100644 --- a/test/Sentry.Tests/AppDomainUnhandledExceptionIntegrationTests.cs +++ b/test/Sentry.Tests/AppDomainUnhandledExceptionIntegrationTests.cs @@ -4,7 +4,7 @@ public class AppDomainUnhandledExceptionIntegrationTests { private class Fixture { - public IHubEx Hub { get; } = Substitute.For(); + public IHub Hub { get; } = Substitute.For(); public IAppDomain AppDomain { get; } = Substitute.For(); public AppDomainUnhandledExceptionIntegration GetSut() => new(AppDomain); @@ -21,7 +21,7 @@ public void Handle_WithException_CaptureEvent() sut.Handle(this, new UnhandledExceptionEventArgs(new Exception(), true)); - _fixture.Hub.Received(1).CaptureEventInternal(Arg.Any()); + _fixture.Hub.Received(1).CaptureEvent(Arg.Any()); } [Fact] @@ -32,7 +32,7 @@ public void Handle_NoException_NoCaptureEvent() sut.Handle(this, new UnhandledExceptionEventArgs(new object(), true)); - _fixture.Hub.DidNotReceive().CaptureEventInternal(Arg.Any()); + _fixture.Hub.DidNotReceive().CaptureEvent(Arg.Any()); } [Fact] diff --git a/test/Sentry.Tests/AttributeReaderTests.cs b/test/Sentry.Tests/AttributeReaderTests.cs index c1d9be89bd..25a5574e75 100644 --- a/test/Sentry.Tests/AttributeReaderTests.cs +++ b/test/Sentry.Tests/AttributeReaderTests.cs @@ -6,7 +6,6 @@ public class AttributeReaderTests public void Simple() { var assembly = typeof(AttributeReaderTests).Assembly; - Assert.True(AttributeReader.TryGetProjectDirectory(assembly, out var projectDirectory)); - Assert.NotNull(projectDirectory); + Assert.NotNull(AttributeReader.TryGetProjectDirectory(assembly)); } } diff --git a/test/Sentry.Tests/BindableSentryOptionsTests.cs b/test/Sentry.Tests/BindableSentryOptionsTests.cs new file mode 100644 index 0000000000..50f39e954a --- /dev/null +++ b/test/Sentry.Tests/BindableSentryOptionsTests.cs @@ -0,0 +1,30 @@ +#if !NETFRAMEWORK +using Microsoft.Extensions.Configuration; + +namespace Sentry.Tests; + +public class BindableSentryOptionsTests : BindableTests +{ + [Fact] + public void BindableProperties_MatchOptionsProperties() + { + var actual = GetPropertyNames(); + AssertContainsAllOptionsProperties(actual); + } + + [Fact] + public void ApplyTo_SetsOptionsFromConfig() + { + // Arrange + var actual = new SentryOptions(); + var bindable = new BindableSentryOptions(); + + // Act + Fixture.Config.Bind(bindable); + bindable.ApplyTo(actual); + + // Assert + AssertContainsExpectedPropertyValues(actual); + } +} +#endif diff --git a/test/Sentry.Tests/Extensibility/DisabledHubTests.cs b/test/Sentry.Tests/Extensibility/DisabledHubTests.cs index 6ec07f6d63..e56ff65370 100644 --- a/test/Sentry.Tests/Extensibility/DisabledHubTests.cs +++ b/test/Sentry.Tests/Extensibility/DisabledHubTests.cs @@ -27,18 +27,6 @@ public void CaptureEvent_EmptyGuid() [Fact] public void ConfigureScope_NoOp() => DisabledHub.Instance.ConfigureScope(null!); - [Fact] - public void WithScope_NoOp() => DisabledHub.Instance.WithScope(null!); - - [Fact] - public void WithScopeT_NoOp() => DisabledHub.Instance.WithScope(null!); - - [Fact] - public Task WithScopeAsync_NoOp() => DisabledHub.Instance.WithScopeAsync(null!); - - [Fact] - public Task WithScopeAsyncT_NoOp() => DisabledHub.Instance.WithScopeAsync(null!); - [Fact] public void BindClient_NoOp() => DisabledHub.Instance.BindClient(null!); diff --git a/test/Sentry.Tests/Extensibility/HubAdapterTests.cs b/test/Sentry.Tests/Extensibility/HubAdapterTests.cs index d0ba4de11a..e84bc71c89 100644 --- a/test/Sentry.Tests/Extensibility/HubAdapterTests.cs +++ b/test/Sentry.Tests/Extensibility/HubAdapterTests.cs @@ -3,11 +3,11 @@ namespace Sentry.Tests.Extensibility; [Collection(nameof(SentrySdkCollection))] public class HubAdapterTests : IDisposable { - private IHubEx Hub { get; } + private IHub Hub { get; } public HubAdapterTests() { - Hub = Substitute.For(); + Hub = Substitute.For(); SentrySdk.UseHub(Hub); } @@ -34,7 +34,7 @@ public void CaptureException_MockInvoked() var expected = new Exception(); Hub.IsEnabled.Returns(true); HubAdapter.Instance.CaptureException(expected); - Hub.Received(1).CaptureEventInternal(Arg.Is(s => s.Exception == expected)); + Hub.Received(1).CaptureEvent(Arg.Is(s => s.Exception == expected)); } [Fact] @@ -78,42 +78,6 @@ void Expected(Scope _) { } Hub.Received(1).ConfigureScope(Expected); } - [Obsolete] - [Fact] - public void WithScope_MockInvoked() - { - void Expected(Scope _) { } - HubAdapter.Instance.WithScope(Expected); - Hub.Received(1).WithScope(Expected); - } - - [Obsolete] - [Fact] - public void WithScopeT_MockInvoked() - { - object Expected(Scope _) => null; - HubAdapter.Instance.WithScope(Expected); - Hub.Received(1).WithScope(Expected); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsync_MockInvoked() - { - Task Expected(Scope _) => Task.CompletedTask; - await HubAdapter.Instance.WithScopeAsync(Expected); - await Hub.Received(1).WithScopeAsync(Expected); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsyncT_MockInvoked() - { - Task Expected(Scope _) => Task.FromResult(null); - await HubAdapter.Instance.WithScopeAsync(Expected); - await Hub.Received(1).WithScopeAsync(Expected); - } - [Fact] public void PushScope_MockInvoked() { diff --git a/test/Sentry.Tests/HintTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.Core3_1.verified.txt b/test/Sentry.Tests/HintTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.Core3_1.verified.txt deleted file mode 100644 index 4eeeeb9e1c..0000000000 --- a/test/Sentry.Tests/HintTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.Core3_1.verified.txt +++ /dev/null @@ -1,181 +0,0 @@ -[ - { - Header: { - sdk: { - name: sentry.dotnet - } - }, - Items: [ - { - Header: { - type: session - }, - Payload: { - Source: { - DistinctId: Guid_1, - Release: release, - Environment: production, - IsInitial: true - } - } - } - ] - }, - { - Header: { - event_id: Guid_2, - sdk: { - name: sentry.dotnet - }, - trace: { - environment: production, - public_key: d4d82fc1c2c4032a83f3a29aa3a3aff, - release: release, - sample_rate: 1, - trace_id: Guid_3, - transaction: my transaction - } - }, - Items: [ - { - Header: { - type: event - }, - Payload: { - Source: { - Platform: csharp, - SentryExceptions: [ - { - Mechanism: { - Type: generic, - Handled: false, - Synthetic: false - } - } - ], - SentryThreads: [ - { - Crashed: false, - Current: true - } - ], - DebugImages: [ - { - Type: pe_dotnet, - ImageAddress: null, - ImageSize: null, - DebugId: ________-____-____-____-____________-________, - DebugChecksum: null, - DebugFile: System.Private.CoreLib.pdb, - CodeId: ______________, - CodeFile: .../System.Private.CoreLib.dll - }, - { - Type: pe_dotnet, - ImageAddress: null, - ImageSize: null, - DebugId: ________-____-____-____-____________-________, - DebugChecksum: ______:________________________________________________________________, - DebugFile: .../Sentry.Tests.pdb, - CodeId: _____________, - CodeFile: .../Sentry.Tests.dll - }, - { - Type: pe_dotnet, - ImageAddress: null, - ImageSize: null, - DebugId: ________-____-____-____-____________-________, - DebugChecksum: ______:________________________________________________________________, - DebugFile: xunit.execution.dotnet.pdb, - CodeId: _____________, - CodeFile: .../xunit.execution.dotnet.dll - }, - { - Type: pe_dotnet, - ImageAddress: null, - ImageSize: null, - DebugId: ________-____-____-____-____________-________, - DebugChecksum: ______:________________________________________________________________, - DebugFile: xunit.core.pdb, - CodeId: _____________, - CodeFile: .../xunit.core.dll - } - ], - Level: error, - TransactionName: my transaction, - Request: {}, - Contexts: { - trace: { - Operation: - } - }, - User: {}, - Environment: production - } - } - }, - { - Header: { - type: session - }, - Payload: { - Source: { - DistinctId: Guid_1, - Release: release, - Environment: production, - ErrorCount: 1, - IsInitial: false, - SequenceNumber: 1, - EndStatus: Crashed - } - } - } - ] - }, - { - Header: { - event_id: Guid_4, - sdk: { - name: sentry.dotnet - }, - trace: { - environment: production, - public_key: d4d82fc1c2c4032a83f3a29aa3a3aff, - release: release, - sample_rate: 1, - trace_id: Guid_3, - transaction: my transaction - } - }, - Items: [ - { - Header: { - type: transaction - }, - Payload: { - Source: { - Name: my transaction, - Platform: csharp, - Operation: my operation, - Description: , - Status: Aborted, - IsSampled: true, - SampleRate: 1.0, - Request: {}, - Contexts: { - trace: { - Operation: my operation, - Description: , - Status: Aborted, - IsSampled: true - } - }, - User: {}, - Environment: production, - IsFinished: true - } - } - } - ] - } -] \ No newline at end of file diff --git a/test/Sentry.Tests/HubTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.Core3_1.verified.txt b/test/Sentry.Tests/HubTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.DotNet8_0.verified.txt similarity index 96% rename from test/Sentry.Tests/HubTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.Core3_1.verified.txt rename to test/Sentry.Tests/HubTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.DotNet8_0.verified.txt index a67f115e35..7e4c8954b0 100644 --- a/test/Sentry.Tests/HubTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.Core3_1.verified.txt +++ b/test/Sentry.Tests/HubTests.CaptureEvent_ActiveTransaction_UnhandledExceptionTransactionEndedAsCrashed.DotNet8_0.verified.txt @@ -67,8 +67,8 @@ ImageAddress: null, ImageSize: null, DebugId: ________-____-____-____-____________-________, - DebugChecksum: null, - DebugFile: System.Private.CoreLib.pdb, + DebugChecksum: ______:________________________________________________________________, + DebugFile: .../System.Private.CoreLib.pdb, CodeId: ______________, CodeFile: .../System.Private.CoreLib.dll }, diff --git a/test/Sentry.Tests/HubTests.cs b/test/Sentry.Tests/HubTests.cs index e175eaf694..b79a5fb4fa 100644 --- a/test/Sentry.Tests/HubTests.cs +++ b/test/Sentry.Tests/HubTests.cs @@ -128,8 +128,7 @@ public void CaptureException_FinishedSpanBoundToSameExceptionExists_EventIsLinke Arg.Is(evt => evt.Contexts.Trace.TraceId == transaction.TraceId && evt.Contexts.Trace.SpanId == transaction.SpanId), - Arg.Any(), - Arg.Any()); + Arg.Any(), Arg.Any()); } [Fact] @@ -151,8 +150,7 @@ public void CaptureException_ActiveSpanExistsOnScope_EventIsLinkedToSpan() Arg.Is(evt => evt.Contexts.Trace.TraceId == transaction.TraceId && evt.Contexts.Trace.SpanId == transaction.SpanId), - Arg.Any(), - Arg.Any()); + Arg.Any(), Arg.Any()); } [Fact] @@ -191,8 +189,7 @@ public void CaptureException_TransactionFinished_Gets_DSC_From_LinkedSpan() _fixture.Client.Received(1).CaptureEvent( Arg.Is(evt => evt.DynamicSamplingContext == dsc), - Arg.Any(), - Arg.Any()); + Arg.Any(), Arg.Any()); } [Fact] @@ -214,8 +211,7 @@ public void CaptureException_ActiveSpanExistsOnScopeButIsSampledOut_EventIsNotLi Arg.Is(evt => evt.Contexts.Trace.TraceId == default && evt.Contexts.Trace.SpanId == default), - Arg.Any(), - Arg.Any()); + Arg.Any(), Arg.Any()); } [Fact] @@ -234,8 +230,7 @@ public void CaptureException_NoActiveSpanAndNoSpanBoundToSameException_EventCont Arg.Is(evt => evt.Contexts.Trace.TraceId == scope.PropagationContext.TraceId && evt.Contexts.Trace.SpanId == scope.PropagationContext.SpanId), - Arg.Any(), - Arg.Any()); + Arg.Any(), Arg.Any()); } [Fact] @@ -275,7 +270,7 @@ public void CaptureEvent_ExceptionWithOpenSpan_SpanLinkedToEventContext() Assert.Equal(child.ParentSpanId, evt.Contexts.Trace.ParentSpanId); } - private class EvilContext + internal class EvilContext { // This property will throw an exception during serialization. // ReSharper disable once UnusedMember.Local @@ -300,6 +295,9 @@ await TestHelpers.RetryTestAsync( private async Task CapturesEventWithContextKey_Implementation(bool offlineCaching) { +#if NET6_0_OR_GREATER + JsonExtensions.AddJsonSerializerContext(o => new HubTestsJsonContext(o)); +#endif var tcs = new TaskCompletionSource(); var expectedMessage = Guid.NewGuid().ToString(); @@ -442,14 +440,12 @@ public void CaptureEvent_Client_GetsHint() var hub = _fixture.GetSut(); // Act - hub.CaptureEvent(@event, hint); + hub.CaptureEvent(@event, hint: hint); // Assert _fixture.Client.Received(1).CaptureEvent( Arg.Any(), - Arg.Is(h => h == hint), - Arg.Any() - ); + Arg.Any(), Arg.Is(h => h == hint)); } [Fact] @@ -1252,7 +1248,7 @@ public void CaptureEvent_HubEnabled(bool enabled) hub.CaptureEvent(evt); // Assert - _fixture.Client.Received(enabled ? 1 : 0).CaptureEvent(Arg.Any(), Arg.Any(), Arg.Any()); + _fixture.Client.Received(enabled ? 1 : 0).CaptureEvent(Arg.Any(), Arg.Any(), Arg.Any()); } [Theory] @@ -1313,7 +1309,7 @@ public void CaptureTransaction_HubEnabled(bool enabled) transaction.Finish(); // Assert - _fixture.Client.Received().CaptureTransaction(Arg.Is(t => t.IsSampled == enabled), Arg.Any()); + _fixture.Client.Received().CaptureTransaction(Arg.Is(t => t.IsSampled == enabled),Arg.Any(), Arg.Any()); } [Fact] @@ -1327,74 +1323,7 @@ public void CaptureTransaction_Client_Gets_Hint() transaction.Finish(); // Assert - _fixture.Client.Received().CaptureTransaction(Arg.Any(), Arg.Any()); - } - - [Fact] - public void CaptureTransaction_Client_Gets_ScopeAttachments() - { - // Arrange - var hub = _fixture.GetSut(); - var attachments = new List { - AttachmentHelper.FakeAttachment("foo"), - AttachmentHelper.FakeAttachment("bar") - }; - hub.ConfigureScope(s => { - s.AddAttachment(attachments[0]); - s.AddAttachment(attachments[1]); - }); - - // Act - Hint hint = null; - _fixture.Client.CaptureTransaction( - Arg.Any(), - Arg.Do(h => hint = h) - ); - var transaction = hub.StartTransaction("test", "test"); - transaction.Finish(); - - // Assert - hint.Should().NotBeNull(); - hint.Attachments.Should().Contain(attachments); - } - - [Fact] - public void CaptureTransaction_EventProcessor_Gets_Hint() - { - // Arrange - var processor = Substitute.For(); - processor.Process(Arg.Any(), Arg.Any()).Returns(new Transaction("name", "operation")); - _fixture.Options.AddTransactionProcessor(processor); - - // Act - var hub = _fixture.GetSut(); - var transaction = hub.StartTransaction("test", "test"); - transaction.Finish(); - - // Assert - processor.Received(1).Process(Arg.Any(), Arg.Any()); - } - - [Fact] - public void CaptureTransaction_EventProcessor_Gets_ScopeAttachments() - { - // Arrange - var processor = Substitute.For(); - Hint hint = null; - processor.Process(Arg.Any(), Arg.Do(h => hint = h)).Returns(new Transaction("name", "operation")); - _fixture.Options.AddTransactionProcessor(processor); - - var attachments = new List { AttachmentHelper.FakeAttachment("foo.txt") }; - var hub = _fixture.GetSut(); - hub.ConfigureScope(s => s.AddAttachment(attachments[0])); - - // Act - var transaction = hub.StartTransaction("test", "test"); - transaction.Finish(); - - // Assert - hint.Should().NotBeNull(); - hint.Attachments.Should().Contain(attachments); + _fixture.Client.Received().CaptureTransaction(Arg.Any(), Arg.Any(), Arg.Any()); } [Theory] @@ -1435,91 +1364,12 @@ await transport.Received(1) .SendEnvelopeAsync(Arg.Any(), Arg.Any()); } - [Obsolete] - [Fact] - public void WithScope_Works() - { - _fixture.Options.IsGlobalModeEnabled = false; - var hub = _fixture.GetSut(); - var originalScope = GetCurrentScope(hub); - - hub.WithScope(scope => - { - var newScope = GetCurrentScope(hub); - Assert.Same(newScope, scope); - Assert.NotSame(originalScope, scope); - }); - - var finalScope = GetCurrentScope(hub); - Assert.Same(originalScope, finalScope); - } - - [Obsolete] - [Fact] - public void WithScopeT_Works() - { - _fixture.Options.IsGlobalModeEnabled = false; - var hub = _fixture.GetSut(); - var originalScope = GetCurrentScope(hub); - - var result = hub.WithScope(scope => - { - var newScope = GetCurrentScope(hub); - Assert.Same(newScope, scope); - Assert.NotSame(originalScope, scope); - - return true; - }); - - Assert.True(result); - - var finalScope = GetCurrentScope(hub); - Assert.Same(originalScope, finalScope); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsync_Works() - { - _fixture.Options.IsGlobalModeEnabled = false; - var hub = _fixture.GetSut(); - var originalScope = GetCurrentScope(hub); - - await hub.WithScopeAsync(scope => - { - var newScope = GetCurrentScope(hub); - Assert.Same(newScope, scope); - Assert.NotSame(originalScope, scope); - - return Task.CompletedTask; - }); - - var finalScope = GetCurrentScope(hub); - Assert.Same(originalScope, finalScope); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsyncT_Works() - { - _fixture.Options.IsGlobalModeEnabled = false; - var hub = _fixture.GetSut(); - var originalScope = GetCurrentScope(hub); - - var result = await hub.WithScopeAsync(scope => - { - var newScope = GetCurrentScope(hub); - Assert.Same(newScope, scope); - Assert.NotSame(originalScope, scope); - - return Task.FromResult(true); - }); - - Assert.True(result); - - var finalScope = GetCurrentScope(hub); - Assert.Same(originalScope, finalScope); - } - private static Scope GetCurrentScope(Hub hub) => hub.ScopeManager.GetCurrent().Key; } + +#if NET6_0_OR_GREATER +[JsonSerializable(typeof(HubTests.EvilContext))] +internal partial class HubTestsJsonContext : JsonSerializerContext +{ +} +#endif diff --git a/test/Sentry.Tests/Internals/ApplicationVersionLocatorTests.cs b/test/Sentry.Tests/Internals/ApplicationVersionLocatorTests.cs index ccd4be9e37..7dacfc8c54 100644 --- a/test/Sentry.Tests/Internals/ApplicationVersionLocatorTests.cs +++ b/test/Sentry.Tests/Internals/ApplicationVersionLocatorTests.cs @@ -36,11 +36,11 @@ public void GetCurrent_VersionWithPrefix_ReturnsVersionAsIs() [Theory] [InlineData("")] - public void GetCurrent_InvalidCases_ReturnsNull(string version) + public void GetCurrent_InvalidCases_DoesNotReturnNull(string version) { var asm = AssemblyCreationHelper.CreateWithInformationalVersion(version); var actual = ApplicationVersionLocator.GetCurrent(asm); - Assert.Null(actual); + Assert.NotNull(actual); } [Fact] diff --git a/test/Sentry.Tests/Internals/DebugStackTraceTests.CreateFrame_ForNativeAOT.verified.txt b/test/Sentry.Tests/Internals/DebugStackTraceTests.CreateFrame_ForNativeAOT.verified.txt new file mode 100644 index 0000000000..d6da3fed6b --- /dev/null +++ b/test/Sentry.Tests/Internals/DebugStackTraceTests.CreateFrame_ForNativeAOT.verified.txt @@ -0,0 +1,7 @@ +{ + function: DoSomething(int, long), + module: Foo.Bar, + in_app: true, + image_addr: 0x1, + instruction_addr: 0x2 +} \ No newline at end of file diff --git a/test/Sentry.Tests/Internals/DebugStackTraceTests.cs b/test/Sentry.Tests/Internals/DebugStackTraceTests.verify.cs similarity index 63% rename from test/Sentry.Tests/Internals/DebugStackTraceTests.cs rename to test/Sentry.Tests/Internals/DebugStackTraceTests.verify.cs index 62e68c4524..9c23992dea 100644 --- a/test/Sentry.Tests/Internals/DebugStackTraceTests.cs +++ b/test/Sentry.Tests/Internals/DebugStackTraceTests.verify.cs @@ -1,7 +1,11 @@ +#nullable enable // ReSharper disable once CheckNamespace // Stack trace filters out Sentry frames by namespace + namespace Other.Tests.Internals; +[UsesVerify] + public class DebugStackTraceTests { private class Fixture @@ -11,19 +15,23 @@ private class Fixture } private readonly Fixture _fixture = new(); - private static readonly string ThisNamespace = typeof(SentryStackTraceFactoryTests).Namespace; + private static readonly string ThisNamespace = typeof(SentryStackTraceFactoryTests).Namespace!; +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/issues/2772 [Fact] public void CreateSentryStackFrame_AppNamespace_InAppFrame() { var frame = new StackFrame(); var sut = _fixture.GetSut(); - var actual = sut.CreateFrame(frame); + var actual = sut.CreateFrame(new RealStackFrame(frame)); - Assert.True(actual.InApp); + Assert.True(actual?.InApp); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/issues/2772 [Fact] public void CreateSentryStackFrame_AppNamespaceExcluded_NotInAppFrame() { @@ -31,11 +39,13 @@ public void CreateSentryStackFrame_AppNamespaceExcluded_NotInAppFrame() var sut = _fixture.GetSut(); var frame = new StackFrame(); - var actual = sut.CreateFrame(frame); + var actual = sut.CreateFrame(new RealStackFrame(frame)); - Assert.False(actual.InApp); + Assert.False(actual?.InApp); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/issues/2772 [Theory] [InlineData(true)] [InlineData(false)] @@ -52,12 +62,14 @@ public void CreateSentryStackFrame_SystemType_NotInAppFrame(bool useEnhancedStac Assert.Equal(typeof(Convert), frame.GetMethod()?.DeclaringType); // Act - var actual = sut.CreateFrame(frame); + var actual = sut.CreateFrame(new RealStackFrame(frame)); // Assert - Assert.False(actual.InApp); + Assert.False(actual?.InApp); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/issues/2772 [Fact] public void CreateSentryStackFrame_NamespaceIncludedAndExcluded_IncludesTakesPrecedence() { @@ -66,9 +78,9 @@ public void CreateSentryStackFrame_NamespaceIncludedAndExcluded_IncludesTakesPre var sut = _fixture.GetSut(); var frame = new StackFrame(); - var actual = sut.CreateFrame(frame); + var actual = sut.CreateFrame(new RealStackFrame(frame)); - Assert.True(actual.InApp); + Assert.True(actual?.InApp); } // https://github.com/getsentry/sentry-dotnet/issues/64 @@ -180,6 +192,47 @@ void CheckStackTraceIsUnchanged(SentryStackTrace stackTrace) } } +#if NET8_0_OR_GREATER + [Fact] + public void ParseNativeAOTToString() + { + var frame = DebugStackTrace.ParseNativeAOTToString( + "System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x42 at offset 66 in file:line:column :0:0"); + Assert.Equal("System.Runtime.CompilerServices.TaskAwaiter", frame.Module); + Assert.Equal("HandleNonSuccessAndDebuggerNotification(Task)", frame.Function); + Assert.Null(frame.Package); + + frame = DebugStackTrace.ParseNativeAOTToString( + "Program.<
$>d__0.MoveNext() + 0xdd at offset 221 in file:line:column :0:0"); + Assert.Equal("Program.<
$>d__0", frame.Module); + Assert.Equal("MoveNext()", frame.Function); + Assert.Null(frame.Package); + + frame = DebugStackTrace.ParseNativeAOTToString( + "Sentry.Samples.Console.Basic!+0x4abb3b at offset 283 in file:line:column :0:0"); + Assert.Null(frame.Module); + Assert.Null(frame.Function); + Assert.Null(frame.Package); + } + + // TODO: Create integration test to test this behaviour when publishing AOT apps + // See https://github.com/getsentry/sentry-dotnet/issues/2772 + [Fact] + public Task CreateFrame_ForNativeAOT() + { + var sut = _fixture.GetSut(); + var frame = sut.CreateFrame(new StubNativeAOTStackFrame() + { + Function = "DoSomething(int, long)", + Module = "Foo.Bar", + ImageBase = 1, + IP = 2, + }); + + return VerifyJson(frame.ToJsonString()); + } +#endif + private class InjectableDebugStackTrace : DebugStackTrace { public InjectableDebugStackTrace(SentryOptions options) : base(options) { } @@ -193,4 +246,41 @@ public void Inject(int identifier) }); } } + internal class StubNativeAOTStackFrame : IStackFrame + { + internal string? Function; + internal string? Module; + internal nint ImageBase; + internal nint IP; + + public StackFrame? Frame => null; + + public int GetFileColumnNumber() => 0; + + public int GetFileLineNumber() => 0; + + public string? GetFileName() => null; + + public int GetILOffset() => StackFrame.OFFSET_UNKNOWN; + + public MethodBase? GetMethod() => null; + + public nint GetNativeImageBase() => ImageBase; + + public nint GetNativeIP() => IP; + + public bool HasNativeImage() => true; + + public override string ToString() + { + if (Function is not null && Module is not null) + { + return $"{Module}.{Function} + 0x{ImageBase:x} at offset 0x{IP - ImageBase:x} in file:line:column :0:0"; + } + else + { + return ""; + } + } + } } diff --git a/test/Sentry.Tests/Internals/ILSpy/SingleFileAppTests.cs b/test/Sentry.Tests/Internals/ILSpy/SingleFileAppTests.cs index a895365b9e..e5bce1ef4a 100644 --- a/test/Sentry.Tests/Internals/ILSpy/SingleFileAppTests.cs +++ b/test/Sentry.Tests/Internals/ILSpy/SingleFileAppTests.cs @@ -1,9 +1,8 @@ +#if NET5_0_OR_GREATER && PLATFORM_NEUTRAL using Sentry.Internal.ILSpy; namespace Sentry.Tests.Internals.ILSpy; -#if NET5_0_OR_GREATER && PLATFORM_NEUTRAL - /// /// Note the tests in this class rely on the SingleFileTestApp having being built. This will be done automatically if /// SingleFileTestApp is included in the solution that dotnet test is running against. Otherwise, tests are skipped. @@ -31,7 +30,9 @@ static SingleFileAppTests() InValidBundleFile = Path.Combine(testRoot, invalidBundle); } -#if NET7_0 +#if NET8_0 + private static string TargetFramework => "net8.0"; +#elif NET7_0 private static string TargetFramework => "net7.0"; #elif NET6_0 private static string TargetFramework => "net6.0"; diff --git a/test/Sentry.Tests/Internals/JsonTests.cs b/test/Sentry.Tests/Internals/JsonTests.cs index 4214d759b4..b3839e908d 100644 --- a/test/Sentry.Tests/Internals/JsonTests.cs +++ b/test/Sentry.Tests/Internals/JsonTests.cs @@ -7,6 +7,9 @@ public class JsonTests public JsonTests(ITestOutputHelper output) { _testOutputLogger = Substitute.ForPartsOf(output); +#if NET6_0_OR_GREATER + JsonExtensions.AddJsonSerializerContext(o => new JsonTestsJsonContext(o)); +#endif } public static Exception GenerateException(string description) @@ -21,7 +24,7 @@ public static Exception GenerateException(string description) } } - private class DataAndNonSerializableObject + internal class DataAndNonSerializableObject { /// /// A class containing two objects that can be serialized and a third one that will have issues if serialized. @@ -60,7 +63,7 @@ private class ExceptionObjectMock public int? HResult { get; set; } } - private class DataWithSerializableObject : DataAndNonSerializableObject + internal class DataWithSerializableObject : DataAndNonSerializableObject { /// /// A class containing three objects that can be serialized. @@ -242,3 +245,15 @@ public class SelfReferencedObject public SelfReferencedObject Object => this; } } + +#if NET6_0_OR_GREATER +[JsonSerializable(typeof(AccessViolationException))] +[JsonSerializable(typeof(Exception))] +[JsonSerializable(typeof(JsonTests.DataAndNonSerializableObject))] +[JsonSerializable(typeof(JsonTests.DataWithSerializableObject))] +[JsonSerializable(typeof(JsonTests.SelfReferencedObject))] +[JsonSerializable(typeof(JsonTests.DataWithSerializableObject))] +internal partial class JsonTestsJsonContext : JsonSerializerContext +{ +} +#endif diff --git a/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs b/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs index ada1545698..7fc9030087 100644 --- a/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs +++ b/test/Sentry.Tests/Internals/MainExceptionProcessorTests.cs @@ -117,6 +117,8 @@ public void Process_AggregateException() sut.Process(BuildAggregateException(), evt); var last = evt.SentryExceptions!.Last(); +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/issues/2772 Assert.NotNull(last.Stacktrace); var mechanism = last.Mechanism; Assert.NotNull(mechanism); diff --git a/test/Sentry.Tests/Internals/MainSentryEventProcessorTests.cs b/test/Sentry.Tests/Internals/MainSentryEventProcessorTests.cs index bc52a9d6d4..201c041e19 100644 --- a/test/Sentry.Tests/Internals/MainSentryEventProcessorTests.cs +++ b/test/Sentry.Tests/Internals/MainSentryEventProcessorTests.cs @@ -373,10 +373,7 @@ public void Process_Modules_NotEmpty() [Fact] public void Process_Modules_IsEmpty_WhenSpecified() { - // Note: this property is obsolete, test is kept for backwards compatibility check -#pragma warning disable CS0618 // Type or member is obsolete - _fixture.SentryOptions.ReportAssemblies = false; -#pragma warning restore CS0618 // Type or member is obsolete + _fixture.SentryOptions.ReportAssembliesMode = ReportAssembliesMode.None; var sut = _fixture.GetSut(); var evt = new SentryEvent(); diff --git a/test/Sentry.Tests/Internals/MemoryInfoTests.WriteTo.Core3_1.verified.txt b/test/Sentry.Tests/Internals/MemoryInfoTests.WriteTo.Core3_1.verified.txt deleted file mode 100644 index c053f03c62..0000000000 --- a/test/Sentry.Tests/Internals/MemoryInfoTests.WriteTo.Core3_1.verified.txt +++ /dev/null @@ -1,8 +0,0 @@ -{ - allocated_bytes: 1, - fragmented_bytes: 2, - heap_size_bytes: 3, - high_memory_load_threshold_bytes: 4, - total_available_memory_bytes: 5, - memory_load_bytes: 6 -} diff --git a/test/Sentry.Tests/Internals/MemoryInfoTests.WriteTo.DotNet8_0.verified.txt b/test/Sentry.Tests/Internals/MemoryInfoTests.WriteTo.DotNet8_0.verified.txt new file mode 100644 index 0000000000..05e978d7b7 --- /dev/null +++ b/test/Sentry.Tests/Internals/MemoryInfoTests.WriteTo.DotNet8_0.verified.txt @@ -0,0 +1,19 @@ +{ + allocated_bytes: 1, + fragmented_bytes: 2, + heap_size_bytes: 3, + high_memory_load_threshold_bytes: 4, + total_available_memory_bytes: 5, + memory_load_bytes: 6, + total_committed_bytes: 7, + promoted_bytes: 8, + pinned_objects_count: 9, + pause_time_percentage: 10, + index: 11, + finalization_pending_count: 12, + compacted: true, + concurrent: false, + pause_durations: [ + 1000 + ] +} \ No newline at end of file diff --git a/test/Sentry.Tests/Internals/ProcessInfoTests.cs b/test/Sentry.Tests/Internals/ProcessInfoTests.cs index 610beee7dd..c30bb46fff 100644 --- a/test/Sentry.Tests/Internals/ProcessInfoTests.cs +++ b/test/Sentry.Tests/Internals/ProcessInfoTests.cs @@ -5,17 +5,6 @@ public class ProcessInfoTests [SkippableFact] public async Task Ctor_StartupTimeSimilarToUtcNow() { - -#if NETCOREAPP - // Skip this test when running on macOS with Apple Silicon (M1) hardware due to a bug in .NET with Process.StartTime. - // See https://github.com/getsentry/sentry-dotnet/issues/1508 - // and https://github.com/dotnet/runtime/issues/66170 - // TODO: When .NET resolves the issue, change the version number below to reflect the fixed version of 3.1.xxx - Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && - RuntimeInformation.OSDescription.Contains("ARM64") && - Environment.Version < Version.Parse("5.0.0")); -#endif - //Arrange var options = new SentryOptions(); diff --git a/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.cs b/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.cs index 665d2650f9..02f7539c39 100644 --- a/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.cs +++ b/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.cs @@ -23,6 +23,8 @@ public void Create_NoExceptionAndAttachStackTraceOptionFalse_NullResult() Assert.Null(sut.Create()); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Fact] public void Create_NoExceptionAndAttachStackTraceOptionOnWithOriginalMode_CurrentStackTrace() { @@ -45,13 +47,15 @@ public void Create_NoExceptionAndAttachStackTraceOptionOnWithOriginalMode_Curren ) == true); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Theory] [InlineData(StackTraceMode.Original, "AsyncWithWait_StackTrace { }")] [InlineData(StackTraceMode.Enhanced, "void SentryStackTraceFactoryTests.AsyncWithWait_StackTrace(StackTraceMode mode, string method)+() => { }")] public void AsyncWithWait_StackTrace(StackTraceMode mode, string method) { - _fixture.SentryOptions.AttachStacktrace = true; _fixture.SentryOptions.StackTraceMode = mode; + _fixture.SentryOptions.AttachStacktrace = true; var sut = _fixture.GetSut(); SentryStackTrace stackTrace = null!; @@ -67,13 +71,15 @@ public void AsyncWithWait_StackTrace(StackTraceMode mode, string method) } } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Theory] [InlineData(StackTraceMode.Original, "MoveNext")] // Should be "AsyncWithAwait_StackTrace { }", but see note in SentryStackTraceFactory [InlineData(StackTraceMode.Enhanced, "async Task SentryStackTraceFactoryTests.AsyncWithAwait_StackTrace(StackTraceMode mode, string method)+(?) => { }")] public async Task AsyncWithAwait_StackTrace(StackTraceMode mode, string method) { - _fixture.SentryOptions.AttachStacktrace = true; _fixture.SentryOptions.StackTraceMode = mode; + _fixture.SentryOptions.AttachStacktrace = true; var sut = _fixture.GetSut(); var stackTrace = await Task.Run(async () => @@ -87,6 +93,8 @@ public async Task AsyncWithAwait_StackTrace(StackTraceMode mode, string method) Assert.Equal(method, stackTrace.Frames.Last().Function); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Fact] public void Create_NoExceptionAndAttachStackTraceOptionOnWithEnhancedMode_CurrentStackTrace() { @@ -109,6 +117,8 @@ public void Create_NoExceptionAndAttachStackTraceOptionOnWithEnhancedMode_Curren ) == true); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Fact] public void Create_WithExceptionAndDefaultAttachStackTraceOption_HasStackTrace() { @@ -125,6 +135,8 @@ public void Create_WithExceptionAndDefaultAttachStackTraceOption_HasStackTrace() Assert.NotNull(sut.Create(exception)); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Fact] public void Create_WithExceptionAndAttachStackTraceOptionOn_HasStackTrace() { @@ -144,6 +156,8 @@ public void Create_WithExceptionAndAttachStackTraceOptionOn_HasStackTrace() Assert.Equal(new StackTrace(exception, true).FrameCount, stackTrace?.Frames.Count); } +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [SkippableFact] public void FileNameShouldBeRelative() { @@ -183,6 +197,8 @@ public void FileNameShouldBeRelative() private static string GetThisFilePath([CallerFilePath] string path = null) => path; +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [Theory] [InlineData(StackTraceMode.Original, "ByRefMethodThatThrows")] [InlineData(StackTraceMode.Enhanced, "(Fixture f, int b) SentryStackTraceFactoryTests.ByRefMethodThatThrows(int value, in int valueIn, ref int valueRef, out int valueOut)")] diff --git a/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.verify.cs b/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.verify.cs index e701641303..6e3990775b 100644 --- a/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.verify.cs +++ b/test/Sentry.Tests/Internals/SentryStackTraceFactoryTests.verify.cs @@ -4,6 +4,8 @@ // Stack trace filters out Sentry frames by namespace namespace Other.Tests.Internals; +// TODO: Create integration test to test this behaviour when publishing AOT apps +// See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 [UsesVerify] public partial class SentryStackTraceFactoryTests { @@ -14,7 +16,6 @@ public Task MethodGeneric(StackTraceMode mode) { // TODO: Mono gives different results. Investigate why. Skip.If(RuntimeInfo.GetRuntime().IsMono(), "Not supported on Mono"); - _fixture.SentryOptions.StackTraceMode = mode; // Arrange diff --git a/test/Sentry.Tests/Internals/SettingLocatorTests.cs b/test/Sentry.Tests/Internals/SettingLocatorTests.cs index c7b9e3b2ac..f4f1c4d660 100644 --- a/test/Sentry.Tests/Internals/SettingLocatorTests.cs +++ b/test/Sentry.Tests/Internals/SettingLocatorTests.cs @@ -153,14 +153,11 @@ public void GetDsn_WithOptionAlreadySet_IgnoresAttribute() } [Fact] - public void GetDsn_WithNoValueAnywhere_ReturnsAndSetsDisabledDsn() + public void GetDsn_WithNoValueAnywhere_ThrowsException() { var options = new SentryOptions(); - var dsn = options.SettingLocator.GetDsn(); - - Assert.Equal(DisableSdkDsnValue, dsn); - Assert.Equal(DisableSdkDsnValue, options.Dsn); + Assert.Throws(() => options.SettingLocator.GetDsn()); } [Fact] diff --git a/test/Sentry.Tests/Internals/ThreadsafeCounterDictionaryTests.cs b/test/Sentry.Tests/Internals/ThreadsafeCounterDictionaryTests.cs index a7857ac33a..70c51fecb6 100644 --- a/test/Sentry.Tests/Internals/ThreadsafeCounterDictionaryTests.cs +++ b/test/Sentry.Tests/Internals/ThreadsafeCounterDictionaryTests.cs @@ -142,8 +142,8 @@ public void CanReadAllCountersWithoutResetting() counters.Increment("bar"); counters.Increment("bar"); - var actual1 = counters.ToDictionary(); - var actual2 = counters.ToDictionary(); + var actual1 = counters.ToDict(); + var actual2 = counters.ToDict(); var expected = new Dictionary {{"foo", 1}, {"bar", 2}}; Assert.Equal(expected, actual1); @@ -159,7 +159,7 @@ public void CanReadAndResetAllCounters() counters.Increment("bar"); var actual1 = counters.ReadAllAndReset(); - var actual2 = counters.ToDictionary(); + var actual2 = counters.ToDict(); var expected1 = new Dictionary {{"foo", 1}, {"bar", 2}}; var expected2 = new Dictionary {{"foo", 0}, {"bar", 0}}; diff --git a/test/Sentry.Tests/ModuleInit.cs b/test/Sentry.Tests/ModuleInit.cs index 57513fea72..996e8f7dd4 100644 --- a/test/Sentry.Tests/ModuleInit.cs +++ b/test/Sentry.Tests/ModuleInit.cs @@ -2,6 +2,7 @@ public static class ModuleInit { [ModuleInitializer] + [SuppressMessage("Usage", "CA2255:The \'ModuleInitializer\' attribute should not be used in libraries")] public static void Init() { CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US"); diff --git a/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs b/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs index 6480edce23..e5ecc83b4a 100644 --- a/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs +++ b/test/Sentry.Tests/PlatformAbstractions/RuntimeInfoTests.cs @@ -16,8 +16,6 @@ public void GetRuntime_AllProperties() #if NET5_0_OR_GREATER Assert.Equal(".NET", actual.Name); Assert.NotNull(actual.Identifier); -#elif NETCOREAPP - Assert.Equal(".NET Core", actual.Name); #elif NETFRAMEWORK if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -33,6 +31,21 @@ public void GetRuntime_AllProperties() #endif } + [Fact] + public void GetRuntime_NetCoreVersion() + { + var actual = RuntimeInfo.GetRuntime(); + Assert.NotNull(actual); + +#if NET8_0 + Assert.StartsWith("8.0", actual.Version); +#elif NET7_0 + Assert.StartsWith("7.0", actual.Version); +#elif NET6_0 + Assert.StartsWith("6.0", actual.Version); +#endif + } + [Theory] [MemberData(nameof(ParseTestCases))] public void Parse_TestCases(ParseTestCase parseTestCase) diff --git a/test/Sentry.Tests/Platforms/Android/BindableSentryOptionsTests.cs b/test/Sentry.Tests/Platforms/Android/BindableSentryOptionsTests.cs new file mode 100644 index 0000000000..3f5f9f5fd9 --- /dev/null +++ b/test/Sentry.Tests/Platforms/Android/BindableSentryOptionsTests.cs @@ -0,0 +1,30 @@ +#if ANDROID +using Microsoft.Extensions.Configuration; + +namespace Sentry.Tests.Platforms.Android; + +public class BindableSentryOptionsTests : BindableTests +{ + [Fact] + public void BindableProperties_MatchOptionsProperties() + { + var actual = GetPropertyNames(); + AssertContainsAllOptionsProperties(actual); + } + + [Fact] + public void ApplyTo_SetsOptionsFromConfig() + { + // Arrange + var actual = new SentryOptions.AndroidOptions(new SentryOptions()); + var bindable = new BindableSentryOptions.AndroidOptions(); + + // Act + Fixture.Config.Bind(bindable); + bindable.ApplyTo(actual); + + // Assert + AssertContainsExpectedPropertyValues(actual); + } +} +#endif diff --git a/test/Sentry.Tests/Platforms/iOS/BindableSentryOptionsTests.cs b/test/Sentry.Tests/Platforms/iOS/BindableSentryOptionsTests.cs new file mode 100644 index 0000000000..8dc7b54474 --- /dev/null +++ b/test/Sentry.Tests/Platforms/iOS/BindableSentryOptionsTests.cs @@ -0,0 +1,35 @@ +# if __IOS__ +using Microsoft.Extensions.Configuration; + +namespace Sentry.Tests.Platforms.iOS; + +public class BindableSentryOptionsTests : BindableTests +{ + public BindableSentryOptionsTests() + : base(nameof(SentryOptions.IosOptions.UrlSessionDelegate)) + { + } + + [Fact] + public void BindableProperties_MatchOptionsProperties() + { + var actual = GetPropertyNames(); + AssertContainsAllOptionsProperties(actual); + } + + [Fact] + public void ApplyTo_SetsOptionsFromConfig() + { + // Arrange + var actual = new SentryOptions.IosOptions(new SentryOptions()); + var bindable = new BindableSentryOptions.IosOptions(); + + // Act + Fixture.Config.Bind(bindable); + bindable.ApplyTo(actual); + + // Assert + AssertContainsExpectedPropertyValues(actual); + } +} +#endif diff --git a/test/Sentry.Tests/Protocol/Context/RuntimeTests.cs b/test/Sentry.Tests/Protocol/Context/RuntimeTests.cs index 0a9f88028c..6bae95b3c1 100644 --- a/test/Sentry.Tests/Protocol/Context/RuntimeTests.cs +++ b/test/Sentry.Tests/Protocol/Context/RuntimeTests.cs @@ -45,9 +45,7 @@ public void Clone_CopyValues() Version = "version" }; -#pragma warning disable CS0618 var clone = sut.Clone(); -#pragma warning restore CS0618 Assert.Equal(sut.Name, clone.Name); Assert.Equal(sut.RawDescription, clone.RawDescription); diff --git a/test/Sentry.Tests/Protocol/DebugImageTests.cs b/test/Sentry.Tests/Protocol/DebugImageTests.cs index dd13dfc71c..40d181c0c8 100644 --- a/test/Sentry.Tests/Protocol/DebugImageTests.cs +++ b/test/Sentry.Tests/Protocol/DebugImageTests.cs @@ -15,7 +15,7 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() var sut = new DebugImage { Type = "elf", - ImageAddress = "0xffffffff", + ImageAddress = 5, ImageSize = 1234, DebugId = "900f7d1b868432939de4457478f34720", DebugFile = "libc.debug", @@ -28,7 +28,7 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() Assert.Equal(""" { "type": "elf", - "image_addr": "0xffffffff", + "image_addr": "0x5", "image_size": 1234, "debug_id": "900f7d1b868432939de4457478f34720", "debug_file": "libc.debug", diff --git a/test/Sentry.Tests/Protocol/DsnTests.cs b/test/Sentry.Tests/Protocol/DsnTests.cs index b45fe98b22..abb5144469 100644 --- a/test/Sentry.Tests/Protocol/DsnTests.cs +++ b/test/Sentry.Tests/Protocol/DsnTests.cs @@ -17,15 +17,6 @@ public void Ctor_SampleValidDsn_CorrectlyConstructs() Assert.Equal(ValidDsn, dsn.ToString()); } - [Fact] - public void Ctor_SampleValidDsnWithSecret_CorrectlyConstructs() - { -#pragma warning disable CS0618 - var dsn = Dsn.Parse(ValidDsnWithSecret); - Assert.Equal(ValidDsnWithSecret, dsn.ToString()); -#pragma warning restore CS0618 - } - [Fact] public void Ctor_NotUri_ThrowsUriFormatException() { @@ -140,14 +131,6 @@ public void TryParse_SampleValidDsn_Succeeds() Assert.NotNull(Dsn.TryParse(ValidDsn)); } - [Fact] - public void TryParse_SampleValidDsnWithSecret_Succeeds() - { -#pragma warning disable CS0618 - Assert.NotNull(Dsn.TryParse(ValidDsnWithSecret)); -#pragma warning restore CS0618 - } - [Fact] public void TryParse_SampleInvalidDsn_Fails() { diff --git a/test/Sentry.Tests/Protocol/Exceptions/SentryStackFrameTests.cs b/test/Sentry.Tests/Protocol/Exceptions/SentryStackFrameTests.cs index f36cee2514..18ddc2cad2 100644 --- a/test/Sentry.Tests/Protocol/Exceptions/SentryStackFrameTests.cs +++ b/test/Sentry.Tests/Protocol/Exceptions/SentryStackFrameTests.cs @@ -30,10 +30,7 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() Platform = "Platform", ImageAddress = 3, SymbolAddress = 4, -#pragma warning disable 0618 - InstructionOffset = 5, -#pragma warning restore 0618 - InstructionAddress = "0xffffffff", + InstructionAddress = 5, AddressMode = "rel:0" }; @@ -66,8 +63,7 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() "platform": "Platform", "image_addr": "0x3", "symbol_addr": "0x4", - "instruction_addr": "0xffffffff", - "instruction_offset": 5, + "instruction_addr": "0x5", "addr_mode": "rel:0" } """, @@ -217,4 +213,37 @@ public void ConfigureAppFrame_InAppAlreadySet_InAppIgnored() // Assert Assert.True(sut.InApp, "InApp started as true but ConfigureAppFrame changed it to false."); } + + [Fact] + public void ConfigureAppFrame_NativeAOTWithoutMethodInfo_InAppIsNull() + { + // See values set by TryCreateNativeAOTFrame + var sut = new SentryStackFrame + { + ImageAddress = 1, + InstructionAddress = 2 + }; + + // Act + sut.ConfigureAppFrame(new()); + + // Assert + Assert.Null(sut.InApp); + } + +#if NET8_0_OR_GREATER + [Fact] + public void ConfigureAppFrame_NativeAOTWithoutMethodInfo_InAppIsSet() + { + var sut = DebugStackTrace.ParseNativeAOTToString( + "System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x42 at offset 66 in file:line:column :0:0"); + sut.ConfigureAppFrame(new()); + Assert.False(sut.InApp); + + sut = DebugStackTrace.ParseNativeAOTToString( + "Program.<
$>d__0.MoveNext() + 0xdd at offset 221 in file:line:column :0:0"); + sut.ConfigureAppFrame(new()); + Assert.True(sut.InApp); + } +#endif } diff --git a/test/Sentry.Tests/Protocol/MeasurementTests.cs b/test/Sentry.Tests/Protocol/MeasurementTests.cs index 762a74a9bb..bfeca3312a 100644 --- a/test/Sentry.Tests/Protocol/MeasurementTests.cs +++ b/test/Sentry.Tests/Protocol/MeasurementTests.cs @@ -187,6 +187,7 @@ public void Transaction_SetMeasurement_IntValue() t.Measurements.Count == 1 && t.Measurements["foo"].Value.As() == int.MaxValue && t.Measurements["foo"].Unit == EmptyUnit), + Arg.Any(), Arg.Any() ); } @@ -214,6 +215,7 @@ public void Transaction_SetMeasurement_LongValue() t.Measurements.Count == 1 && t.Measurements["foo"].Value.As() == long.MaxValue && t.Measurements["foo"].Unit == EmptyUnit), + Arg.Any(), Arg.Any() ); } @@ -241,6 +243,7 @@ public void Transaction_SetMeasurement_ULongValue() t.Measurements.Count == 1 && t.Measurements["foo"].Value.As() == ulong.MaxValue && t.Measurements["foo"].Unit == EmptyUnit), + Arg.Any(), Arg.Any() ); } @@ -268,6 +271,7 @@ public void Transaction_SetMeasurement_DoubleValue() t.Measurements.Count == 1 && Math.Abs(t.Measurements["foo"].Value.As() - double.MaxValue) < double.Epsilon && t.Measurements["foo"].Unit == EmptyUnit), + Arg.Any(), Arg.Any() ); } @@ -295,6 +299,7 @@ public void Transaction_SetMeasurement_IntValue_WithUnit() t.Measurements.Count == 1 && t.Measurements["foo"].Value.As() == int.MaxValue && t.Measurements["foo"].Unit == MeasurementUnit.Duration.Nanosecond), + Arg.Any(), Arg.Any() ); } @@ -322,6 +327,7 @@ public void Transaction_SetMeasurement_LongValue_WithUnit() t.Measurements.Count == 1 && t.Measurements["foo"].Value.As() == long.MaxValue && t.Measurements["foo"].Unit == MeasurementUnit.Duration.Nanosecond), + Arg.Any(), Arg.Any() ); } @@ -349,6 +355,7 @@ public void Transaction_SetMeasurement_ULongValue_WithUnit() t.Measurements.Count == 1 && t.Measurements["foo"].Value.As() == ulong.MaxValue && t.Measurements["foo"].Unit == MeasurementUnit.Duration.Nanosecond), + Arg.Any(), Arg.Any() ); } @@ -376,6 +383,7 @@ public void Transaction_SetMeasurement_DoubleValue_WithUnit() t.Measurements.Count == 1 && Math.Abs(t.Measurements["foo"].Value.As() - double.MaxValue) < double.Epsilon && t.Measurements["foo"].Unit == MeasurementUnit.Duration.Nanosecond), + Arg.Any(), Arg.Any() ); } diff --git a/test/Sentry.Tests/Protocol/ProfilerTests.ProfileInfo_Serialization.verified.txt b/test/Sentry.Tests/Protocol/ProfilerTests.ProfileInfo_Serialization.verified.txt index a9b12aa921..faac5c1682 100644 --- a/test/Sentry.Tests/Protocol/ProfilerTests.ProfileInfo_Serialization.verified.txt +++ b/test/Sentry.Tests/Protocol/ProfilerTests.ProfileInfo_Serialization.verified.txt @@ -8,7 +8,7 @@ debug_meta: { images: [ { - image_addr: 0xABCDEF + image_addr: 0x5 } ] }, diff --git a/test/Sentry.Tests/Protocol/ProfilerTests.verify.cs b/test/Sentry.Tests/Protocol/ProfilerTests.verify.cs index 34165209a9..7d58ea2435 100644 --- a/test/Sentry.Tests/Protocol/ProfilerTests.verify.cs +++ b/test/Sentry.Tests/Protocol/ProfilerTests.verify.cs @@ -82,7 +82,7 @@ public Task ProfileInfo_Serialization() sut.StartTimestamp = DateTimeOffset.UtcNow; sut.DebugMeta.Images = new List { new () { - ImageAddress = "0xABCDEF" + ImageAddress = 5 } }; sut.Profile = CreateSampleProfile(); diff --git a/test/Sentry.Tests/Protocol/SentryEventTests.verify.cs b/test/Sentry.Tests/Protocol/SentryEventTests.verify.cs index 952229f1c6..6a16d77c0c 100644 --- a/test/Sentry.Tests/Protocol/SentryEventTests.verify.cs +++ b/test/Sentry.Tests/Protocol/SentryEventTests.verify.cs @@ -3,7 +3,6 @@ namespace Sentry.Tests.Protocol; [UsesVerify] public partial class SentryEventTests { - [Fact] public async Task SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() { diff --git a/test/Sentry.Tests/Protocol/TransactionTests.cs b/test/Sentry.Tests/Protocol/TransactionTests.cs index d29fc867c6..dd43d92398 100644 --- a/test/Sentry.Tests/Protocol/TransactionTests.cs +++ b/test/Sentry.Tests/Protocol/TransactionTests.cs @@ -38,18 +38,13 @@ public async Task NewTransactionTracer_IdleTimeoutProvided_AutomaticallyFinishes Debug = true }; var hub = new Hub(options, client); - var context = new TransactionContext( + var context = new TransactionContext("my name", + "my operation", SpanId.Create(), SpanId.Create(), SentryId.Create(), - "my name", - "my operation", "description", - SpanStatus.Ok, - null, - true, - TransactionNameSource.Component - ); + SpanStatus.Ok, null, true, TransactionNameSource.Component); var transaction = new TransactionTracer(hub, context, TimeSpan.FromMilliseconds(2)); @@ -75,18 +70,13 @@ public void Redact_Redacts_Urls() var breadcrumbMessage = "message https://user@sentry.io"; // should be redacted var breadcrumbDataValue = "data-value https://user@sentry.io"; // should be redacted var tagValue = "tag_value https://user@not.redacted"; - var context = new TransactionContext( + var context = new TransactionContext(name, + operation, SpanId.Create(), SpanId.Create(), SentryId.Create(), - name, - operation, description, - SpanStatus.AlreadyExists, - null, - true, - TransactionNameSource.Component - ); + SpanStatus.AlreadyExists, null, true, TransactionNameSource.Component); var txTracer = new TransactionTracer(DisabledHub.Instance, context) { @@ -172,18 +162,14 @@ public void SerializeObject_AllPropertiesSetToNonDefault_SerializesValidObject() { // Arrange var timestamp = DateTimeOffset.MaxValue; - var context = new TransactionContext( + var context = new TransactionContext("name123", + "op123", SpanId.Create(), SpanId.Create(), - SentryId.Create(), - "name123", - "op123", - "desc", - SpanStatus.AlreadyExists, - null, // sampling isn't serialized and getting FluentAssertions + SentryId.Create(), // sampling isn't serialized and getting FluentAssertions // to ignore that on Spans and contexts isn't really straight forward - true, - TransactionNameSource.Component); + "desc", + SpanStatus.AlreadyExists, null, true, TransactionNameSource.Component); var transaction = new TransactionTracer(DisabledHub.Instance, context) { @@ -452,18 +438,13 @@ public async Task Finish_SentryRequestTransactionGetsIgnored() Dsn = ValidDsn, }; var hub = new Hub(options, client); - var context = new TransactionContext( + var context = new TransactionContext("my name", + "my operation", SpanId.Create(), SpanId.Create(), SentryId.Create(), - "my name", - "my operation", "description", - SpanStatus.Ok, - null, - true, - TransactionNameSource.Component - ); + SpanStatus.Ok, null, true, TransactionNameSource.Component); var transaction = new TransactionTracer(hub, context, TimeSpan.FromMilliseconds(2)) { @@ -491,7 +472,7 @@ public void Finish_CapturesTransaction() transaction.Finish(); // Assert - client.Received(1).CaptureTransaction(Arg.Any(), Arg.Any()); + client.Received(1).CaptureTransaction(Arg.Any(), Arg.Any(), Arg.Any()); } [Fact] @@ -520,9 +501,7 @@ public void Finish_LinksExceptionToEvent() e.Contexts.Trace.SpanId == transaction.SpanId && e.Contexts.Trace.ParentSpanId == transaction.ParentSpanId ), - Arg.Any(), - Arg.Any() - ); + Arg.Any(), Arg.Any()); } [Fact] diff --git a/test/Sentry.Tests/ScopeTests.cs b/test/Sentry.Tests/ScopeTests.cs index dbd8e9308d..8624cc3ac5 100644 --- a/test/Sentry.Tests/ScopeTests.cs +++ b/test/Sentry.Tests/ScopeTests.cs @@ -624,12 +624,11 @@ public static void ApplyFakeValues(this Scope scope, string salt = "fake") scope.Request = new() { Data = $"{salt} request" }; scope.Contexts.Add($"{salt} context", "{}"); scope.User = new User() { Username = $"{salt} username" }; - scope.Platform = $"{salt} platform"; scope.Release = $"{salt} release"; scope.Distribution = $"{salt} distribution"; scope.Environment = $"{salt} environment"; scope.TransactionName = $"{salt} transaction"; - scope.Transaction = Substitute.For(); + scope.Transaction = Substitute.For(); scope.Fingerprint = new[] { $"{salt} fingerprint" }; scope.AddBreadcrumb(new(message: $"{salt} breadcrumb")); scope.SetExtra("extra", $"{salt} extra"); @@ -643,7 +642,6 @@ public static void ShouldBeEquivalentTo(this Scope source, Scope target) source.Request.Should().BeEquivalentTo(target.Request); source.Contexts.Should().BeEquivalentTo(target.Contexts); source.User.Should().BeEquivalentTo(target.User); - source.Platform.Should().Be(target.Platform); source.Release.Should().Be(target.Release); source.Distribution.Should().Be(target.Distribution); source.Environment.Should().Be(target.Environment); diff --git a/test/Sentry.Tests/Sentry.Tests.csproj b/test/Sentry.Tests/Sentry.Tests.csproj index a0bdebbb3b..13ab9ee2fb 100644 --- a/test/Sentry.Tests/Sentry.Tests.csproj +++ b/test/Sentry.Tests/Sentry.Tests.csproj @@ -1,10 +1,10 @@  - net7.0;net6.0;netcoreapp3.1;net48 - $(TargetFrameworks);net7.0-android - $(TargetFrameworks);net7.0-ios - $(TargetFrameworks);net7.0-maccatalyst + net8.0;net7.0;net6.0;net48 + $(TargetFrameworks);net7.0-android;net8.0-android + $(TargetFrameworks);net7.0-ios;net8.0-ios + $(TargetFrameworks);net7.0-maccatalyst;net8.0-maccatalyst @@ -39,4 +39,9 @@ + + + + + diff --git a/test/Sentry.Tests/SentryClientTests.CaptureEvent_BeforeEventThrows_ErrorToEventBreadcrumb.Core3_1.verified.txt b/test/Sentry.Tests/SentryClientTests.CaptureEvent_BeforeEventThrows_ErrorToEventBreadcrumb.Core3_1.verified.txt deleted file mode 100644 index 6dcf0fd76a..0000000000 --- a/test/Sentry.Tests/SentryClientTests.CaptureEvent_BeforeEventThrows_ErrorToEventBreadcrumb.Core3_1.verified.txt +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - Timestamp: DateTimeOffset_1, - Message: BeforeSend callback failed., - Data: { - message: Exception message!, - stackTrace: -at Task Sentry.Tests.SentryClientTests.CaptureEvent_BeforeEventThrows_ErrorToEventBreadcrumb() -at void Sentry.SentryOptions.SetBeforeSend(...) -at SentryEvent Sentry.SentryClient.BeforeSend(...) - }, - Category: SentryClient, - Level: error - } -] \ No newline at end of file diff --git a/test/Sentry.Tests/SentryClientTests.cs b/test/Sentry.Tests/SentryClientTests.cs index 8b5cc632a0..c13f2475b7 100644 --- a/test/Sentry.Tests/SentryClientTests.cs +++ b/test/Sentry.Tests/SentryClientTests.cs @@ -1,8 +1,6 @@ using Sentry.Internal.Http; using BackgroundWorker = Sentry.Internal.BackgroundWorker; -#pragma warning disable CS0618 - namespace Sentry.Tests; public partial class SentryClientTests @@ -338,7 +336,7 @@ public void CaptureEvent_BeforeSend_GetsHint() var hint = new Hint(); var sut = _fixture.GetSut(); - _ = sut.CaptureEvent(@event, hint); + _ = sut.CaptureEvent(@event, hint: hint); Assert.Same(hint, received); } @@ -1027,6 +1025,89 @@ public void CaptureTransaction_BeforeSendTransaction_RejectEvent() _ = _fixture.BackgroundWorker.DidNotReceive().EnqueueEnvelope(Arg.Any()); } + [Fact] + public void CaptureTransaction_ScopeContainsAttachments_GetAppliedToHint() + { + // Arrange + var transaction = new Transaction("name", "operation") + { + IsSampled = true, + EndTimestamp = DateTimeOffset.Now // finished + }; + var attachments = new List { + AttachmentHelper.FakeAttachment("foo"), + AttachmentHelper.FakeAttachment("bar") + }; + var scope = new Scope(_fixture.SentryOptions); + scope.AddAttachment(attachments[0]); + scope.AddAttachment(attachments[1]); + + Hint hint = null; + _fixture.SentryOptions.SetBeforeSendTransaction((e, h) => { + hint = h; + return e; + }); + + // Act + _fixture.GetSut().CaptureTransaction(transaction, scope, hint); + + // Assert + hint.Should().NotBeNull(); + hint.Attachments.Should().Contain(attachments); + } + + [Fact] + public void CaptureTransaction_AddedTransactionProcessor_ReceivesHint() + { + // Arrange + var processor = Substitute.For(); + processor.Process(Arg.Any(), Arg.Any()).Returns(new Transaction("name", "operation")); + _fixture.SentryOptions.AddTransactionProcessor(processor); + + var transaction = new Transaction("name", "operation") + { + IsSampled = true, + EndTimestamp = DateTimeOffset.Now // finished + }; + + // Act + _fixture.GetSut().CaptureTransaction(transaction); + + // Assert + processor.Received(1).Process(Arg.Any(), Arg.Any()); + } + + [Fact] + public void CaptureTransaction_TransactionProcessor_ReceivesScopeAttachments() + { + // Arrange + var transaction = new Transaction("name", "operation") + { + IsSampled = true, + EndTimestamp = DateTimeOffset.Now // finished + }; + + var processor = Substitute.For(); + Hint hint = null; + processor.Process( + Arg.Any(), + Arg.Do(h => hint = h)) + .Returns(new Transaction("name", "operation")); + _fixture.SentryOptions.AddTransactionProcessor(processor); + + var attachments = new List { AttachmentHelper.FakeAttachment("foo.txt") }; + var scope = new Scope(_fixture.SentryOptions); + scope.AddAttachment(attachments[0]); + + // Act + var client = _fixture.GetSut(); + client.CaptureTransaction(transaction, scope, null); + + // Assert + hint.Should().NotBeNull(); + hint.Attachments.Should().Contain(attachments); + } + [Fact] public void CaptureTransaction_BeforeSendTransaction_GetsHint() { @@ -1045,7 +1126,7 @@ public void CaptureTransaction_BeforeSendTransaction_GetsHint() var sut = _fixture.GetSut(); var hint = new Hint(); - sut.CaptureTransaction(transaction, hint); + sut.CaptureTransaction(transaction, null, hint); Assert.Same(hint, received); } diff --git a/test/Sentry.Tests/SentryGraphQlHttpFailedRequestHandlerTests.cs b/test/Sentry.Tests/SentryGraphQlHttpFailedRequestHandlerTests.cs index 7f8980d858..c620d79f25 100644 --- a/test/Sentry.Tests/SentryGraphQlHttpFailedRequestHandlerTests.cs +++ b/test/Sentry.Tests/SentryGraphQlHttpFailedRequestHandlerTests.cs @@ -100,9 +100,7 @@ public void HandleResponse_NoError_BaseCapturesFailedRequests() // Assert hub.Received(1).CaptureEvent( Arg.Any(), - Arg.Any(), - Arg.Any() - ); + Arg.Any(), Arg.Any()); } [Fact] @@ -125,9 +123,7 @@ public void HandleResponse_Error_Capture() // Assert hub.Received(1).CaptureEvent( Arg.Any(), - Arg.Any(), - Arg.Any() - ); + Arg.Any(), Arg.Any()); } [Fact] @@ -147,7 +143,7 @@ public void HandleResponse_Error_DontSendPii() // Act SentryEvent @event = null; - hub.CaptureEvent(Arg.Do(e => @event = e), Arg.Any()); + hub.CaptureEvent(Arg.Do(e => @event = e), hint: Arg.Any()); sut.HandleResponse(response); // Assert @@ -181,7 +177,7 @@ public void HandleResponse_Error_CaptureRequestAndResponse() SentryEvent @event = null; hub.CaptureEvent( Arg.Do(e => @event = e), - Arg.Any() + hint: Arg.Any() ); // Act @@ -240,7 +236,7 @@ public void HandleResponse_Error_ResponseAsHint() Hint hint = null; hub.CaptureEvent( Arg.Any(), - Arg.Do(h => hint = h) + hint: Arg.Do(h => hint = h) ); sut.HandleResponse(response); diff --git a/test/Sentry.Tests/SentryHttpFailedRequestHandlerTests.cs b/test/Sentry.Tests/SentryHttpFailedRequestHandlerTests.cs index 54e88f40dc..4980929596 100644 --- a/test/Sentry.Tests/SentryHttpFailedRequestHandlerTests.cs +++ b/test/Sentry.Tests/SentryHttpFailedRequestHandlerTests.cs @@ -119,9 +119,7 @@ public void HandleResponse_Capture_FailedRequest() // Assert _hub.Received(1).CaptureEvent( Arg.Any(), - Arg.Any(), - Arg.Any() - ); + Arg.Any(), Arg.Any()); } [Fact] @@ -140,7 +138,7 @@ public void HandleResponse_Capture_FailedRequest_No_Pii() // Act SentryEvent @event = null; - _hub.CaptureEvent(Arg.Do(e => @event = e), Arg.Any()); + ((ISentryClient)_hub).CaptureEvent(Arg.Do(e => @event = e), hint: Arg.Any()); sut.HandleResponse(response); // Assert @@ -170,9 +168,9 @@ public void HandleResponse_Capture_RequestAndResponse() // Act SentryEvent @event = null; - _hub.CaptureEvent( + ((ISentryClient)_hub).CaptureEvent( Arg.Do(e => @event = e), - Arg.Any() + hint: Arg.Any() ); sut.HandleResponse(response); @@ -220,9 +218,9 @@ public void HandleResponse_Capture_Default_SkipCookiesAndHeaders() // Act SentryEvent @event = null; - _hub.CaptureEvent( + ((ISentryClient)_hub).CaptureEvent( Arg.Do(e => @event = e), - Arg.Any() + hint: Arg.Any() ); sut.HandleResponse(response); @@ -252,9 +250,9 @@ public void HandleResponse_Hint_Response() // Act Hint hint = null; - _hub.CaptureEvent( + ((ISentryClient)_hub).CaptureEvent( Arg.Any(), - Arg.Do(h => hint = h) + hint: Arg.Do(h => hint = h) ); sut.HandleResponse(response); diff --git a/test/Sentry.Tests/SentryHttpMessageHandlerTests.cs b/test/Sentry.Tests/SentryHttpMessageHandlerTests.cs index 4d5b7844d7..fc38202019 100644 --- a/test/Sentry.Tests/SentryHttpMessageHandlerTests.cs +++ b/test/Sentry.Tests/SentryHttpMessageHandlerTests.cs @@ -41,7 +41,7 @@ public async Task SendAsync_SentryTraceHeaderNotSet_SetsHeader_WhenUrlMatchesPro var failedRequestHandler = Substitute.For(); var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("localhost") } @@ -73,7 +73,7 @@ public async Task SendAsync_SentryTraceHeaderNotSet_DoesntSetHeader_WhenUrlDoesn var failedRequestHandler = Substitute.For(); var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("foo") } @@ -323,7 +323,7 @@ public void Send_SentryTraceHeaderNotSet_SetsHeader_WhenUrlMatchesPropagationOpt var failedRequestHandler = Substitute.For(); var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("localhost") } @@ -355,7 +355,7 @@ public void Send_SentryTraceHeaderNotSet_DoesntSetHeader_WhenUrlDoesntMatchesPro var failedRequestHandler = Substitute.For(); var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("foo") } diff --git a/test/Sentry.Tests/SentryOptionsTests.cs b/test/Sentry.Tests/SentryOptionsTests.cs index 283a680fee..6afd837660 100644 --- a/test/Sentry.Tests/SentryOptionsTests.cs +++ b/test/Sentry.Tests/SentryOptionsTests.cs @@ -175,10 +175,10 @@ public void IsPerformanceMonitoringEnabled_EnableTracing_False_TracesSampler_Pro } [Fact] - public void CaptureFailedRequests_ByDefault_IsFalse() + public void CaptureFailedRequests_ByDefault_IsTrue() { var sut = new SentryOptions(); - Assert.False(sut.CaptureFailedRequests, "CaptureFailedRequests should be false by default to protect potentially PII (Privately Identifiable Information)"); + Assert.True(sut.CaptureFailedRequests); } [Fact] diff --git a/test/Sentry.Tests/SentrySdkTests.cs b/test/Sentry.Tests/SentrySdkTests.cs index d23cfa5878..dc9dc102f1 100644 --- a/test/Sentry.Tests/SentrySdkTests.cs +++ b/test/Sentry.Tests/SentrySdkTests.cs @@ -79,22 +79,6 @@ public void Init_ValidDsn_EnablesSdk() Assert.True(SentrySdk.IsEnabled); } - [Fact] - public void Init_ValidDsnWithSecret_EnablesSdk() - { - using var _ = SentrySdk.Init(o => - { -#pragma warning disable CS0618 - o.Dsn = ValidDsnWithSecret; -#pragma warning restore CS0618 - o.AutoSessionTracking = false; - o.BackgroundWorker = Substitute.For(); - o.InitNativeSdks = false; - }); - - Assert.True(SentrySdk.IsEnabled); - } - [Fact] public void Init_ValidDsnEnvironmentVariable_EnablesSdk() { @@ -141,6 +125,7 @@ public void Init_EmptyDsn_LogsWarning() { var options = new SentryOptions { + Dsn = Constants.DisableSdkDsnValue, DiagnosticLogger = _logger, Debug = true, InitNativeSdks = false @@ -148,7 +133,7 @@ public void Init_EmptyDsn_LogsWarning() using (SentrySdk.Init(options)) { - _logger.Received(1).Log(SentryLevel.Warning, "Init was called but no DSN was provided nor located. Sentry SDK will be disabled."); + _logger.Received(1).Log(SentryLevel.Warning, "Init called with an empty string as the DSN. Sentry SDK will be disabled."); } } @@ -176,6 +161,7 @@ public void Init_EmptyDsnDisabledDiagnostics_DoesNotLogWarning() { var options = new SentryOptions { + Dsn = Constants.DisableSdkDsnValue, DiagnosticLogger = _logger, Debug = false, InitNativeSdks = false, @@ -467,153 +453,6 @@ async Task ModifyScope() } } - [Obsolete] - [Fact] - public void WithScope_DisabledSdk_CallbackNeverInvoked() - { - var invoked = false; - - // Note: Specifying void in the lambda ensures we are testing WithScope, rather than WithScope. - SentrySdk.WithScope(void (_) => invoked = true); - Assert.False(invoked); - } - - [Obsolete] - [Fact] - public void WithScopeT_DisabledSdk_CallbackNeverInvoked() - { - var invoked = SentrySdk.WithScope(_ => true); - Assert.False(invoked); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsync_DisabledSdk_CallbackNeverInvoked() - { - var invoked = false; - await SentrySdk.WithScopeAsync(_ => - { - invoked = true; - return Task.CompletedTask; - }); - Assert.False(invoked); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsyncT_DisabledSdk_CallbackNeverInvoked() - { - var invoked = await SentrySdk.WithScopeAsync(_ => Task.FromResult(true)); - Assert.False(invoked); - } - - [Obsolete] - [Fact] - public void WithScope_InvokedWithNewScope() - { - var options = new SentryOptions - { - Dsn = ValidDsn, - IsGlobalModeEnabled = false, - AutoSessionTracking = false, - BackgroundWorker = Substitute.For(), - InitNativeSdks = false - }; - - using var _ = SentrySdk.Init(options); - - Scope expected = null; - SentrySdk.ConfigureScope(s => expected = s); - - Scope actual = null; - // Note: Specifying void in the lambda ensures we are testing WithScope, rather than WithScope. - SentrySdk.WithScope(void (s) => actual = s); - - Assert.NotNull(actual); - Assert.NotSame(expected, actual); - SentrySdk.ConfigureScope(s => Assert.Same(expected, s)); - } - - [Obsolete] - [Fact] - public void WithScopeT_InvokedWithNewScope() - { - var options = new SentryOptions - { - Dsn = ValidDsn, - IsGlobalModeEnabled = false, - AutoSessionTracking = false, - BackgroundWorker = Substitute.For(), - InitNativeSdks = false - }; - - using var _ = SentrySdk.Init(options); - - Scope expected = null; - SentrySdk.ConfigureScope(s => expected = s); - - var actual = SentrySdk.WithScope(s => s); - - Assert.NotNull(actual); - Assert.NotSame(expected, actual); - SentrySdk.ConfigureScope(s => Assert.Same(expected, s)); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsync_InvokedWithNewScope() - { - var options = new SentryOptions - { - Dsn = ValidDsn, - IsGlobalModeEnabled = false, - AutoSessionTracking = false, - BackgroundWorker = Substitute.For(), - InitNativeSdks = false - }; - - using var _ = SentrySdk.Init(options); - - Scope expected = null; - SentrySdk.ConfigureScope(s => expected = s); - - Scope actual = null; - await SentrySdk.WithScopeAsync(s => - { - actual = s; - return Task.CompletedTask; - }); - - Assert.NotNull(actual); - Assert.NotSame(expected, actual); - SentrySdk.ConfigureScope(s => Assert.Same(expected, s)); - } - - [Obsolete] - [Fact] - public async Task WithScopeAsyncT_InvokedWithNewScope() - { - var options = new SentryOptions - { - Dsn = ValidDsn, - IsGlobalModeEnabled = false, - AutoSessionTracking = false, - BackgroundWorker = Substitute.For(), - InitNativeSdks = false - }; - - using var _ = SentrySdk.Init(options); - - Scope expected = null; - SentrySdk.ConfigureScope(s => expected = s); - - var actual = await SentrySdk.WithScopeAsync(Task.FromResult); - - Assert.NotNull(actual); - Assert.NotSame(expected, actual); - SentrySdk.ConfigureScope(s => Assert.Same(expected, s)); - } - [Fact] public void CaptureEvent_WithConfiguredScope_ScopeAppliesToEvent() { @@ -829,14 +668,14 @@ public void Implements_ScopeManagement() [Fact] public void InitHub_NoDsn_DisposeDoesNotThrow() { - var sut = SentrySdk.InitHub(new SentryOptions()) as IDisposable; + var sut = SentrySdk.InitHub(new SentryOptions(){Dsn = Constants.DisableSdkDsnValue}) as IDisposable; sut?.Dispose(); } [Fact] public async Task InitHub_NoDsn_FlushAsyncDoesNotThrow() { - var sut = SentrySdk.InitHub(new SentryOptions()); + var sut = SentrySdk.InitHub(new SentryOptions(){Dsn = Constants.DisableSdkDsnValue}); await sut.FlushAsync(); } diff --git a/test/Sentry.Tests/SerializationTests.verify.cs b/test/Sentry.Tests/SerializationTests.verify.cs index 37edd86544..9f6a61f508 100644 --- a/test/Sentry.Tests/SerializationTests.verify.cs +++ b/test/Sentry.Tests/SerializationTests.verify.cs @@ -1,3 +1,7 @@ +#if NET7_0_OR_GREATER +using System.Text.Json.Serialization.Metadata; +#endif + namespace Sentry.Tests; [UsesVerify] @@ -18,6 +22,39 @@ public async Task Serialization(string name, object target) await Verify(json).UseParameters(name); } +#if NET7_0_OR_GREATER + internal class NestedStringClass { public string Value { get; set; } } + internal class NestedIntClass { public int Value { get; set; } } + internal class NestedNIntClass { public nint Value { get; set; } } + internal class NestedNuIntClass { public nuint Value { get; set; } } + internal class NestedIntPtrClass { public IntPtr Value { get; set; } } + internal class NestedNullableIntPtrClass { public IntPtr? Value { get; set; } } + internal class NestedUIntPtrClass { public UIntPtr Value { get; set; } } + internal class NestedNullableUIntPtrClass { public UIntPtr? Value { get; set; } } + + public static IEnumerable GetData() + { + yield return new object[] { "string", "string value" }; + yield return new object[] { "int", 5 }; + + JsonExtensions.ResetSerializerOptions(); + JsonExtensions.AddJsonSerializerContext(options => new SerializationTestsJsonContext(options)); + yield return new object[] { "nested string", new NestedStringClass { Value= "string value" } }; + yield return new object[] { "nested int", new NestedIntClass { Value= 5 } }; + yield return new object[] { "nested nint", new NestedNIntClass { Value= 5 } }; + yield return new object[] { "nested nuint", new NestedNuIntClass { Value= 5 } }; + yield return new object[] { "nested IntPtr", new NestedIntPtrClass { Value= (IntPtr)3 } }; + yield return new object[] { "nested nullable IntPtr", new NestedNullableIntPtrClass { Value= (IntPtr?)3 } }; + yield return new object[] { "nested UIntPtr", new NestedUIntPtrClass { Value= (UIntPtr)3 } }; + yield return new object[] { "nested nullable UIntPtr", new NestedNullableUIntPtrClass { Value= (UIntPtr?)3 } }; + + JsonExtensions.ResetSerializerOptions(); + JsonExtensions.AddJsonConverter(new CustomObjectConverter()); + JsonExtensions.AddJsonSerializerContext(options => new SerializationTestsJsonContext(options)); + yield return new object[] {"custom object with value", new CustomObject("test")}; + yield return new object[] {"custom object with null", new CustomObject(null)}; + } +#else public static IEnumerable GetData() { yield return new object[] {"string", "string value"}; @@ -36,6 +73,7 @@ public static IEnumerable GetData() yield return new object[] {"custom object with value", new CustomObject("test")}; yield return new object[] {"custom object with null", new CustomObject(null)}; } +#endif public class CustomObject { @@ -56,3 +94,18 @@ public override void Write(Utf8JsonWriter writer, CustomObject value, JsonSerial => writer.WriteStringValue(value.Value); } } + +#if NET7_0_OR_GREATER +[JsonSerializable(typeof(SerializationTests.CustomObject))] +[JsonSerializable(typeof(SerializationTests.NestedStringClass))] +[JsonSerializable(typeof(SerializationTests.NestedIntClass))] +[JsonSerializable(typeof(SerializationTests.NestedNIntClass))] +[JsonSerializable(typeof(SerializationTests.NestedNuIntClass))] +[JsonSerializable(typeof(SerializationTests.NestedIntPtrClass))] +[JsonSerializable(typeof(SerializationTests.NestedNullableIntPtrClass))] +[JsonSerializable(typeof(SerializationTests.NestedUIntPtrClass))] +[JsonSerializable(typeof(SerializationTests.NestedNullableUIntPtrClass))] +internal partial class SerializationTestsJsonContext : JsonSerializerContext +{ +} +#endif diff --git a/test/Sentry.Tests/TracePropagationTargetTests.cs b/test/Sentry.Tests/TracePropagationTargetTests.cs index fca8772b3d..f4a2dec2c1 100644 --- a/test/Sentry.Tests/TracePropagationTargetTests.cs +++ b/test/Sentry.Tests/TracePropagationTargetTests.cs @@ -14,8 +14,8 @@ public void SentryOptions_TracePropagationTargets_DefaultAll() public void SentryOptions_TracePropagationTargets_AddRemovesDefault() { var options = new SentryOptions(); - options.TracePropagationTargets.Add(new TracePropagationTarget("foo")); - options.TracePropagationTargets.Add(new TracePropagationTarget("bar")); + options.TracePropagationTargets.Add(new SubstringOrRegexPattern("foo")); + options.TracePropagationTargets.Add(new SubstringOrRegexPattern("bar")); Assert.Equal(2, options.TracePropagationTargets.Count); Assert.Equal("foo", options.TracePropagationTargets[0].ToString()); @@ -28,9 +28,9 @@ public void SentryOptions_TracePropagationTargets_SetRemovesDefault() var options = new SentryOptions(); var targets = new [] { - new TracePropagationTarget(".*"), - new TracePropagationTarget("foo"), - new TracePropagationTarget("bar") + new SubstringOrRegexPattern(".*"), + new SubstringOrRegexPattern("foo"), + new SubstringOrRegexPattern("bar") }; options.TracePropagationTargets = targets; @@ -59,7 +59,7 @@ public void SentryOptions_TracePropagationTargets_EmptyPropagatesNone() { var options = new SentryOptions { - TracePropagationTargets = new List() + TracePropagationTargets = new List() }; var result1 = options.TracePropagationTargets.ContainsMatch("foo"); @@ -76,7 +76,7 @@ public void SentryOptions_TracePropagationTargets_OneMatchPropagates() { var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("foo"), new("localhost"), @@ -93,7 +93,7 @@ public void SentryOptions_TracePropagationTargets_MultipleMatchesPropagates() { var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("foo"), new("localhost"), @@ -110,7 +110,7 @@ public void SentryOptions_TracePropagationTargets_NoMatchesDoesntPropagates() { var options = new SentryOptions { - TracePropagationTargets = new List + TracePropagationTargets = new List { new("foo"), new("localhost"), diff --git a/test/Sentry.Tests/UnobservedTaskExceptionIntegrationTests.cs b/test/Sentry.Tests/UnobservedTaskExceptionIntegrationTests.cs index 58b803bdff..020a9f1e16 100644 --- a/test/Sentry.Tests/UnobservedTaskExceptionIntegrationTests.cs +++ b/test/Sentry.Tests/UnobservedTaskExceptionIntegrationTests.cs @@ -4,7 +4,7 @@ public class UnobservedTaskExceptionIntegrationTests { private class Fixture { - public IHubEx Hub { get; set; } = Substitute.For(); + public IHub Hub { get; set; } = Substitute.For(); public IAppDomain AppDomain { get; set; } = Substitute.For(); public Fixture() => Hub.IsEnabled.Returns(true); @@ -16,6 +16,7 @@ private class Fixture private SentryOptions SentryOptions { get; } = new(); +#if !NET7_0_OR_GREATER // This is disabled on net7, see https://github.com/getsentry/sentry-dotnet/pull/2894 [Fact] public void Handle_WithException_CaptureEvent() { @@ -24,8 +25,9 @@ public void Handle_WithException_CaptureEvent() sut.Handle(this, new UnobservedTaskExceptionEventArgs(new AggregateException())); - _ = _fixture.Hub.Received(1).CaptureEventInternal(Arg.Any()); + _ = _fixture.Hub.Received(1).CaptureEvent(Arg.Any()); } +#endif // Test is flaky on mobile in CI. #if !(__MOBILE__ && CI_BUILD) @@ -35,7 +37,7 @@ public void Handle_UnobservedTaskException_CaptureEvent() _fixture.AppDomain = AppDomainAdapter.Instance; var captureCalledEvent = new ManualResetEvent(false); SentryEvent capturedEvent = null; - _fixture.Hub.When(x => x.CaptureEventInternal(Arg.Any())) + _fixture.Hub.When(x => x.CaptureEvent(Arg.Any())) .Do(callInfo => { capturedEvent = callInfo.Arg(); @@ -86,6 +88,8 @@ public void Handle_UnobservedTaskException_CaptureEvent() // The first should be the actual exception that was unobserved. var actualException = exceptions[0]; + // TODO: Create integration test to test this behaviour when publishing AOT apps + // See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 Assert.NotNull(actualException.Stacktrace); Assert.NotNull(actualException.Mechanism); Assert.Equal("chained", actualException.Mechanism.Type); @@ -97,6 +101,8 @@ public void Handle_UnobservedTaskException_CaptureEvent() // The last should be the aggregate exception that raised the UnobservedTaskException event. var aggregateException = exceptions[1]; + // TODO: Create integration test to test this behaviour when publishing AOT apps + // See https://github.com/getsentry/sentry-dotnet/pull/2732#discussion_r1371006441 Assert.Null(aggregateException.Stacktrace); Assert.NotNull(aggregateException.Mechanism); Assert.Equal("UnobservedTaskException", aggregateException.Mechanism.Type); diff --git a/test/SingleFileTestApp/SingleFileTestApp.csproj b/test/SingleFileTestApp/SingleFileTestApp.csproj index 65158a7e42..13285771a6 100644 --- a/test/SingleFileTestApp/SingleFileTestApp.csproj +++ b/test/SingleFileTestApp/SingleFileTestApp.csproj @@ -7,6 +7,7 @@ 11 true true + true diff --git a/test/sentry-cli-integration.Tests.ps1 b/test/sentry-cli-integration.Tests.ps1 deleted file mode 100644 index 99f1840c0d..0000000000 --- a/test/sentry-cli-integration.Tests.ps1 +++ /dev/null @@ -1,134 +0,0 @@ -using namespace System.Runtime.InteropServices - -Set-StrictMode -Version Latest -$ErrorActionPreference = 'Stop' - -# In CI, the module is loaded automatically -if (!(Test-Path env:CI )) -{ - Import-Module $PSScriptRoot/../../github-workflows/sentry-cli/integration-test/action.psm1 -Force -} - -BeforeAll { - function DotnetBuild([string]$Sample, [bool]$Symbols, [bool]$Sources, [string]$TargetFramework = '') - { - $rootDir = "$(Get-Item $PSScriptRoot/../../)" - $framework = $TargetFramework -eq '' ? '' : @('-f', $TargetFramework) - - Invoke-SentryServer { - Param([string]$url) - Write-Host "Building $Sample" - dotnet build "samples/$sample/$sample.csproj" -c Release $framework --no-restore --nologo ` - /p:UseSentryCLI=true ` - /p:SentryUploadSymbols=$Symbols ` - /p:SentryUploadSources=$Sources ` - /p:SentryOrg=org ` - /p:SentryProject=project ` - /p:SentryUrl=$url ` - /p:SentryAuthToken=dummy ` - | ForEach-Object { - if ($_ -match "^Time Elapsed ") - { - "Time Elapsed [value removed]" - } - elseif ($_ -match "\[[0-9/]+\]") - { - # Skip lines like `[102/103] Sentry.Samples.Maui.dll -> Sentry.Samples.Maui.dll.so` - } - else - { - "$_". ` - Replace($rootDir, ''). ` - Replace('\', '/') - } - } - | ForEach-Object { - Write-Host " $_" - $_ - } - } - } -} - -Describe 'CLI-integration' { - - It "uploads symbols and sources for a console app build" { - $result = DotnetBuild 'Sentry.Samples.Console.Basic' $True $True - $result.ScriptOutput | Should -Contain 'Build succeeded.' - $result.HasErrors() | Should -BeFalse - $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( - 'Sentry.pdb', - 'Sentry.Samples.Console.Basic.pdb', - 'Sentry.Samples.Console.Basic.src.zip') - } - - It "uploads symbols for a console app build" { - $result = DotnetBuild 'Sentry.Samples.Console.Basic' $True $False - $result.ScriptOutput | Should -Contain 'Build succeeded.' - $result.HasErrors() | Should -BeFalse - $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( - 'Sentry.pdb', - 'Sentry.Samples.Console.Basic.pdb') - } - - It "uploads sources for a console app build" { - $result = DotnetBuild 'Sentry.Samples.Console.Basic' $False $True - $result.ScriptOutput | Should -Contain 'Build succeeded.' - $result.HasErrors() | Should -BeFalse - $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( - 'Sentry.Samples.Console.Basic.src.zip') - } - - It "uploads nothing for a console app build when disabled" { - $result = DotnetBuild 'Sentry.Samples.Console.Basic' $False $False - $result.ScriptOutput | Should -Contain 'Build succeeded.' - $result.HasErrors() | Should -BeFalse - $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @() - } - - It "uploads symbols and sources for a MAUI Android app build" { - $result = DotnetBuild 'Sentry.Samples.Maui' $True $True 'net7.0-android' - $result.ScriptOutput | Should -Contain 'Build succeeded.' - $result.HasErrors() | Should -BeFalse - $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( - 'Sentry.Android.AssemblyReader.pdb', - 'Sentry.Bindings.Android.pdb', - 'Sentry.Extensions.Logging.pdb', - 'Sentry.Maui.pdb', - 'Sentry.pdb', - 'Sentry.Samples.Maui.pdb', - 'Sentry.Samples.Maui.src.zip' - ) - } - - if (![RuntimeInformation]::IsOSPlatform([OSPlatform]::OSX)) { - # Remaining tests run on macOS only - return - } - - It "uploads symbols and sources for a MAUI iOS app build" { - $result = DotnetBuild 'Sentry.Samples.Maui' $True $True 'net7.0-ios' - $result.ScriptOutput | Should -Contain 'Build succeeded.' - $result.HasErrors() | Should -BeFalse - $result.UploadedDebugFiles() | Sort-Object -Unique | Should -Be @( - 'libmono-component-debugger.dylib', - 'libmono-component-diagnostics_tracing.dylib', - 'libmono-component-hot_reload.dylib', - 'libmonosgen-2.0.dylib', - 'libSystem.IO.Compression.Native.dylib', - 'libSystem.Native.dylib', - 'libSystem.Net.Security.Native.dylib', - 'libSystem.Security.Cryptography.Native.Apple.dylib', - 'libxamarin-dotnet-debug.dylib', - 'libxamarin-dotnet.dylib', - 'Sentry', - 'Sentry.Bindings.Cocoa.pdb', - 'Sentry.Extensions.Logging.pdb', - 'Sentry.Maui.pdb', - 'Sentry.pdb', - 'Sentry.Samples.Maui', - 'Sentry.Samples.Maui.pdb', - 'Sentry.Samples.Maui.src.zip' - ) - } -}