Skip to content

Commit 8a02f7b

Browse files
authored
Merge branch 'main' into feat/poc-continuous-profiling
2 parents 03a20dd + 0048b42 commit 8a02f7b

File tree

113 files changed

+5556
-1362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+5556
-1362
lines changed

.cursor/rules/coding.mdc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
alwaysApply: true
3+
description: Cursor Coding Rules
4+
---
5+
6+
# Contributing Rules for Agents
7+
8+
## Overview
9+
10+
sentry-java is the Java and Android SDK for Sentry. This repository contains the source code and examples for SDK usage.
11+
12+
## Tech Stack
13+
14+
- **Language**: Java and Kotlin
15+
- **Build Framework**: Gradle
16+
17+
## Key Commands
18+
19+
```bash
20+
# Format code and regenerate .api files
21+
./gradlew spotlessApply apiDump
22+
23+
# Run all tests and linter
24+
./gradlew check
25+
26+
# Run unit tests for a specific file
27+
./gradle ':<module>:testDebugUnitTest' --tests="*<file name>*" --info
28+
```
29+
30+
## Contributing Guidelines
31+
32+
1. Follow existing code style and language
33+
2. Do not modify the API files (e.g. sentry.api) manually, instead run `./gradlew apiDump` to regenerate them
34+
3. Write comprehensive tests
35+
4. New features should always be opt-in by default, extend `SentryOptions` or similar Option classes with getters and setters to enable/disable a new feature
36+
5. Consider backwards compatibility
37+
38+
## Coding rules
39+
40+
1. First think through the problem, read the codebase for relevant files, and propose a plan
41+
2. Before you begin working, check in with me and I will verify the plan
42+
3. Then, begin working on the todo items, marking them as complete as you go
43+
4. Please do not describe every step of the way and just give me a high level explanation of what changes you made
44+
5. Make every task and code change you do as simple as possible. We want to avoid making any massive or complex changes. Every change should impact as little code as possible. Everything is about simplicity.
45+
6. Once you're done, format the code and regenerate the .api files using the following command `./gradlew spotlessApply apiDump`
46+
7. As a last step, git stage the relevant files and propose (but not execute) a single git commit command (e.g. `git commit -m "<git commit message>"`)
47+
48+
49+
## Useful Resources
50+
51+
- Main SDK documentation: https://develop.sentry.dev/sdk/overview/
52+
- Internal contributing guide: https://docs.sentry.io/internal/contributing/
53+
- Git commit messages conventions: https://develop.sentry.dev/engineering-practices/commit-messages/

