Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,12 @@ private void setRelease(final @NotNull SentryBaseEvent event) {

private void setEnvironment(final @NotNull SentryBaseEvent event) {
if (event.getEnvironment() == null) {
final String scopeEnvironment =
readFromDisk(options, PersistingScopeObserver.ENVIRONMENT_FILENAME, String.class);
if (scopeEnvironment != null) {
event.setEnvironment(scopeEnvironment);
return;
}
final String environment =
PersistingOptionsObserver.read(options, ENVIRONMENT_FILENAME, String.class);
event.setEnvironment(environment != null ? environment : options.getEnvironment());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,18 @@ class ApplicationExitInfoEventProcessorTest {
assertEquals("release", processed.environment)
}

@Test
fun `if scope environment is persisted, it takes precedence over the options environment`() {
val hint = HintUtils.createWithTypeCheckHint(BackfillableHint())

val processor = fixture.getSut(tmpDir, populateOptionsCache = true)
fixture.persistScope(PersistingScopeObserver.ENVIRONMENT_FILENAME, "staging")

val processed = processor.process(SentryEvent(), hint)

assertEquals("staging", processed!!.environment)
}

@Test
fun `if dist is not persisted, backfills it from release`() {
val hint = HintUtils.createWithTypeCheckHint(BackfillableHint())
Expand Down
12 changes: 12 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ public final class io/sentry/CombinedScopeView : io/sentry/IScope {
public fun getBreadcrumbs ()Ljava/util/Queue;
public fun getClient ()Lio/sentry/ISentryClient;
public fun getContexts ()Lio/sentry/protocol/Contexts;
public fun getEnvironment ()Ljava/lang/String;
public fun getEventProcessors ()Ljava/util/List;
public fun getEventProcessorsWithOrder ()Ljava/util/List;
public fun getExtras ()Ljava/util/Map;
Expand Down Expand Up @@ -320,6 +321,7 @@ public final class io/sentry/CombinedScopeView : io/sentry/IScope {
public fun setContexts (Ljava/lang/String;Ljava/lang/String;)V
public fun setContexts (Ljava/lang/String;Ljava/util/Collection;)V
public fun setContexts (Ljava/lang/String;[Ljava/lang/Object;)V
public fun setEnvironment (Ljava/lang/String;)V
public fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public fun setFingerprint (Ljava/util/List;)V
public fun setLastEventId (Lio/sentry/protocol/SentryId;)V
Expand Down Expand Up @@ -921,6 +923,7 @@ public abstract interface class io/sentry/IScope {
public abstract fun getBreadcrumbs ()Ljava/util/Queue;
public abstract fun getClient ()Lio/sentry/ISentryClient;
public abstract fun getContexts ()Lio/sentry/protocol/Contexts;
public abstract fun getEnvironment ()Ljava/lang/String;
public abstract fun getEventProcessors ()Ljava/util/List;
public abstract fun getEventProcessorsWithOrder ()Ljava/util/List;
public abstract fun getExtras ()Ljava/util/Map;
Expand Down Expand Up @@ -956,6 +959,7 @@ public abstract interface class io/sentry/IScope {
public abstract fun setContexts (Ljava/lang/String;Ljava/lang/String;)V
public abstract fun setContexts (Ljava/lang/String;Ljava/util/Collection;)V
public abstract fun setContexts (Ljava/lang/String;[Ljava/lang/Object;)V
public abstract fun setEnvironment (Ljava/lang/String;)V
public abstract fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public abstract fun setFingerprint (Ljava/util/List;)V
public abstract fun setLastEventId (Lio/sentry/protocol/SentryId;)V
Expand Down Expand Up @@ -983,6 +987,7 @@ public abstract interface class io/sentry/IScopeObserver {
public abstract fun removeTag (Ljava/lang/String;)V
public abstract fun setBreadcrumbs (Ljava/util/Collection;)V
public abstract fun setContexts (Lio/sentry/protocol/Contexts;)V
public abstract fun setEnvironment (Ljava/lang/String;)V
public abstract fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public abstract fun setExtras (Ljava/util/Map;)V
public abstract fun setFingerprint (Ljava/util/Collection;)V
Expand Down Expand Up @@ -1743,6 +1748,7 @@ public final class io/sentry/NoOpScope : io/sentry/IScope {
public fun getBreadcrumbs ()Ljava/util/Queue;
public fun getClient ()Lio/sentry/ISentryClient;
public fun getContexts ()Lio/sentry/protocol/Contexts;
public fun getEnvironment ()Ljava/lang/String;
public fun getEventProcessors ()Ljava/util/List;
public fun getEventProcessorsWithOrder ()Ljava/util/List;
public fun getExtras ()Ljava/util/Map;
Expand Down Expand Up @@ -1779,6 +1785,7 @@ public final class io/sentry/NoOpScope : io/sentry/IScope {
public fun setContexts (Ljava/lang/String;Ljava/lang/String;)V
public fun setContexts (Ljava/lang/String;Ljava/util/Collection;)V
public fun setContexts (Ljava/lang/String;[Ljava/lang/Object;)V
public fun setEnvironment (Ljava/lang/String;)V
public fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public fun setFingerprint (Ljava/util/List;)V
public fun setLastEventId (Lio/sentry/protocol/SentryId;)V
Expand Down Expand Up @@ -2431,6 +2438,7 @@ public final class io/sentry/Scope : io/sentry/IScope {
public fun getBreadcrumbs ()Ljava/util/Queue;
public fun getClient ()Lio/sentry/ISentryClient;
public fun getContexts ()Lio/sentry/protocol/Contexts;
public fun getEnvironment ()Ljava/lang/String;
public fun getEventProcessors ()Ljava/util/List;
public fun getEventProcessorsWithOrder ()Ljava/util/List;
public fun getExtras ()Ljava/util/Map;
Expand Down Expand Up @@ -2466,6 +2474,7 @@ public final class io/sentry/Scope : io/sentry/IScope {
public fun setContexts (Ljava/lang/String;Ljava/lang/String;)V
public fun setContexts (Ljava/lang/String;Ljava/util/Collection;)V
public fun setContexts (Ljava/lang/String;[Ljava/lang/Object;)V
public fun setEnvironment (Ljava/lang/String;)V
public fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public fun setFingerprint (Ljava/util/List;)V
public fun setLastEventId (Lio/sentry/protocol/SentryId;)V
Expand Down Expand Up @@ -2514,6 +2523,7 @@ public abstract class io/sentry/ScopeObserverAdapter : io/sentry/IScopeObserver
public fun removeTag (Ljava/lang/String;)V
public fun setBreadcrumbs (Ljava/util/Collection;)V
public fun setContexts (Lio/sentry/protocol/Contexts;)V
public fun setEnvironment (Ljava/lang/String;)V
public fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public fun setExtras (Ljava/util/Map;)V
public fun setFingerprint (Ljava/util/Collection;)V
Expand Down Expand Up @@ -4867,6 +4877,7 @@ public final class io/sentry/cache/PersistingOptionsObserver : io/sentry/IOption
public final class io/sentry/cache/PersistingScopeObserver : io/sentry/ScopeObserverAdapter {
public static final field BREADCRUMBS_FILENAME Ljava/lang/String;
public static final field CONTEXTS_FILENAME Ljava/lang/String;
public static final field ENVIRONMENT_FILENAME Ljava/lang/String;
public static final field EXTRAS_FILENAME Ljava/lang/String;
public static final field FINGERPRINT_FILENAME Ljava/lang/String;
public static final field LEVEL_FILENAME Ljava/lang/String;
Expand All @@ -4883,6 +4894,7 @@ public final class io/sentry/cache/PersistingScopeObserver : io/sentry/ScopeObse
public fun resetCache ()V
public fun setBreadcrumbs (Ljava/util/Collection;)V
public fun setContexts (Lio/sentry/protocol/Contexts;)V
public fun setEnvironment (Ljava/lang/String;)V
public fun setExtras (Ljava/util/Map;)V
public fun setFingerprint (Ljava/util/Collection;)V
public fun setLevel (Lio/sentry/SentryLevel;)V
Expand Down
18 changes: 18 additions & 0 deletions sentry/src/main/java/io/sentry/CombinedScopeView.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ public void setLevel(@Nullable SentryLevel level) {
getDefaultWriteScope().setLevel(level);
}

@Override
public @Nullable String getEnvironment() {
final @Nullable String current = scope.getEnvironment();
if (current != null) {
return current;
}
final @Nullable String isolation = isolationScope.getEnvironment();
if (isolation != null) {
return isolation;
}
return globalScope.getEnvironment();
}

@Override
public void setEnvironment(@Nullable String environment) {
getDefaultWriteScope().setEnvironment(environment);
}

@Override
public @Nullable String getTransactionName() {
final @Nullable String current = scope.getTransactionName();
Expand Down
16 changes: 16 additions & 0 deletions sentry/src/main/java/io/sentry/IScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ public interface IScope {
*/
void setLevel(final @Nullable SentryLevel level);

/**
* Returns the Scope's environment.
*
* @return the environment or {@code null} if not set on the scope
*/
@Nullable
String getEnvironment();

/**
* Sets the Scope's environment. Takes precedence over {@link SentryOptions#getEnvironment()} when
* applied to events. Mainly used by hybrid SDKs to sync their environment into this SDK.
*
* @param environment the environment
*/
void setEnvironment(final @Nullable String environment);

/**
* Returns the Scope's transaction name.
*
Expand Down
2 changes: 2 additions & 0 deletions sentry/src/main/java/io/sentry/IScopeObserver.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public interface IScopeObserver {

void setLevel(@Nullable SentryLevel level);

void setEnvironment(@Nullable String environment);

void setContexts(@NotNull Contexts contexts);

void setTransaction(@Nullable String transaction);
Expand Down
8 changes: 8 additions & 0 deletions sentry/src/main/java/io/sentry/NoOpScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ public static NoOpScope getInstance() {
@Override
public void setLevel(@Nullable SentryLevel level) {}

@Override
public @Nullable String getEnvironment() {
return null;
}

@Override
public void setEnvironment(@Nullable String environment) {}

@Override
public @Nullable String getTransactionName() {
return null;
Expand Down
30 changes: 30 additions & 0 deletions sentry/src/main/java/io/sentry/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public final class Scope implements IScope {
/** Scope's screen */
private @Nullable String screen;

/** Scope's environment */
private @Nullable String environment;

/** Scope's request */
private @Nullable Request request;

Expand Down Expand Up @@ -137,6 +140,7 @@ private Scope(final @NotNull Scope scope) {
final User userRef = scope.user;
this.user = userRef != null ? new User(userRef) : null;
this.screen = scope.screen;
this.environment = scope.environment;
this.replayId = scope.replayId;

final Request requestRef = scope.request;
Expand Down Expand Up @@ -224,6 +228,32 @@ public void setLevel(final @Nullable SentryLevel level) {
}
}

/**
* Returns the Scope's environment.
*
* @return the environment or {@code null} if not set on the scope
*/
@Override
public @Nullable String getEnvironment() {
return environment;
}

/**
* Sets the Scope's environment. Mainly used by hybrid SDKs (e.g. .NET, Unity) to sync their
* environment into this SDK. Takes precedence over {@link SentryOptions#getEnvironment()} when
* applied to events.
*
* @param environment the environment
*/
@Override
public void setEnvironment(final @Nullable String environment) {
this.environment = environment;

for (final IScopeObserver observer : options.getScopeObservers()) {
observer.setEnvironment(environment);
}
}

/**
* Returns the Scope's transaction name.
*
Expand Down
3 changes: 3 additions & 0 deletions sentry/src/main/java/io/sentry/ScopeObserverAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ public void setFingerprint(@NotNull Collection<String> fingerprint) {}
@Override
public void setLevel(@Nullable SentryLevel level) {}

@Override
public void setEnvironment(@Nullable String environment) {}

@Override
public void setContexts(@NotNull Contexts contexts) {}

Expand Down
3 changes: 3 additions & 0 deletions sentry/src/main/java/io/sentry/SentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,9 @@ public void captureBatchedMetricsEvents(final @NotNull SentryMetricsEvents metri
if (sentryBaseEvent.getUser() == null) {
sentryBaseEvent.setUser(scope.getUser());
}
if (sentryBaseEvent.getEnvironment() == null) {
sentryBaseEvent.setEnvironment(scope.getEnvironment());
}
if (sentryBaseEvent.getTags() == null) {
sentryBaseEvent.setTags(scope.getTags());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public final class PersistingScopeObserver extends ScopeObserverAdapter {
public static final String CONTEXTS_FILENAME = "contexts.json";
public static final String REQUEST_FILENAME = "request.json";
public static final String LEVEL_FILENAME = "level.json";
public static final String ENVIRONMENT_FILENAME = "environment.json";
public static final String FINGERPRINT_FILENAME = "fingerprint.json";
public static final String TRANSACTION_FILENAME = "transaction.json";
public static final String TRACE_FILENAME = "trace.json";
Expand Down Expand Up @@ -189,6 +190,18 @@ public void setLevel(@Nullable SentryLevel level) {
});
}

@Override
public void setEnvironment(@Nullable String environment) {
serializeToDisk(
() -> {
if (environment == null) {
delete(ENVIRONMENT_FILENAME);
} else {
store(environment, ENVIRONMENT_FILENAME);
}
});
}

@Override
public void setTransaction(@Nullable String transaction) {
serializeToDisk(
Expand Down Expand Up @@ -296,6 +309,7 @@ public void resetCache() {
// the rest we can safely delete
delete(USER_FILENAME);
delete(LEVEL_FILENAME);
delete(ENVIRONMENT_FILENAME);
delete(REQUEST_FILENAME);
delete(FINGERPRINT_FILENAME);
delete(CONTEXTS_FILENAME);
Expand Down
30 changes: 30 additions & 0 deletions sentry/src/test/java/io/sentry/ScopeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,36 @@ class ScopeTest {
verify(observer).setLevel(eq(WARNING))
}

@Test
fun `Scope set environment sync scopes`() {
val observer = mock<IScopeObserver>()
val options = SentryOptions().apply { addScopeObserver(observer) }
val scope = Scope(options)

scope.environment = "staging"
verify(observer).setEnvironment(eq("staging"))
}

@Test
fun `Scope set environment null sync scopes`() {
val observer = mock<IScopeObserver>()
val options = SentryOptions().apply { addScopeObserver(observer) }
val scope = Scope(options)

scope.environment = null
verify(observer).setEnvironment(null)
}

@Test
fun `Scope clone copies environment`() {
val scope = Scope(SentryOptions())
scope.environment = "staging"

val clone = scope.clone()

assertEquals("staging", clone.environment)
}

@Test
fun `Scope set transaction name sync scopes`() {
val observer = mock<IScopeObserver>()
Expand Down
33 changes: 22 additions & 11 deletions sentry/src/test/java/io/sentry/SentryClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -570,24 +570,35 @@ class SentryClientTest {
}

@Test
fun `when event has environment, value from options not applied`() {
fun `when scope has environment, it takes precedence over options`() {
val event = SentryEvent()
val expected = "original"
fixture.sentryOptions.environment = "not to be applied"
event.environment = expected
val scope = createScope()
scope.environment = "from-scope"
fixture.sentryOptions.environment = "from-options"
val sut = fixture.getSut()
sut.captureEvent(event)
assertEquals(expected, event.environment)
sut.captureEvent(event, scope)
assertEquals("from-scope", event.environment)
}

@Test
fun `when event doesn't have environment, value from options applied`() {
fun `when event has environment, scope environment not applied`() {
val event = SentryEvent()
val expected = "original"
fixture.sentryOptions.environment = expected
event.environment = "from-event"
val scope = createScope()
scope.environment = "from-scope"
val sut = fixture.getSut()
sut.captureEvent(event)
assertEquals(expected, event.environment)
sut.captureEvent(event, scope)
assertEquals("from-event", event.environment)
}

@Test
fun `when scope has no environment, value from options applied`() {
val event = SentryEvent()
val scope = createScope()
fixture.sentryOptions.environment = "from-options"
val sut = fixture.getSut()
sut.captureEvent(event, scope)
assertEquals("from-options", event.environment)
}

@Test
Expand Down
Loading
Loading