Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ff555aa
feat(core): Add scope-level attributes API
adinauer Feb 26, 2026
7cd38e6
changelog
adinauer Feb 26, 2026
de80a23
ref: Split out LoggerApi/MetricsApi changes for stacked PR
adinauer Feb 26, 2026
f4e82bf
feat(core): Wire scope attributes into LoggerApi and MetricsApi
adinauer Feb 26, 2026
d535d44
changelog
adinauer Feb 26, 2026
5974800
feat(samples): Showcase scope attributes in Spring Boot 4 samples
adinauer Feb 26, 2026
7189bdc
changelog
adinauer Feb 26, 2026
082fab0
Revert "changelog"
adinauer Feb 26, 2026
f0a2a21
ref: Remove redundant comments from variant controllers
adinauer Feb 26, 2026
12d88f2
ref: Limit scope attributes sample to base Spring Boot 4 variant
adinauer Feb 26, 2026
bb056cc
fix: Detect integer attribute type correctly for all integer Number sโ€ฆ
adinauer Feb 26, 2026
3791872
changelog
adinauer Feb 26, 2026
858da6c
feat: Support collections and arrays in log attribute type inference
adinauer Feb 26, 2026
ff23f6e
changelog
adinauer Feb 26, 2026
80755b7
use ConcurrentHashMap instead of HashMap when merging attributes
adinauer Feb 26, 2026
5c478cc
add enabled check similar to tags
adinauer Feb 27, 2026
7c750cf
make setAttribute and setAttributes params nullable
adinauer Feb 27, 2026
8e61d4d
test: Add coverage for arrayAttribute factory method
adinauer Feb 27, 2026
1e7bcf5
Merge branch 'main' into feat/scope-attributes
adinauer Mar 3, 2026
534ff79
Merge pull request #5118 from getsentry/feat/scope-attributes
adinauer Mar 3, 2026
4aaa380
Merge branch 'feat/global-attributes-api' into feat/scope-attributes-โ€ฆ
adinauer Mar 3, 2026
d56444b
Merge pull request #5120 from getsentry/feat/scope-attributes-logger-โ€ฆ
adinauer Mar 3, 2026
68c4a74
Merge pull request #5121 from getsentry/feat/scope-attributes-sample-e2e
adinauer Mar 3, 2026
e077d0d
Merge branch 'feat/global-attributes-api' into fix/attribute-integer-โ€ฆ
adinauer Mar 3, 2026
e15272c
Merge pull request #5122 from getsentry/fix/attribute-integer-type-deโ€ฆ
adinauer Mar 3, 2026
3e35f04
Merge pull request #5124 from getsentry/feat/log-attribute-array-support
adinauer Mar 3, 2026
94afb06
feat: Add Object[] overload to arrayAttribute factory
adinauer Mar 3, 2026
1c603b0
shape changelog
adinauer Mar 4, 2026
b5de18d
Merge branch 'main' into feat/global-attributes-api
adinauer Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

### Features