.cursor/rules/offline.mdc

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
alwaysApply: true
3+
description: Java SDK Offline behaviour
4+
---
5+
# Java SDK Offline behaviour
6+
7+
By default offline caching is enabled for Android but disabled for JVM.
8+
It can be enabled by setting SentryOptions.cacheDirPath.
9+
10+
For Android, AndroidEnvelopeCache is used. For JVM, if cache path has been configured, EnvelopeCache will be used.
11+
12+
Any error, event, transaction, profile, replay etc. is turned into an envelope and then sent into ITransport.send.
13+
The default implementation is AsyncHttpTransport.
14+
15+
If an envelope is dropped due to rate limit and has previously been cached (Cached hint) it will be discarded from the IEnvelopeCache.
16+
17+
AsyncHttpTransport.send will enqueue an AsyncHttpTransport.EnvelopeSender task onto an executor.
18+
19+
Any envelope that doesn't have the Cached hint will be stored in IEnvelopeCache by the EventSender task. Previously cached envelopes (Cached hint) will have a noop cache passed to AsyncHttpTransport.EnvelopeSender and thus not cache again. It is also possible cache is disabled in general.
20+
21+
An envelope being sent directly from SDK API like Sentry.captureException will not have the Retryable hint.
22+
23+
In case the SDK is offline, it'll mark the envelope to be retried if it has the Retryable hint.
24+
If the envelope is not retryable and hasn't been sent to offline cache, it's recorded as lost in a client report.
25+
26+
In case the envelope can't be sent due to an error or network connection problems it'll be marked for retry if it has the Retryable hint.
27+
If it's not retryable and hasn't been cached, it's recorded as lost in a client report.
28+
29+
In case the envelope is sent successfully, it'll be discarded from cache.
30+
31+
The SDK has multiple mechanisms to deal with envelopes on disk.
32+
- OutboxSender: Sends events coming from other SDKs like NDK that wrote them to disk.
33+
- io.sentry.EnvelopeSender: This is the offline cache.
34+
35+
Both of these are set up through an integration (SendCachedEnvelopeIntegration) which is configured to use SendFireAndForgetOutboxSender or SendFireAndForgetEnvelopeSender.
36+
37+
io.sentry.EnvelopeSender is able to pick up files in the cache directory and send them.
38+
It will trigger sending envelopes in cache dir on init and when the connection status changes (e.g. the SDK comes back online, meaning it has Internet connection again).
39+
40+
## When Envelope Files Are Removed From Cache
41+
42+
Envelope files are removed from the cache directory in the following scenarios:
43+
44+
### 1. Successful Send to Sentry Server
45+
When `AsyncHttpTransport` successfully sends an envelope to the Sentry server, it calls `envelopeCache.discard(envelope)` to remove the cached file. This happens in `AsyncHttpTransport.EnvelopeSender.flush()` when `result.isSuccess()` is true.
46+
47+
### 2. Rate Limited Previously Cached Envelopes
48+
If an envelope is dropped due to rate limiting **and** has previously been cached (indicated by the `Cached` hint), it gets discarded immediately via `envelopeCache.discard(envelope)` in `AsyncHttpTransport.send()`.
49+
In this case the discarded envelope is recorded as lost in client reports.
50+
51+
### 3. Offline Cache Processing (EnvelopeSender)
52+
When the SDK processes cached envelope files from disk (via `EnvelopeSender`), files are deleted after processing **unless** they are marked for retry. In `EnvelopeSender.processFile()`, the file is deleted with `safeDelete(file)` if `!retryable.isRetry()`.
53+
54+
### 4. Session File Management
55+
Session-related files (session.json, previous_session.json) are removed during session lifecycle events like session start/end and abnormal exits.
56+
57+
### 5. Cache rotation
58+
If the number of files in the cache directory has reached the configured limit (SentryOptions.maxCacheItems), the oldest file will be deleted to make room.
59+
This happens in `CacheStrategy.rotateCacheIfNeeded`. The deleted envelope will be recorded as lost in client reports.
60+
61+
## Retry Mechanism
62+
63+
**Important**: The SDK does NOT implement a traditional "max retry count" mechanism. Instead:
64+
65+
### Infinite Retry Approach
66+
- **Retryable envelopes**: Stay in cache indefinitely and are retried when conditions improve (network connectivity restored, rate limits expire, etc.)
67+
- **Non-retryable envelopes**: If they fail to send, they're immediately recorded as lost (not cached for retry)
68+
69+
### When Envelopes Are Permanently Lost (Not Due to Retry Limits)
70+
71+
1. **Queue Overflow**: When the transport executor queue is full - recorded as `DiscardReason.QUEUE_OVERFLOW`
72+
73+
2. **Network Errors (Non-Retryable)**: When an envelope isn't marked as retryable and fails due to network issues - recorded as `DiscardReason.NETWORK_ERROR`
74+
75+
3. **Rate Limiting**: When envelope items are dropped due to active rate limits - recorded as `DiscardReason.RATELIMIT_BACKOFF`
76+
77+
4. **Cache Overflow**: When the cache directory has reached maxCacheItems, old files are deleted - recorded as `DiscardReason.CACHE_OVERFLOW`
78+
79+
### Cache Processing Triggers
80+
Cached envelopes are processed when:
81+
- Network connectivity is restored (via connection status observer)
82+
- SDK initialization occurs
83+
- Rate limits expire
84+
- Manual flush operations
85+
86+
### File Deletion Implementation
87+
The actual file deletion is handled by `EnvelopeCache.discard()` which calls `envelopeFile.delete()` and logs errors if deletion fails.

.envrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export VIRTUAL_ENV=".venv"
2+
layout python3

