Repository navigation
chore: merge main into version7 - #5834
Merged
Merged
Conversation
Craft's nuget target is dropping --skip-duplicate (getsentry/craft#686). With our single nuget target, a retry after a partly failed publish would stop at the first package that's already on nuget.org. With workspaces enabled, craft splits the target into one target per package, in dependency order, and a retry skips the packages that already went out. Craft releases without workspace support pass the new keys through and keep publishing everything as one target, so this is safe to merge before the craft release. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…5505) --------- Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Dan Fuller <dfuller@sentry.io> Co-authored-by: Ricardo Colombo Oliveira <github@ricoliv.com>
Co-authored-by: GitHub <noreply@github.com>
coverlet instruments the SDK assemblies again in every test host, and for each branch it rescans the whole method for sequence points. [GeneratedRegex] turns the crontab pattern into one TryMatchAtCurrentPosition method with 8,070 IL instructions, 682 branches and 1,968 sequence points, about 90% of the instruction x branch cost across Sentry.dll. That costs about 35 s of CPU per test host before any test runs. Excluding [GeneratedCode] skips the generated regex matchers and the System.Text.Json source-generated context. Hand-written code keeps the same coverage, and CodeCoverage.runsettings already excludes the same attribute for the Microsoft collector. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore: update modules/sentry-cocoa to 9.31.0 * chore: regenerate Cocoa bindings for 9.31.0 Cocoa 9.31.0 adds SentryObjCExperimentalOptions.metrickit, which returns SentryObjCMetricKitOptions. That type isn't in the patch script's KeepInterfaces list, so the regenerated bindings failed to compile with CS0246. .NET doesn't expose MetricKit, so drop the property alongside the other option properties that reference types we don't bind. The rest is Objective Sharpie output: serializeScope: and serializeDebugMeta: on the internal serializer API, and the SentryObjCMetricKitHangReportingMode enum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: GitHub <noreply@github.com> Co-authored-by: Ricardo Colombo Oliveira <github@ricoliv.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…verify-api and format-code (#5758) * ci: stop building the device test app in the macOS build job The macOS leg of build.yml built Sentry.Maui.Device.TestApp for net9.0-android, net10.0-android and net10.0-ios, and nothing in build.yml runs it. In the run for #5752 on version7 that was the last 6 minutes of the 24.7-minute Build step, on the critical path. The Linux and Windows filters already exclude the app, and both device test workflows build it themselves. The macOS leg of verify-api builds the same filter, so it no longer builds the app either. The device test path filters now also cover what the app compiles and they didn't list: Sentry.Analyzers, Sentry.Testing.CrashableApp, the nested Directory.Build files and .editorconfig, which can fail the build because warnings are errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: serialize only the jobs that push in verify-api and format-code Both workflows put the whole run in the pr-auto-commit concurrency group, so each waited for the other to finish. On one PR, format-code started 35 minutes after its run was created, and on another verify-api waited 13 minutes. The group exists to keep their git pushes apart, so it now covers only accept-api-changes and the format-code job, and the API test matrix starts right away. Both still push from the head they checked out and fail as non-fast-forward if the branch moved in the meantime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Unsupported AOT jobs run after the whole build-sentry matrix, so their time adds to every build. They only publish a console app against the packages from the macOS job, but they ran the full Setup Environment with Java, the Android SDK, Mono and workloads. version7 dropped that in #5746, and this brings the same job to main. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: Use craft's built-in version bumping Craft 3.0.0 bumps <VersionPrefix> in Directory.Build.props itself and fails prepare if no version gets bumped (getsentry/craft#923), so the custom bump-version script is no longer needed. Co-Authored-By: Burak Yigit Kaya <burak.kaya@sentry.io> * ci: Move to craft's changelog and versioning policy keys Co-Authored-By: Burak Yigit Kaya <burak.kaya@sentry.io> * ci: Use the craft v3 floating tag Co-Authored-By: Burak Yigit Kaya <burak.kaya@sentry.io> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: Burak Yigit Kaya <burak.kaya@sentry.io>
…ration tests (#5771) Microsoft.Data.SqlClient 6.1.x pulls in Pkcs 9.0.4 on net10.0, which is affected by GHSA-846f-f764-76mx and GHSA-2fmv-rv2c-59x7. No SqlClient release floors Pkcs high enough to clear them yet. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: GitHub <noreply@github.com>
Co-authored-by: GitHub <noreply@github.com>
The macOS build job and the iOS device tests build the Cocoa SDK from the sentry-cocoa submodule on every run. In the macOS Build step on main, that takes 12.2 of 23.7 minutes on one MSBuild node, and the other two nodes go idle waiting for the Cocoa bindings. version7 caches it since #5746, and this brings the same steps to main. The key covers the selected Xcode, build-sentry-cocoa.sh, sentry-cocoa.xcconfig and the submodule commit. Pushes to main save the cache, so pull requests restore it from there. Release branches still build it from source, because it ships in the Sentry.Bindings.Cocoa package. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
--- updated-dependencies: - dependency-name: sharpie.bind.tool dependency-version: 27.1.0.18 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…4 updates (#5780) Bumps the github-actions group with 4 updates in the / directory: [getsentry/craft/.github/workflows/changelog-preview.yml](https://github.com/getsentry/craft), [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [actions/setup-java](https://github.com/actions/setup-java). Bumps the github-actions group with 1 update in the /.github/actions/environment directory: [actions/setup-java](https://github.com/actions/setup-java). Updates `getsentry/craft/.github/workflows/changelog-preview.yml` from 2.34.1 to 2.35.1 - [Release notes](https://github.com/getsentry/craft/releases) - [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md) - [Commits](getsentry/craft@3f2abdc...0ff7589) Updates `github/codeql-action/init` from 4.38.3 to 4.39.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@24c5418...6f2ac81) Updates `github/codeql-action/analyze` from 4.38.3 to 4.39.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@24c5418...6f2ac81) Updates `actions/setup-java` from 6.0.1 to 6.1.0 - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](actions/setup-java@de7274f...b843ebf) Updates `actions/setup-java` from 6.0.1 to 6.1.0 - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](actions/setup-java@de7274f...b843ebf) --- updated-dependencies: - dependency-name: getsentry/craft/.github/workflows/changelog-preview.yml dependency-version: 2.35.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: github/codeql-action/init dependency-version: 4.39.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: github/codeql-action/analyze dependency-version: 4.39.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/setup-java dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/setup-java dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* ci: stop installing Mono Every Linux and macOS job installed Mono, but nothing runs it. #4545 added it for the net4-console integration test, which ran the .NET Framework app through Mono there. Two weeks later #4461 made that test Windows-only, and the logs show it skipped on Linux and macOS. The .NET Framework unit tests only build on Windows too. On Ubuntu the install downloads 53 MB from the package mirror. On October 23 that download took 15 to 21 minutes in 4 linux-x64 legs and 1 Android device test job. The chmod after it only repaired the /usr/share/dotnet permissions that installing Mono had changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: stop writing detailed text build logs The Build step wrote a detailed text log next to the binlog, 1.9 GB on macOS, and uploaded both. The binlog holds the same events and warnings, and nothing reads the text log. The MSBuild job and the integration test builds wrote one too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: install only the workloads each job needs Setup Environment ran dotnet workload restore without a project, so it evaluated every project in Sentry.slnx in every job. The Linux legs without mobile targets installed android, maui-android, maui-tizen, macos, wasm-tools and wasm-tools-net9, and Windows installed ios, maccatalyst and macos. The environment action now requires the solution filters or project files the job builds, and restores only their workloads. dotnet workload restore doesn't accept a solution filter, so the step passes the projects in it, and names the filter if it finds none. Jobs that build everything pass Sentry.slnx. The Android test app is restored only when the job builds the tests that build it, and the legs without mobile targets skip Java and the Android SDK. CodeQL, format-code and verify-api no longer run a second, unfiltered workload restore after the action. Jobs that build a MAUI project still get maui-tizen, because dotnet workload restore adds it for every MAUI project. Measured on top of the other CI changes, Setup Environment went from about 190 to 89 seconds in the trim job and from 170-180 to 71-78 in the Android device test build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply suggestion from @jamescrosswell --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com>
* ci: install tzdata in the Alpine CI image The linux-musl CI image has no time zone database, so only UTC resolves and tests that need a real IANA zone are skipped on musl. Refs #5756 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply suggestion from @jamescrosswell --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com>
* ci: build the MSBuild job on all cores msbuild.exe builds on one node unless it gets -m, while the dotnet CLI passes -maxcpucount on its own. The MSBuild job's binlog shows 21.4 minutes on one node, 12.4 of them in Build. The win-x64 leg builds the same solution filter with dotnet build in 3 to 4.5 minutes. -nr:false keeps the worker nodes from staying around after the build, since nothing later in the job uses them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: install .NET and NuGet packages on a faster drive on Windows The Windows .NET legs spent about 12 minutes in Setup Environment and Restore, against about 4.5 on Linux. setup-dotnet installed into C:\Program Files\dotnet, where the SDK installs workloads as MSI packages, and NuGet extracted packages into the user profile on C:. On Windows, Setup Environment now starts by installing .NET and the NuGet cache next to the workspace, where workloads install as plain files. On the x64 runners that's on D:. The arm64 runners have no D:, so there the NuGet packages and TEMP go on a Dev Drive, and .NET stays next to the workspace on C:. Trusting the new drive is retried. If setting it up fails anyway, the step warns and keeps the NuGet packages next to the workspace, because the drive is a speedup. Every Windows job that uses Setup Environment gets it. There ~/.nuget/packages isn't the NuGet cache anymore, so the integration tests now clear the Sentry packages they push from NUGET_PACKAGES when it's set. In two probes of the win-arm64 leg, the job took 33.8 and 32.4 minutes with the Dev Drive, against 37.2 and 35.8 without it, and 36.9 with .NET on the drive too. On its own, the step took the MSBuild job's Run MSBuild from 23-24 to 14.7 minutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: restore in its own pass in the MSBuild job The MSBuild job ran msbuild -t:Restore,Build,Pack. NuGet's docs say restoring and building in one invocation is unpredictable and often wrong: restore can bring in props and targets from packages, so the build needs its own evaluation after it. -restore runs the restore as a separate pass first, which is what the dotnet CLI does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: build the app samples in their own job The app samples only check that they compile, but their Release builds trim, AOT-compile and package each app. In the macOS leg that's about 13.7 of the Build step's 28.3 task-minutes, and it's the whole tail of the step once the Cocoa SDK comes from the cache. On Windows, the MAUI sample's Android build is the last thing the Build step finishes. The Android, iOS, Mac Catalyst, macOS and MAUI samples now build in a separate job that starts with the .NET legs: all of them on macOS, the Android and MAUI samples on Linux, and the MAUI sample on Windows, which is the only build of its Windows target. The legs' solution filters no longer include them, and generated filters list them. The samples job's Cocoa SDK steps match the macOS leg's. So that msbuild.exe still builds an Android and a Windows app, the MSBuild job builds the MAUI sample after the solution filter. That took 180 to 211 seconds on three runs, and the job still ended about 10 minutes before the slowest check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run the integration tests in their own jobs The build legs built, ran the unit tests, and then ran the integration tests, one step after another. On macOS the MAUI cases in cli.Tests.ps1 took 8 to 10 of the leg's 13 to 15 integration test minutes, building three Release apps for Android, iOS and Mac Catalyst, and the Windows legs spent 12 to 16 minutes in the integration tests. The MAUI cases move to cli-maui.Tests.ps1, unchanged except that SKIP_MAUI_TESTS also skips them. A new integration-test job runs next to the legs: on macOS it runs the MAUI cases, which the macOS leg now skips, and on linux-x64, win-x64 and win-arm64 it runs every integration test file, which those legs now skip. Each entry builds and packs only the packages its tests use, from two generated solution filters: Sentry-CI-IntegrationTest-macOS.slnf, which adds the Cocoa bindings, and Sentry-CI-IntegrationTest.slnf. It packs with --no-build like the legs, because packing Sentry.Maui while building it on macOS fails with NU5026. These packages aren't the ones the macOS leg publishes, but CI_PUBLISHING_BUILD only adds the other desktop platforms' native libraries and sentry-cli binaries, which these tests don't use. On release branches the macOS leg runs the MAUI cases too, against the packages it uploads for craft, so the packages we publish are still the ones tested. The integration-test job runs them there as well, which keeps the jobs the same on every branch. On three runs with the other CI changes, the win-x64, linux-x64 and win-arm64 legs took 15.0, 11.2 and 17.9 minutes, and their integration jobs 18.5, 12.7 and 22.1. Before, the win-arm64 leg took 31 and was the slowest job. The new jobs passed the same 69 tests and skipped the same 35 as the legs did before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run the integration tests on linux-musl-x64 again #4789 turned them off on linux-musl-x64 while they hung there without an error, tracked in #4788. #4743 fixed the disk space problem behind it, and #4788 was closed in December 2025, but the guard stayed. The leg finishes in about 9 minutes without them, and the same tests take about 6 on linux-musl-arm64, so the leg still ends well before the slowest check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: run the iOS integration tests in their own job The iOS job ran the device tests and then the integration tests on one Mac, about 42 minutes in all. The two build and run different apps and share only the simulator, so the integration tests now run in a second job at the same time. ios.Tests.ps1 skips every case unless a simulator is already booted, and xharness only boots one in the ios-tests job, so the new job boots its own, with a 10-minute timeout. The boot takes about 2 minutes. The job uploads no results, because ios.Tests.ps1 writes nothing to the integration-test/mobile-app/test_output folder the old job uploaded. On its first run, the iOS workflow took 18 minutes, against 38.7 for the single job the same night, and all 8 integration cases passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run the Android integration tests in their own job Each Android emulator job ran the device tests, then Setup Environment, then the integration tests, about 22 minutes after waiting 7.5 for the device test app builds. The integration tests build their own app from source and share only the emulator, so they now run in a second job that starts with the workflow, on the same runners. The new job drops "Select Java 21". #4559 added it as "Select Java 17", when Setup Environment ended on Java 11, and since #5060 Setup Environment installs only Java 21. The new job uploads integration-test/mobile-app/test_output, where android.Tests.ps1 points xharness, without a warning when it's empty. It was empty on every run so far. On its first run, the Android workflow took 19.8 minutes instead of 30.1. The device test jobs took 3.6 to 3.8 minutes and the integration jobs 12.0 to 19.7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Unsupported AOT jobs waited for the whole build matrix to use the macOS packages, but any leg's packages work. Every leg already packs and runs aot.Tests.ps1 against its own. linux-arm now runs in the linux-arm64 leg and win-x86 in the win-x64 leg, which removes two jobs and the tail after the matrix. Some arm64 hosts can't run 32-bit ARM binaries and failed with "Exec format error", so QEMU runs them on every host. Its binfmt_misc handler comes before the kernel's own loader, so it runs them even on hosts that could. On the first runs a small uname program confirmed that: it reported armv7l, which only QEMU does, on a host that runs 32-bit ARM natively. The leg now only checks that the handler is enabled. The action runs the tonistiigi/binfmt image privileged, so that image is pinned by digest here and in alpine.yml, like the action itself. On its first run, the AOT and container cases passed under QEMU in 38 seconds. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The emulator jobs ran on the ubuntu-latest-4-cores larger runner. #2139 moved them there in 2023 because the 2-core standard runners couldn't run a hardware-accelerated emulator. Since April 2024 they can, with the same KVM udev rule this workflow already sets, and on public repositories ubuntu-latest now has 4 CPUs and 16 GB of RAM. Both the device test and the integration test jobs move. On the first runs the device tests took 2.5 to 4.5 minutes, against 2.3 to 4.4 on the larger runner, with the same 2,921 tests. The standard runner listed less disk, but had 88 GB free at the start and 67 at the end. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Remove skip logic from tests and HasTimeZone helper method * Use Fact and Theory for tests that no longer skip Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: GitHub <noreply@github.com>
generate-solution-filters.ps1 tries to install powershell-yaml up to 5 times, 10 seconds apart, but it sets $ErrorActionPreference to Stop, so the first failed download ended the script. The PowerShell Gallery failed that download twice in two days, failing test-solution-filters on #5810 and #5808. A failed attempt now prints a warning and the loop tries again. If every attempt fails, Import-Module still stops the script. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(hangfire): Send recurring job schedule as monitor config Opt-in via UseSentry(o => o.SendRecurringJobSchedule = true). The in-progress check-in of a recurring job carries the job's cron and time zone so Sentry can create the monitor. Unsupported schedules fall back to a check-in without config. Co-Authored-By: Claude <noreply@anthropic.com> * ref(hangfire): Validate the recurring job schedule before capturing Check the crontab up front so the check-in goes out in a single call instead of relying on the hub to swallow an exception from Interval. The validator is shared with Sentry.Hangfire as a linked source file, since the unsigned assembly can't see Sentry's internals. Read the job through GetRecurringJobs, look up time zones with FindSystemTimeZoneById on .NET 6+, and add tests for UTC, unknown zones, deleted jobs, the UseSentry overload, and a real recurring job. Co-Authored-By: Claude <noreply@anthropic.com> * test(hangfire): Skip time zone tests when the zone is missing The linux-musl CI containers have no time zone database, so lookups of Europe/Berlin and Etc/UTC fail there. Co-Authored-By: Claude <noreply@anthropic.com> * fix(hangfire): Skip schedules Sentry would read differently Hangfire runs a job only on days that match both the day-of-month and day-of-week fields, while Sentry runs it on days that match either unless one of them starts with '*'. Don't send those schedules, nor ones with a reversed range such as 5-1 or SAT-SUN, which Sentry rejects. Co-Authored-By: Claude <noreply@anthropic.com> * feat(hangfire): Send recurring job schedules by default Jobs are only monitored when they have [SentryMonitorSlug], so sending the recurring job's schedule lets Sentry create or update the monitor, like the Spring and Quartz integrations. Set SendRecurringJobSchedule to false to keep managing the schedule in Sentry. Co-Authored-By: Claude <noreply@anthropic.com> * fix(hangfire): Create the check-in ID before the in-progress check-in The final check-in reused the ID returned for the in-progress one, which is empty when that one isn't captured. Create the ID up front, send it with the in-progress check-in, and store it in the job's items as before. Co-Authored-By: Claude <noreply@anthropic.com> * ref(hangfire): Rename SendRecurringJobSchedule to SendMonitorConfig Matches SentryQuartzOptions.SendMonitorConfig. Co-Authored-By: Claude <noreply@anthropic.com> * feat(hangfire): Don't send a monitor config when recurring jobs share a slug with different schedules * fix(hangfire): Don't treat a recurring job as conflicting with its own cached schedule Co-Authored-By: Claude <noreply@anthropic.com> * feat(hangfire): Add an option to monitor every recurring job MonitorAllRecurringJobs sends check-ins for recurring jobs without SentryMonitorSlugAttribute, using the slugified recurring job ID as the monitor slug. ExcludedRecurringJobs leaves out recurring jobs by ID. Co-Authored-By: Claude <noreply@anthropic.com> * fix(hangfire): Build recurring job slugs the way Sentry normalizes them Collapse runs of hyphens and trim underscores, so IDs that Sentry would store under the same slug also share one here and the conflicting schedule check sees them. Co-Authored-By: Claude <noreply@anthropic.com> * feat(hangfire): Match Relay's slugify and accept regexes in ExcludedRecurringJobs Adds a public StringOrRegex.Regex, since Sentry.Hangfire isn't strong-named and can't see Sentry's internals. Co-Authored-By: Claude <noreply@anthropic.com> * ref(crons): Share one Relay-compatible slug helper between Hangfire and Quartz Quartz now joins a job's group and name with a hyphen, since Relay drops dots. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitHub <noreply@github.com>
It was only used by SentrySdk.RunAsyncVoid, which was removed in #3466. Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
…ll jobs (#5831) MonitorAllRecurringJobs only covers recurring jobs whose schedule Sentry can represent, matching Quartz and sentry-python. Jobs with SentryMonitorSlug keep checking in without a config.
* feat: add Sentry.Quartz * refactor: optimize cron information retrieval in SentryCronJobListener * refactor: swap ILogger dependency from SentryCronJobListener with IDiagnosticLogger * refactor: simplify Quartz configuration by removing redundant service dependencies and streamlining SentryCronJobListener options handling * refactor: migrate to Quartz v4.0.0 with .NET 10 * feat: include Sentry.Quartz in solution filter and generation scripts * feat: add Quartz sample showcasing Sentry integration * fix: cursor github comments * refactor: simplify Quartz configuration and update project to use Web SDK * refactor: replace SentryCronJobListener with SentryCronJobMiddleware and update Quartz integration * fix: handling issue where current region might throw a CultureNotFoundException * fix: sample project has different nuget package version * fix: skip middleware execution for non-cron triggers * refactor: rename and update Quartz extension method to AddSentryCronJob * feat: add SentryMetricsMiddleware to track Quartz job execution duration metrics * refactor: simplify AddSentryCronJob method by removing unused service collection parameter and streamlining option configuration * feat: add SentryScopeMiddleware and extend Quartz integration with AddSentryScope method, update SentryMetricsMiddleware to support configurable options * refactor: move non-cron trigger check to StartQuartz method * feat: add missing options parameter * refactor: remove unused project reference to Sentry.AspNetCore in Sentry.Quartz * fix: Quatz.Net and Sentry handling cron expression for days differently * feat: add XML documenation * feat: update Quartz to stable v4.0.0 * feat: add Quartz Dashboard and HTTP API integration, update launch URL * feat: add customizable SentryMonitorOptions via callback * style: apply dotnet format to Sentry.Quartz The format-code workflow can't push its auto-fix to a fork branch, so it fails the check instead. Applying the fix here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci(craft): add Sentry.Quartz to the release registry Every package needs a name/packageUrl/mainDocsUrl entry so craft can create its registry entry on first publish; a missing `name` fails the whole registry target rather than just that package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test: add Sentry.Quartz.Tests Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat: add configurable SentryScopeMiddleware options * refactor: migrate extension methods to extension block * refactor: remove SentryMetricsMiddleware * fix: use JobDetail.Key.ToString() * fix: replace job type with job ID in SentryCronJobMiddleware dictionary key * feat(quartz): Rework Sentry.Quartz into Sentry.Quartz4 Keeps the middleware design from #5505 and adds what the cron monitors need on top: - One AddSentry() entry point on IQuartzBuilder that registers the scope and check-in middleware with HubAdapter, so no IHub is needed in DI. - The scope middleware starts a new trace per run and captures what the job throws inside the run's scope. - Check-ins only for jobs with [SentryCronMonitorSlug]. The slug comes from the trigger or job data map, the attribute, or the slugified job key, so job keys sharing a class don't share a monitor. - The monitor config is converted from cron and simple triggers, with the Quartz day-of-week shift, and left out when Sentry can't represent the schedule. SendMonitorConfig turns it off globally or per job. - ConfigureMonitorOptions runs before the trigger's schedule is applied, so it can override it, and never breaks the check-in. - The package is signed and restricted to Quartz [4.0.0,5.0.0). The schedule conversion, slug and check-in logic live in Core/ so the Quartz 3 package can compile the same files. Co-Authored-By: Claude <noreply@anthropic.com> * ref(quartz): Rename Sentry.Quartz4 to Sentry.Quartz Sentry.Quartz3 keeps its name for Quartz.NET 3.x. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Address review feedback on Sentry.Quartz - Jobs built without an identity get a new GUID name on each start, so their monitor slug falls back to the job class name, with a warning. Two jobs that resolve to the same slug also log a warning. - The scope middleware no longer captures exceptions. Quartz logs them, and the logging integration reports that. The cron middleware still sends an error check-in. In global mode the scope is left alone. - Quartz 4 accepts '*' in both day fields and runs on either day when both restrict. Convert those expressions, spelling out a '*' step as a range so Sentry unions the fields too. - ConfigureMonitorOptions takes the IJobExecutionContext and always runs while SendMonitorConfig is on. The trigger's schedule fills in when it sets none, and the config is only sent when it has a schedule. - The check-in ID is created up front, so the final check-in matches the in-progress one even when that wasn't sent. Co-Authored-By: Claude <noreply@anthropic.com> * ref(quartz): Drop warn-once state and discard options from a failed callback Log the unnamed-job fallback at debug level on each run instead of tracking which jobs were warned about, and remove the shared-slug detection. If ConfigureMonitorOptions throws, ignore what it set and use the trigger's schedule. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Capture job exceptions in the job scope and rename the slug attribute Quartz logs a job's exception only after the middleware chain has returned, so the logged error lost the job's scope and trace. Capture it inside the scope again; the SDK drops the duplicate from the log. Rename SentryCronMonitorSlugAttribute to SentryMonitorSlugAttribute to match Sentry.Hangfire. Co-Authored-By: Claude <noreply@anthropic.com> * docs(quartz): Say that AddSentry captures job exceptions The AddSentry() remarks still said job exceptions are left to the logging integration. The scope middleware has captured them again since 73e5551. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(quartz): Add an option to monitor every scheduled job MonitorAllJobs sends check-ins for every job fired by a cron trigger or a repeating simple trigger, with the slug of the job's key. ExcludedJobs skips jobs by name, full key or regex. Jobs with SentryMonitorSlug keep their settings. Co-Authored-By: Claude <noreply@anthropic.com> * ref(quartz): Remove a leftover comment from JobMonitor * fix(quartz): Drop the schedule when jobs share a slug with different schedules Reads every monitored trigger, cached for a minute, like Sentry.Hangfire. Replaces the check for jobs with several triggers. * test(quartz): Skip the time zone test when there's no time zone database * docs(quartz): Drop the stale warning from the slug attribute docs A job without an identity has fallen back to its class name with a debug message, not a warning, since fe97276. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(quartz): Skip jobs whose type can't be resolved when reading triggers A job left in a persistent store after its class was renamed or deleted made the whole trigger read throw, so no monitored job sent its schedule. Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Pin the order of the Sentry job middleware Co-Authored-By: Claude <noreply@anthropic.com> * docs(quartz): Update the sample's comment on how job exceptions are captured Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Capture each job exception once with the logging integration on Quartz's ErrorLogger logs the exception again, wrapped in a JobExecutionProcessException that the default DeduplicateMode doesn't unwrap. AddSentry now adds a log entry filter for that entry, to whichever SentryLoggingOptions the app uses (SentryAspNetCoreOptions included), when the middleware captured the inner exception. Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Check that AddSentry leaves unrelated options resolvable Co-Authored-By: Claude <noreply@anthropic.com> * Update src/Sentry.Quartz/QuartzErrorLogFilterSetup.cs Co-authored-by: Ricardo Colombo Oliveira <github@ricoliv.com> * ref(quartz): Drop the stale constraint wording and assertion for the log filter setup Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Skip jobs with unsupported schedules when monitoring all jobs MonitorAllJobs only covers runs whose trigger schedule Sentry can represent, matching sentry-python. Jobs with SentryMonitorSlug keep checking in without a config. * fix(quartz): Skip default-monitored jobs whose triggers have different schedules --------- Co-authored-by: Michael Mairegger <michael.mairegger@yahoo.de> Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Ricardo Colombo Oliveira <github@ricoliv.com>
…5668) * feat: add Sentry.Quartz * refactor: optimize cron information retrieval in SentryCronJobListener * refactor: swap ILogger dependency from SentryCronJobListener with IDiagnosticLogger * refactor: simplify Quartz configuration by removing redundant service dependencies and streamlining SentryCronJobListener options handling * refactor: migrate to Quartz v4.0.0 with .NET 10 * feat: include Sentry.Quartz in solution filter and generation scripts * feat: add Quartz sample showcasing Sentry integration * fix: cursor github comments * refactor: simplify Quartz configuration and update project to use Web SDK * refactor: replace SentryCronJobListener with SentryCronJobMiddleware and update Quartz integration * fix: handling issue where current region might throw a CultureNotFoundException * fix: sample project has different nuget package version * fix: skip middleware execution for non-cron triggers * refactor: rename and update Quartz extension method to AddSentryCronJob * feat: add SentryMetricsMiddleware to track Quartz job execution duration metrics * refactor: simplify AddSentryCronJob method by removing unused service collection parameter and streamlining option configuration * feat: add SentryScopeMiddleware and extend Quartz integration with AddSentryScope method, update SentryMetricsMiddleware to support configurable options * refactor: move non-cron trigger check to StartQuartz method * feat: add missing options parameter * refactor: remove unused project reference to Sentry.AspNetCore in Sentry.Quartz * fix: Quatz.Net and Sentry handling cron expression for days differently * feat: add XML documenation * feat: update Quartz to stable v4.0.0 * feat: add Quartz Dashboard and HTTP API integration, update launch URL * feat: add customizable SentryMonitorOptions via callback * style: apply dotnet format to Sentry.Quartz The format-code workflow can't push its auto-fix to a fork branch, so it fails the check instead. Applying the fix here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ci(craft): add Sentry.Quartz to the release registry Every package needs a name/packageUrl/mainDocsUrl entry so craft can create its registry entry on first publish; a missing `name` fails the whole registry target rather than just that package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test: add Sentry.Quartz.Tests Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat: add configurable SentryScopeMiddleware options * refactor: migrate extension methods to extension block * refactor: remove SentryMetricsMiddleware * fix: use JobDetail.Key.ToString() * fix: replace job type with job ID in SentryCronJobMiddleware dictionary key * feat(quartz): Rework Sentry.Quartz into Sentry.Quartz4 Keeps the middleware design from #5505 and adds what the cron monitors need on top: - One AddSentry() entry point on IQuartzBuilder that registers the scope and check-in middleware with HubAdapter, so no IHub is needed in DI. - The scope middleware starts a new trace per run and captures what the job throws inside the run's scope. - Check-ins only for jobs with [SentryCronMonitorSlug]. The slug comes from the trigger or job data map, the attribute, or the slugified job key, so job keys sharing a class don't share a monitor. - The monitor config is converted from cron and simple triggers, with the Quartz day-of-week shift, and left out when Sentry can't represent the schedule. SendMonitorConfig turns it off globally or per job. - ConfigureMonitorOptions runs before the trigger's schedule is applied, so it can override it, and never breaks the check-in. - The package is signed and restricted to Quartz [4.0.0,5.0.0). The schedule conversion, slug and check-in logic live in Core/ so the Quartz 3 package can compile the same files. Co-Authored-By: Claude <noreply@anthropic.com> * ref(quartz): Rename Sentry.Quartz4 to Sentry.Quartz Sentry.Quartz3 keeps its name for Quartz.NET 3.x. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Address review feedback on Sentry.Quartz - Jobs built without an identity get a new GUID name on each start, so their monitor slug falls back to the job class name, with a warning. Two jobs that resolve to the same slug also log a warning. - The scope middleware no longer captures exceptions. Quartz logs them, and the logging integration reports that. The cron middleware still sends an error check-in. In global mode the scope is left alone. - Quartz 4 accepts '*' in both day fields and runs on either day when both restrict. Convert those expressions, spelling out a '*' step as a range so Sentry unions the fields too. - ConfigureMonitorOptions takes the IJobExecutionContext and always runs while SendMonitorConfig is on. The trigger's schedule fills in when it sets none, and the config is only sent when it has a schedule. - The check-in ID is created up front, so the final check-in matches the in-progress one even when that wasn't sent. Co-Authored-By: Claude <noreply@anthropic.com> * feat(quartz): Add Sentry.Quartz3 for Quartz.NET 3.x Compiles the Sentry.Quartz core (schedule conversion, slugs, options and check-ins) against Quartz 3.6+ and drives it from an IJobListener, since Quartz 3 has no job middleware. Logs an error at startup when Quartz 4 is loaded, where the listener's Task methods would never be called. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Apply the Sentry.Quartz review fixes to Sentry.Quartz3 Quartz 3 needs exactly one '?' day field, so only that form is converted. ConfigureMonitorOptions gets the listener's IJobExecutionContext, and the final check-in reuses the ID created for the in-progress one. Co-Authored-By: Claude <noreply@anthropic.com> * ref(quartz): Drop warn-once state and discard options from a failed callback Log the unnamed-job fallback at debug level on each run instead of tracking which jobs were warned about, and remove the shared-slug detection. If ConfigureMonitorOptions throws, ignore what it set and use the trigger's schedule. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Capture job exceptions in the job scope and rename the slug attribute Quartz logs a job's exception only after the middleware chain has returned, so the logged error lost the job's scope and trace. Capture it inside the scope again; the SDK drops the duplicate from the log. Rename SentryCronMonitorSlugAttribute to SentryMonitorSlugAttribute to match Sentry.Hangfire. Co-Authored-By: Claude <noreply@anthropic.com> * ref(quartz): Rename SentryCronMonitorSlug to SentryMonitorSlug in Sentry.Quartz3 Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Reorder the Sentry.Quartz3 API snapshots after the attribute rename Co-Authored-By: Claude <noreply@anthropic.com> * docs(quartz): Say that AddSentry captures job exceptions The AddSentry() remarks still said job exceptions are left to the logging integration. The scope middleware has captured them again since 73e5551. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ref(quartz): Remove a leftover comment from JobMonitor * fix(quartz): Drop the schedule when jobs share a slug with different schedules Reads every monitored trigger, cached for a minute, like Sentry.Hangfire. Replaces the check for jobs with several triggers. * test(quartz): Skip the time zone test when there's no time zone database * docs(quartz): Drop the stale warning from the slug attribute docs A job without an identity has fallen back to its class name with a debug message, not a warning, since fe97276. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge branch 'danf/quartz-5505-rebased' into danf/quartz-crons Ports the shared slug check to Quartz 3: QuartzApi.GetTriggersAsync reads each job and the triggers of each monitored one, since Quartz 3 has no bulk lookups. The test shim gets the new ReturnsTriggers and LookedUpTriggers, and HasSeveralTriggersAsync is gone. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Skip jobs whose type can't be resolved when reading triggers A job left in a persistent store after its class was renamed or deleted made the whole trigger read throw, so no monitored job sent its schedule. Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Pin the order of the Sentry job middleware Co-Authored-By: Claude <noreply@anthropic.com> * docs(quartz): Update the sample's comment on how job exceptions are captured Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Fix the nullability of the Quartz 3 job detail stub Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Ignore the nullability of the Quartz 3 job detail stub Quartz 3 annotates GetJobDetail differently across target frameworks. Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz): Capture each job exception once with the logging integration on Quartz's ErrorLogger logs the exception again, wrapped in a JobExecutionProcessException that the default DeduplicateMode doesn't unwrap. AddSentry now adds a log entry filter for that entry, to whichever SentryLoggingOptions the app uses (SentryAspNetCoreOptions included), when the middleware captured the inner exception. Co-Authored-By: Claude <noreply@anthropic.com> * test(quartz): Check that AddSentry leaves unrelated options resolvable Co-Authored-By: Claude <noreply@anthropic.com> * Update src/Sentry.Quartz/QuartzErrorLogFilterSetup.cs Co-authored-by: Ricardo Colombo Oliveira <github@ricoliv.com> * ref(quartz): Drop the stale constraint wording and assertion for the log filter setup Co-Authored-By: Claude <noreply@anthropic.com> * fix(quartz3): Send an error check-in when a job is cancelled Quartz 3 swallows a cancelled job's OperationCanceledException and calls JobWasExecuted with no exception, so check the context's cancellation token too. This matches SentryCronJobMiddleware in Sentry.Quartz. * test(quartz): Only run the IANA time zone test on .NET 6+ .NET Framework on Windows can't resolve IANA time zone IDs, and the shared JobMonitor tests run on net48 in Sentry.Quartz3.Tests. --------- Co-authored-by: Michael Mairegger <michael.mairegger@yahoo.de> Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Ricardo Colombo Oliveira <github@ricoliv.com>
…5828) * perf: pushing a scope no longer eagerly allocates tags, extras, contexts and attachments Scope.Clone runs on every ILogger.BeginScope call made while Sentry's logging integration is registered. Every Scope eagerly allocated three ConcurrentDictionary instances (tags, extras and the one inside SentryContexts), which made up around 80% of the 4.4 KB each scope cost on a 20 core machine (about 60% of 2.5 KB with 2 cores). Create the tags, extras, contexts, attachments and SDK version lazily, and skip copying them in Clone and Apply when the source has none. The public properties still return the same live instance once created. Assisted-by: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Code <noreply@anthropic.com> * perf: cloning a scope copies its breadcrumbs without intermediate allocations Scope.Clone enumerated the breadcrumbs of the source scope (which takes a snapshot array) and enqueued them one by one into the clone, repeatedly growing the clone's backing list. With the default of 100 breadcrumbs that was around 3 KB per clone. Copy the items of the source queue directly into the clone with a single sized allocation instead. Assisted-by: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Code <noreply@anthropic.com> * perf: SentryLogger only formats a log message once it knows it will be used SentryLogger.Log invoked the formatter before checking whether the entry came from the Sentry SDK itself, was an EF exception message or was excluded by a log entry filter, so the message was formatted (and allocated) for every entry that was then discarded. The filter check also allocated a closure for every entry through LINQ's Any(). Move the formatting after those checks and replace the LINQ call with a loop. Assisted-by: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Code <noreply@anthropic.com> * refactor: address review feedback on lazy scope collections Use LazyInitializer.EnsureInitialized for the lazily created collections of Scope instead of hand-written compare-and-swap loops. Assert in the Clone test that the contexts and attachments of a clone are independent of the scope they were cloned from, and remove new tests that only duplicate the coverage of existing tests. Assisted-by: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com>
Conflict resolutions: - build.yml: keep main's integration-test job and in-leg unsupported AOT steps; carry version7's .NET 11 container image pins and VS 2026 runners into them. The musl integration test step now covers linux-musl-x64 too, since main re-enabled it (#4788 is closed). - cli.Tests.ps1: main moved the MAUI tests to cli-maui.Tests.ps1; version7's .NET 11 changes to them are applied there. - verify-api.yml, environment/action.yml: version7's side. - Scope.Apply: version7's SDK merge logic, guarded by main's lazy _sdk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Quartz: the logging integration no longer takes InitializeSdk. - AttachmentSerializationTests: Envelope.FromEvent's logger is now the last, optional parameter. - Add the net11.0 API snapshots for StringOrRegex.Regex and Sentry.Quartz3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
version7 renamed integration-test/net9-maui to maui-device. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## version7 #5834 +/- ##
============================================
+ Coverage 76.17% 76.76% +0.58%
============================================
Files 526 539 +13
Lines 19265 19694 +429
Branches 3729 3851 +122
============================================
+ Hits 14676 15119 +443
+ Misses 3734 3703 -31
- Partials 855 872 +17 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges the latest
main(up to 5d33189, #5828) intoversion7, plus the commit from #5832 (Quartz3 API snapshots forMonitorAllJobs/ExcludedJobs) cherry-picked on top.Merge with a merge commit, not squash, so
version7keeps main's individual commits.Conflict resolutions
build.yml: kept main's newintegration-testjob and its in-leg unsupported AOT steps (ci: run the samples and integration tests in their own jobs #5809, ci: test unsupported AOT runtimes in the build legs #5811), and dropped the standaloneunsupported-aotjob. version7's .NET 11ContainerBaseImagepins and VS 2026 Windows runners now apply to those new steps and jobs too, includingbuild-samples.Integration test (musl)step with the musl image pin. They haven't run on .NET 11 yet, so this PR's CI is their first run there.cli.Tests.ps1: main moved the MAUI tests tocli-maui.Tests.ps1. version7's .NET 11 changes to those tests (latest framework, CoreCLR file lists) are applied in the new file.verify-api.yml,environment/action.yml: version7's side. Its API-approval filter step already covers main'sworkload restoreremoval, and the Xcode pin now lives inpin-xcode.Scope.Apply: version7's SDK name/version/package merge logic, guarded by main's lazily created_sdk(perf: reduce allocations when pushing scopes via ILogger.BeginScope #5828).Fixes for main's new code on version7
The merge compiled cleanly, but some of main's new code broke against version7's API (d26b28a):
Sentry.Quartz.TestssetSentryLoggingOptions.InitializeSdk, which is now an error-level[Obsolete].AttachmentSerializationTestscase passed the logger asEnvelope.FromEvent's second argument.StringOrRegex.Regex(Sentry), and a new one forSentry.Quartz3.#skip-changelog
🤖 Generated with Claude Code