- Add scope-level attributes API ([#5118](https://github.com/getsentry/sentry-java/pull/5118)) via ([#5148](https://github.com/getsentry/sentry-java/pull/5148))
- Automatically include scope attributes in logs and metrics ([#5120](https://github.com/getsentry/sentry-java/pull/5120))
- New APIs are `Sentry.setAttribute`, `Sentry.setAttributes`, `Sentry.removeAttribute`
- Support collections and arrays in attribute type inference ([#5124](https://github.com/getsentry/sentry-java/pull/5124))
- Add support for `SENTRY_SAMPLE_RATE` environment variable / `sample-rate` property ([#5112](https://github.com/getsentry/sentry-java/pull/5112))
- Create `sentry-opentelemetry-otlp` and `sentry-opentelemetry-otlp-spring` modules for combining OpenTelemetry SDK OTLP export with Sentry SDK ([#5100](https://github.com/getsentry/sentry-java/pull/5100))
- OpenTelemetry is configured to send spans to Sentry directly using an OTLP endpoint.
Expand Down Expand Up @@ -32,6 +36,7 @@

### Fixes

- Fix attribute type detection for `Long`, `Short`, `Byte`, `BigInteger`, `AtomicInteger`, and `AtomicLong` being incorrectly inferred as `double` instead of `integer` ([#5122](https://github.com/getsentry/sentry-java/pull/5122))
- Remove `AndroidRuntimeManager` StrictMode relaxation to prevent ANRs during SDK init ([#5127](https://github.com/getsentry/sentry-java/pull/5127))
- **IMPORTANT:** StrictMode violations may appear again in debug builds. This is intentional to prevent ANRs in production releases.
- Fix crash when unregistering `SystemEventsBroadcastReceiver` with try-catch block. ([#5106](https://github.com/getsentry/sentry-java/pull/5106))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class MetricController {

@GetMapping("count")
String count() {
Sentry.setAttribute("user.type", "admin");
Sentry.setAttribute("feature.version", 2);
Sentry.metrics().count("countMetric");
return "count metric increased";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ Person person(@PathVariable Long id) {
ISpan currentSpan = Sentry.getSpan();
ISpan sentrySpan = currentSpan.startChild("spanCreatedThroughSentryApi");
try {
Sentry.setAttribute("user.type", "admin");
Sentry.setAttribute("feature.version", 2);
Sentry.setAttribute("debug.enabled", true);

Sentry.logger().warn("warn Sentry logging");
Sentry.logger().error("error Sentry logging");
Sentry.logger().info("hello %s %s", "there", "world!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ class MetricsSystemTest {
assertEquals(200, restClient.lastKnownStatusCode)

testHelper.ensureMetricsReceived { event, header ->
testHelper.doesContainMetric(event, "countMetric", "counter", 1.0)
testHelper.doesContainMetric(event, "countMetric", "counter", 1.0) &&
testHelper.doesMetricHaveAttribute(event, "countMetric", "user.type", "admin") &&
testHelper.doesMetricHaveAttribute(event, "countMetric", "feature.version", 2)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,20 @@ class PersonSystemTest {
testHelper.ensureLogsReceived { logs, envelopeHeader ->
testHelper.doesContainLogWithBody(logs, "warn Sentry logging") &&
testHelper.doesContainLogWithBody(logs, "error Sentry logging") &&
testHelper.doesContainLogWithBody(logs, "hello there world!")
testHelper.doesContainLogWithBody(logs, "hello there world!") &&
testHelper.doesLogWithBodyHaveAttribute(
logs,
"warn Sentry logging",
"user.type",
"admin",
) &&
testHelper.doesLogWithBodyHaveAttribute(
logs,
"warn Sentry logging",
"feature.version",
2,
) &&
testHelper.doesLogWithBodyHaveAttribute(logs, "warn Sentry logging", "debug.enabled", true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,8 @@ public final class io/sentry/systemtest/util/TestHelper {
public static synthetic fun doesContainMetric$default (Lio/sentry/systemtest/util/TestHelper;Lio/sentry/SentryMetricsEvents;Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;ILjava/lang/Object;)Z
public final fun doesEventHaveExceptionMessage (Lio/sentry/SentryEvent;Ljava/lang/String;)Z
public final fun doesEventHaveFlag (Lio/sentry/SentryEvent;Ljava/lang/String;Z)Z
public final fun doesLogWithBodyHaveAttribute (Lio/sentry/SentryLogEvents;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)Z
public final fun doesMetricHaveAttribute (Lio/sentry/SentryMetricsEvents;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)Z
public final fun doesTransactionContainSpanWithDescription (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z
public final fun doesTransactionContainSpanWithOp (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z
public final fun doesTransactionContainSpanWithOpAndDescription (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;Ljava/lang/String;)Z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,68 @@ class TestHelper(backendUrl: String) {
return true
}

fun doesLogWithBodyHaveAttribute(
logs: SentryLogEvents,
body: String,
attributeKey: String,
attributeValue: Any?,
): Boolean {
val logItem = logs.items.firstOrNull { logItem -> logItem.body == body }
if (logItem == null) {
println("Unable to find log item with body $body in logs:")
logObject(logs)
return false
}

val attr = logItem.attributes?.get(attributeKey)
if (attr == null) {
println("Unable to find attribute $attributeKey on log with body $body:")
logObject(logItem)
return false
}

if (attr.value != attributeValue) {
println(
"Attribute $attributeKey has value ${attr.value} but expected $attributeValue on log with body $body:"
)
logObject(logItem)
return false
}

return true
}

fun doesMetricHaveAttribute(
metrics: SentryMetricsEvents,
metricName: String,
attributeKey: String,
attributeValue: Any?,
): Boolean {
val metricItem = metrics.items.firstOrNull { it.name == metricName }
if (metricItem == null) {
println("Unable to find metric with name $metricName in metrics:")
logObject(metrics)
return false
}

val attr = metricItem.attributes?.get(attributeKey)
if (attr == null) {
println("Unable to find attribute $attributeKey on metric $metricName:")
logObject(metricItem)
return false
}

if (attr.value != attributeValue) {
println(
"Attribute $attributeKey has value ${attr.value} but expected $attributeValue on metric $metricName:"
)
logObject(metricItem)
return false
}

return true
}

private fun checkIfTransactionMatches(
envelopeString: String,
callback: ((SentryTransaction, SentryEnvelopeHeader) -> Boolean),
Expand Down
Loading
Loading