.github/workflows/release-build.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,3 @@ jobs:
3939
path: |
4040
./*/build/distributions/*.zip
4141
./sentry-opentelemetry/*/build/distributions/*.zip
42-
./sentry-android-ndk/build/intermediates/merged_native_libs/release/out/lib/*

.github/workflows/system-tests-backend.yml

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,39 @@ jobs:
2121
fail-fast: false
2222
matrix:
2323
sample: [ "sentry-samples-spring-boot-jakarta" ]
24-
agent: [ "0" ]
24+
agent: [ "false" ]
2525
agent-auto-init: [ "true" ]
2626
include:
2727
- sample: "sentry-samples-spring-boot"
28+
agent: "false"
29+
agent-auto-init: "true"
2830
- sample: "sentry-samples-spring-boot-opentelemetry-noagent"
31+
agent: "false"
32+
agent-auto-init: "true"
2933
- sample: "sentry-samples-spring-boot-opentelemetry"
30-
agent: "1"
34+
agent: "true"
3135
agent-auto-init: "true"
3236
- sample: "sentry-samples-spring-boot-opentelemetry"
33-
agent: "1"
37+
agent: "true"
3438
agent-auto-init: "false"
3539
- sample: "sentry-samples-spring-boot-webflux-jakarta"
40+
agent: "false"
41+
agent-auto-init: "true"
3642
- sample: "sentry-samples-spring-boot-webflux"
43+
agent: "false"
44+
agent-auto-init: "true"
3745
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry-noagent"
46+
agent: "false"
47+
agent-auto-init: "true"
3848
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
39-
agent: "1"
49+
agent: "true"
4050
agent-auto-init: "true"
4151
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
42-
agent: "1"
52+
agent: "true"
4353
agent-auto-init: "false"
54+
- sample: "sentry-samples-console"
55+
agent: "false"
56+
agent-auto-init: "true"
4457
steps:
4558
- uses: actions/checkout@v4
4659
with:
@@ -50,6 +63,11 @@ jobs:
5063
with:
5164
python-version: '3.10.5'
5265

66+
- name: Install Python dependencies
67+
run: |
68+
python3 -m pip install --upgrade pip
69+
python3 -m pip install -r requirements.txt
70+
5371
- name: Set up Java
5472
uses: actions/setup-java@v4
5573
with:
@@ -90,17 +108,9 @@ jobs:
90108
-e '/.*"sentry-samples-android",/d' \
91109
build.gradle.kts
92110
93-
- name: Build server jar
94-
run: |
95-
./gradlew :sentry-samples:${{ matrix.sample }}:bootJar
96-
97-
- name: Build agent jar
98-
run: |
99-
./gradlew :sentry-opentelemetry:sentry-opentelemetry-agent:assemble
100-
101-
- name: Start server and run integration test for sentry-cli commands
111+
- name: Build and run system tests
102112
run: |
103-
test/system-test-run.sh "${{ matrix.sample }}" "${{ matrix.agent }}" "${{ matrix.agent-auto-init }}" "0"
113+
python3 test/system-test-runner.py test --module "${{ matrix.sample }}" --agent "${{ matrix.agent }}" --auto-init "${{ matrix.agent-auto-init }}" --build "true"
104114
105115
- name: Upload test results
106116
if: always()

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ distributions/
2020
*.vscode/
2121
sentry-spring-boot-starter-jakarta/src/main/resources/META-INF/spring.factories
2222
sentry-samples/sentry-samples-spring-boot-jakarta/spy.log
23+
sentry-mock-server.txt
24+
spring-server.txt
2325
spy.log
2426
.kotlin

CHANGELOG.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,61 @@
22

33
## Unreleased
44

5+
### Improvements
6+
7+
- Session Replay: Use main thread looper to schedule replay capture ([#4542](https://github.com/getsentry/sentry-java/pull/4542))
8+
- Use single `LifecycleObserver` and multi-cast it to the integrations interested in lifecycle states ([#4567](https://github.com/getsentry/sentry-java/pull/4567))
9+
10+
### Fixes
11+
12+
- Cache network capabilities and status to reduce IPC calls ([#4560](https://github.com/getsentry/sentry-java/pull/4560))
13+
- Deduplicate battery breadcrumbs ([#4561](https://github.com/getsentry/sentry-java/pull/4561))
14+
- Remove unused method in ManifestMetadataReader ([#4585](https://github.com/getsentry/sentry-java/pull/4585))
15+
- Have single `NetworkCallback` registered at a time to reduce IPC calls ([#4562](https://github.com/getsentry/sentry-java/pull/4562))
16+
- Limit ProGuard keep rules for native methods within `sentry-android-ndk` to the `io.sentry.**` namespace. ([#4427](https://github.com/getsentry/sentry-java/pull/4427))
17+
- If you relied on the Sentry SDK to keep native method names for JNI compatibility within your namespace, please review your ProGuard rules and ensure the configuration still works. Especially when you're not consuming any of the default Android proguard rules (`proguard-android.txt` or `proguard-android-optimize.txt`) the following config should be present:
18+
```
19+
-keepclasseswithmembernames class * {
20+
native <methods>;
21+
}
22+
```
23+
- Fix abstract method error in `SentrySupportSQLiteDatabase` ([#4597](https://github.com/getsentry/sentry-java/pull/4597))
24+
25+
## 8.18.0
26+
27+
### Features
28+
29+
- Add `SentryUserFeedbackButton` Composable ([#4559](https://github.com/getsentry/sentry-java/pull/4559))
30+
- Also added `Sentry.showUserFeedbackDialog` static method
31+
- Add deadlineTimeout option ([#4555](https://github.com/getsentry/sentry-java/pull/4555))
32+
- Add Ktor client integration ([#4527](https://github.com/getsentry/sentry-java/pull/4527))
33+
- To use the integration, add a dependency on `io.sentry:sentry-ktor-client`, then install the `SentryKtorClientPlugin` on your `HttpClient`,
34+
e.g.:
35+
```kotlin
36+
val client =
37+
HttpClient(Java) {
38+
install(io.sentry.ktorClient.SentryKtorClientPlugin) {
39+
captureFailedRequests = true
40+
failedRequestTargets = listOf(".*")
41+
failedRequestStatusCodes = listOf(HttpStatusCodeRange(500, 599))
42+
}
43+
}
44+
```
45+
546
### Fixes
647

748
- Allow multiple UncaughtExceptionHandlerIntegrations to be active at the same time ([#4462](https://github.com/getsentry/sentry-java/pull/4462))
49+
- Prevent repeated scroll target determination during a single scroll gesture ([#4557](https://github.com/getsentry/sentry-java/pull/4557))
50+
- This should reduce the number of ANRs seen in `SentryGestureListener`
51+
- Do not use Sentry logging API in JUL if logs are disabled ([#4574](https://github.com/getsentry/sentry-java/pull/4574))
52+
- This was causing Sentry SDK to log warnings: "Sentry Log is disabled and this 'logger' call is a no-op."
53+
- Do not use Sentry logging API in Log4j2 if logs are disabled ([#4573](https://github.com/getsentry/sentry-java/pull/4573))
54+
- This was causing Sentry SDK to log warnings: "Sentry Log is disabled and this 'logger' call is a no-op."
55+
- SDKs send queue is no longer shutdown immediately on re-init ([#4564](https://github.com/getsentry/sentry-java/pull/4564))
56+
- This means we're no longer losing events that have been enqueued right before SDK re-init.
57+
- Reduce scope forking when using OpenTelemetry ([#4565](https://github.com/getsentry/sentry-java/pull/4565))
58+
- `Sentry.withScope` now has the correct current scope passed to the callback. Previously our OpenTelemetry integration forked scopes an additional.
59+
- Overall the SDK is now forking scopes a bit less often.
860

961
## 8.17.0
1062

Makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: all clean compile javadocs dryRelease update checkFormat api assembleBenchmarkTestRelease assembleUiTestRelease assembleUiTestCriticalRelease createCoverageReports runUiTestCritical check preMerge publish
1+
.PHONY: all clean compile javadocs dryRelease update checkFormat api assembleBenchmarkTestRelease assembleUiTestRelease assembleUiTestCriticalRelease createCoverageReports runUiTestCritical setupPython systemTest systemTestInteractive check preMerge publish
22

33
all: stop clean javadocs compile createCoverageReports
44
assembleBenchmarks: assembleBenchmarkTestRelease
@@ -10,6 +10,7 @@ publish: clean dryRelease
1010
clean:
1111
./gradlew clean --no-configuration-cache
1212
rm -rf distributions
13+
rm -rf .venv
1314

1415
# build and run tests
1516
compile:
@@ -59,6 +60,20 @@ createCoverageReports:
5960
./gradlew jacocoTestReport
6061
./gradlew koverXmlReportRelease
6162

63+
# Create the Python virtual environment for system tests, and install the necessary dependencies
64+
setupPython:
65+
@test -d .venv || python3 -m venv .venv
66+
.venv/bin/pip install --upgrade pip
67+
.venv/bin/pip install -r requirements.txt
68+
69+
# Run system tests for sample applications
70+
systemTest: setupPython
71+
.venv/bin/python test/system-test-runner.py test --all
72+
73+
# Run system tests with interactive module selection
74+
systemTestInteractive: setupPython
75+
.venv/bin/python test/system-test-runner.py test --interactive
76+
6277
# Run tests and lint
6378
check:
6479
./gradlew check

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Sentry SDK for Java and Android
3737
| sentry-apollo-3 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo-3/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo-3) | 21 |
3838
| sentry-apollo-4 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo-4/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo-4) | 21 |
3939
| sentry-kotlin-extensions | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-kotlin-extensions/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-kotlin-extensions) | 21 |
40+
| sentry-ktor-client | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-ktor-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-ktor-client) | 21 |
4041
| sentry-servlet | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet) | |
4142
| sentry-servlet-jakarta | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet-jakarta/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet-jakarta) | |
4243
| sentry-spring-boot | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot) |

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ apiValidation {
6969
"sentry-samples-spring-boot-jakarta-opentelemetry-noagent",
7070
"sentry-samples-spring-boot-webflux",
7171
"sentry-samples-spring-boot-webflux-jakarta",
72+
"sentry-samples-ktor-client",
7273
"sentry-uitest-android",
7374
"sentry-uitest-android-benchmark",
7475
"sentry-uitest-android-critical",

0 commit comments

Comments
 (0)