Skip to content

Commit

Permalink
feat: Allow Hybrid SDK to setTrace (#4137)
Browse files Browse the repository at this point in the history
  • Loading branch information
bitsandfoxes authored Mar 3, 2025
1 parent 0584f7e commit 158d688
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 1 deletion.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

### Features

- The SDK now automatically propagates the trace-context to the native layer. This allows to connect errors on different layers of the application. ([#4137](https://github.com/getsentry/sentry-java/pull/4137))

### Dependencies

- Bump Native SDK from v0.7.20 to v0.8.1 ([#4137](https://github.com/getsentry/sentry-java/pull/4137))
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0810)
- [diff](https://github.com/getsentry/sentry-native/compare/v0.7.20...0.8.1)

## 8.3.0

### Features
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ object Config {
val apolloKotlin = "com.apollographql.apollo3:apollo-runtime:3.8.2"
val apolloKotlin4 = "com.apollographql.apollo:apollo-runtime:4.1.1"

val sentryNativeNdk = "io.sentry:sentry-native-ndk:0.7.20"
val sentryNativeNdk = "io.sentry:sentry-native-ndk:0.8.1"

object OpenTelemetry {
val otelVersion = "1.44.1"
Expand Down
1 change: 1 addition & 0 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ public final class io/sentry/android/core/InternalSentrySdk {
public static fun getAppStartMeasurement ()Ljava/util/Map;
public static fun getCurrentScope ()Lio/sentry/IScope;
public static fun serializeScope (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/IScope;)Ljava/util/Map;
public static fun setTrace (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Double;)V
}

public final class io/sentry/android/core/LoadClass : io/sentry/util/LoadClass {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.android.core;

import static io.sentry.Sentry.getCurrentScopes;
import static io.sentry.SentryLevel.DEBUG;
import static io.sentry.SentryLevel.INFO;
import static io.sentry.SentryLevel.WARNING;
Expand All @@ -13,6 +14,7 @@
import io.sentry.IScopes;
import io.sentry.ISerializer;
import io.sentry.ObjectWriter;
import io.sentry.PropagationContext;
import io.sentry.ScopeType;
import io.sentry.ScopesAdapter;
import io.sentry.SentryEnvelope;
Expand All @@ -30,6 +32,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;
import io.sentry.util.MapObjectWriter;
import io.sentry.util.TracingUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
Expand Down Expand Up @@ -329,4 +332,22 @@ private static Session updateSession(
});
return sessionRef.get();
}

/**
* Allows a Hybrid SDK to set the trace on the native layer
*
* @param traceId the trace ID
* @param spanId the trace origin's span ID
* @param sampleRate the sample rate used by the origin of the trace
* @param sampleRand the random value used to sample with by the origin of the trace
*/
public static void setTrace(
final @NotNull String traceId,
final @NotNull String spanId,
final @Nullable Double sampleRate,
final @Nullable Double sampleRand) {
TracingUtils.setTrace(
getCurrentScopes(),
PropagationContext.fromExistingTrace(traceId, spanId, sampleRate, sampleRand));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import io.sentry.SentryExceptionFactory
import io.sentry.SentryItemType
import io.sentry.SentryOptions
import io.sentry.Session
import io.sentry.SpanId
import io.sentry.android.core.performance.ActivityLifecycleTimeSpan
import io.sentry.android.core.performance.AppStartMetrics
import io.sentry.exception.ExceptionMechanismException
Expand Down Expand Up @@ -505,4 +506,25 @@ class InternalSentrySdkTest {
assertEquals(20.toLong(), actualProcessSpan["start_timestamp_ms"])
assertEquals(100.toLong(), actualProcessSpan["end_timestamp_ms"])
}

@Test
fun `setTrace sets correct propagation context`() {
val fixture = Fixture()
fixture.init(context)

val traceId = "771a43a4192642f0b136d5159a501700"
val spanId = "771a43a4192642f0"
val sampleRate = 0.5
val sampleRand = 0.3

InternalSentrySdk.setTrace(traceId, spanId, sampleRate, sampleRand)

Sentry.configureScope { scope ->
val propagationContext = scope.propagationContext
assertEquals(SentryId(traceId), propagationContext.traceId)
assertEquals(SpanId(spanId), propagationContext.parentSpanId)
assertEquals(sampleRate, propagationContext.baggage.sampleRateDouble)
assertEquals(sampleRand, propagationContext.baggage.sampleRandDouble)
}
}
}
1 change: 1 addition & 0 deletions sentry-android-ndk/api/sentry-android-ndk.api
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public final class io/sentry/android/ndk/NdkScopeObserver : io/sentry/ScopeObser
public fun removeTag (Ljava/lang/String;)V
public fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
public fun setTrace (Lio/sentry/SpanContext;Lio/sentry/IScope;)V
public fun setUser (Lio/sentry/protocol/User;)V
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import io.sentry.Breadcrumb;
import io.sentry.DateUtils;
import io.sentry.IScope;
import io.sentry.ScopeObserverAdapter;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.SpanContext;
import io.sentry.ndk.INativeScope;
import io.sentry.ndk.NativeScope;
import io.sentry.protocol.User;
Expand Down Expand Up @@ -125,4 +127,22 @@ public void removeExtra(final @NotNull String key) {
.log(SentryLevel.ERROR, e, "Scope sync removeExtra(%s) has an error.", key);
}
}

@Override
public void setTrace(@Nullable SpanContext spanContext, @NotNull IScope scope) {
if (spanContext == null) {
return;
}

try {
options
.getExecutorService()
.submit(
() ->
nativeScope.setTrace(
spanContext.getTraceId().toString(), spanContext.getSpanId().toString()));
} catch (Throwable e) {
options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setTrace failed.");
}
}
}
2 changes: 2 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -1952,6 +1952,7 @@ public final class io/sentry/PropagationContext {
public fun <init> ()V
public fun <init> (Lio/sentry/PropagationContext;)V
public fun <init> (Lio/sentry/protocol/SentryId;Lio/sentry/SpanId;Lio/sentry/SpanId;Lio/sentry/Baggage;Ljava/lang/Boolean;)V
public static fun fromExistingTrace (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Double;)Lio/sentry/PropagationContext;
public static fun fromHeaders (Lio/sentry/ILogger;Ljava/lang/String;Ljava/lang/String;)Lio/sentry/PropagationContext;
public static fun fromHeaders (Lio/sentry/ILogger;Ljava/lang/String;Ljava/util/List;)Lio/sentry/PropagationContext;
public static fun fromHeaders (Lio/sentry/SentryTraceHeader;Lio/sentry/Baggage;Lio/sentry/SpanId;)Lio/sentry/PropagationContext;
Expand Down Expand Up @@ -6360,6 +6361,7 @@ public final class io/sentry/util/TracingUtils {
public static fun ensureBaggage (Lio/sentry/Baggage;Ljava/lang/Boolean;Ljava/lang/Double;Ljava/lang/Double;)Lio/sentry/Baggage;
public static fun isIgnored (Ljava/util/List;Ljava/lang/String;)Z
public static fun maybeUpdateBaggage (Lio/sentry/IScope;Lio/sentry/SentryOptions;)Lio/sentry/PropagationContext;
public static fun setTrace (Lio/sentry/IScopes;Lio/sentry/PropagationContext;)V
public static fun startNewTrace (Lio/sentry/IScopes;)V
public static fun trace (Lio/sentry/IScopes;Ljava/util/List;Lio/sentry/ISpan;)Lio/sentry/util/TracingUtils$TracingHeaders;
public static fun traceIfAllowed (Lio/sentry/IScopes;Ljava/lang/String;Ljava/util/List;Lio/sentry/ISpan;)Lio/sentry/util/TracingUtils$TracingHeaders;
Expand Down
13 changes: 13 additions & 0 deletions sentry/src/main/java/io/sentry/PropagationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ public static PropagationContext fromHeaders(
sentryTraceHeader.isSampled());
}

public static @NotNull PropagationContext fromExistingTrace(
final @NotNull String traceId,
final @NotNull String spanId,
final @Nullable Double decisionSampleRate,
final @Nullable Double decisionSampleRand) {
return new PropagationContext(
new SentryId(traceId),
new SpanId(),
new SpanId(spanId),
TracingUtils.ensureBaggage(null, null, decisionSampleRate, decisionSampleRand),
null);
}

private @NotNull SentryId traceId;
private @NotNull SpanId spanId;
private @Nullable SpanId parentSpanId;
Expand Down
11 changes: 11 additions & 0 deletions sentry/src/main/java/io/sentry/util/TracingUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ public static void startNewTrace(final @NotNull IScopes scopes) {
});
}

public static void setTrace(
final @NotNull IScopes scopes, final @NotNull PropagationContext propagationContext) {
scopes.configureScope(
scope -> {
scope.withPropagationContext(
oldPropagationContext -> {
scope.setPropagationContext(propagationContext);
});
});
}

public static @Nullable TracingHeaders traceIfAllowed(
final @NotNull IScopes scopes,
final @NotNull String requestUrl,
Expand Down

0 comments on commit 158d688

Please sign in to comment.