diff --git a/sentry-opentelemetry/sentry-opentelemetry-extra/src/main/java/io/sentry/opentelemetry/OtelSpanWrapper.java b/sentry-opentelemetry/sentry-opentelemetry-extra/src/main/java/io/sentry/opentelemetry/OtelSpanWrapper.java index 85526b200f..fa051eeb68 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-extra/src/main/java/io/sentry/opentelemetry/OtelSpanWrapper.java +++ b/sentry-opentelemetry/sentry-opentelemetry-extra/src/main/java/io/sentry/opentelemetry/OtelSpanWrapper.java @@ -128,8 +128,10 @@ public OtelSpanWrapper( final @NotNull ISpan childSpan = scopes.getOptions().getSpanFactory().createSpan(scopes, spanOptions, spanContext, this); - // TODO [POTEL] spanOptions.isBindToScope with default true? - childSpan.makeCurrent(); + + if (spanOptions.isBindToScope()) { + childSpan.makeCurrent(); + } return childSpan; } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index ff14481eda..50a49ce24f 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -607,6 +607,7 @@ public final class io/sentry/HubAdapter : io/sentry/IHub { public fun setTransaction (Ljava/lang/String;)V public fun setUser (Lio/sentry/protocol/User;)V public fun startSession ()V + public fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun traceHeaders ()Lio/sentry/SentryTraceHeader; public fun withIsolationScope (Lio/sentry/ScopeCallback;)V @@ -673,6 +674,7 @@ public final class io/sentry/HubScopesWrapper : io/sentry/IHub { public fun setTransaction (Ljava/lang/String;)V public fun setUser (Lio/sentry/protocol/User;)V public fun startSession ()V + public fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun traceHeaders ()Lio/sentry/SentryTraceHeader; public fun withIsolationScope (Lio/sentry/ScopeCallback;)V @@ -912,6 +914,7 @@ public abstract interface class io/sentry/IScopes { public abstract fun setTransaction (Ljava/lang/String;)V public abstract fun setUser (Lio/sentry/protocol/User;)V public abstract fun startSession ()V + public abstract fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;)Lio/sentry/ITransaction; public abstract fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun startTransaction (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ITransaction; @@ -1450,6 +1453,7 @@ public final class io/sentry/NoOpHub : io/sentry/IHub { public fun setTransaction (Ljava/lang/String;)V public fun setUser (Lio/sentry/protocol/User;)V public fun startSession ()V + public fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun traceHeaders ()Lio/sentry/SentryTraceHeader; public fun withIsolationScope (Lio/sentry/ScopeCallback;)V @@ -1611,6 +1615,7 @@ public final class io/sentry/NoOpScopes : io/sentry/IScopes { public fun setTransaction (Ljava/lang/String;)V public fun setUser (Lio/sentry/protocol/User;)V public fun startSession ()V + public fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun traceHeaders ()Lio/sentry/SentryTraceHeader; public fun withIsolationScope (Lio/sentry/ScopeCallback;)V @@ -2207,6 +2212,7 @@ public final class io/sentry/Scopes : io/sentry/IScopes, io/sentry/metrics/Metri public fun setTransaction (Ljava/lang/String;)V public fun setUser (Lio/sentry/protocol/User;)V public fun startSession ()V + public fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startSpanForMetric (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun traceHeaders ()Lio/sentry/SentryTraceHeader; @@ -2274,6 +2280,7 @@ public final class io/sentry/ScopesAdapter : io/sentry/IScopes { public fun setTransaction (Ljava/lang/String;)V public fun setUser (Lio/sentry/protocol/User;)V public fun startSession ()V + public fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public fun traceHeaders ()Lio/sentry/SentryTraceHeader; public fun withIsolationScope (Lio/sentry/ScopeCallback;)V @@ -2381,6 +2388,7 @@ public final class io/sentry/Sentry { public static fun setTransaction (Ljava/lang/String;)V public static fun setUser (Lio/sentry/protocol/User;)V public static fun startSession ()V + public static fun startSpan (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; public static fun startTransaction (Lio/sentry/TransactionContext;)Lio/sentry/ITransaction; public static fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction; public static fun startTransaction (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ITransaction; @@ -3552,9 +3560,11 @@ public class io/sentry/SpanOptions { public fun ()V public fun getOrigin ()Ljava/lang/String; public fun getStartTimestamp ()Lio/sentry/SentryDate; + public fun isBindToScope ()Z public fun isIdle ()Z public fun isTrimEnd ()Z public fun isTrimStart ()Z + public fun setBindToScope (Z)V public fun setIdle (Z)V public fun setOrigin (Ljava/lang/String;)V public fun setStartTimestamp (Lio/sentry/SentryDate;)V @@ -3696,10 +3706,8 @@ public final class io/sentry/TransactionOptions : io/sentry/SpanOptions { public fun getSpanFactory ()Lio/sentry/ISpanFactory; public fun getTransactionFinishedCallback ()Lio/sentry/TransactionFinishedCallback; public fun isAppStartTransaction ()Z - public fun isBindToScope ()Z public fun isWaitForChildren ()Z public fun setAppStartTransaction (Z)V - public fun setBindToScope (Z)V public fun setCustomSamplingContext (Lio/sentry/CustomSamplingContext;)V public fun setDeadlineTimeout (Ljava/lang/Long;)V public fun setIdleTimeout (Ljava/lang/Long;)V diff --git a/sentry/src/main/java/io/sentry/HubAdapter.java b/sentry/src/main/java/io/sentry/HubAdapter.java index 81ae409286..be14474d8f 100644 --- a/sentry/src/main/java/io/sentry/HubAdapter.java +++ b/sentry/src/main/java/io/sentry/HubAdapter.java @@ -278,6 +278,12 @@ public boolean isAncestorOf(final @Nullable IScopes otherScopes) { return Sentry.startTransaction(transactionContext, transactionOptions); } + @Override + public @NotNull ISpan startSpan( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + return Sentry.startSpan(spanContext, spanOptions); + } + @Deprecated @Override public @Nullable SentryTraceHeader traceHeaders() { diff --git a/sentry/src/main/java/io/sentry/HubScopesWrapper.java b/sentry/src/main/java/io/sentry/HubScopesWrapper.java index f1b5c31a6c..2f1fa0e80e 100644 --- a/sentry/src/main/java/io/sentry/HubScopesWrapper.java +++ b/sentry/src/main/java/io/sentry/HubScopesWrapper.java @@ -273,6 +273,12 @@ public boolean isAncestorOf(final @Nullable IScopes otherScopes) { return scopes.startTransaction(transactionContext, transactionOptions); } + @Override + public @NotNull ISpan startSpan( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + return scopes.startSpan(spanContext, spanOptions); + } + @Override public @Nullable SentryTraceHeader traceHeaders() { return scopes.traceHeaders(); diff --git a/sentry/src/main/java/io/sentry/IScopes.java b/sentry/src/main/java/io/sentry/IScopes.java index f85f2b7c4a..194bddb615 100644 --- a/sentry/src/main/java/io/sentry/IScopes.java +++ b/sentry/src/main/java/io/sentry/IScopes.java @@ -583,6 +583,16 @@ ITransaction startTransaction( final @NotNull TransactionContext transactionContext, final @NotNull TransactionOptions transactionOptions); + /** + * Creates a span and returns the instance. + * + * @param spanContext the span context + * @param spanOptions the span options + * @return created span + */ + @NotNull + ISpan startSpan(final @NotNull SpanContext spanContext, final @NotNull SpanOptions spanOptions); + /** * Returns the "sentry-trace" header that allows tracing across services. Can also be used in * <meta> HTML tags. Also see {@link IScopes#getBaggage()}. diff --git a/sentry/src/main/java/io/sentry/NoOpHub.java b/sentry/src/main/java/io/sentry/NoOpHub.java index c71fcd628c..fdcfe96beb 100644 --- a/sentry/src/main/java/io/sentry/NoOpHub.java +++ b/sentry/src/main/java/io/sentry/NoOpHub.java @@ -242,6 +242,12 @@ public boolean isAncestorOf(@Nullable IScopes otherScopes) { return NoOpTransaction.getInstance(); } + @Override + public @NotNull ISpan startSpan( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + return NoOpSpan.getInstance(); + } + @Override @Deprecated @SuppressWarnings("InlineMeSuggester") diff --git a/sentry/src/main/java/io/sentry/NoOpScopes.java b/sentry/src/main/java/io/sentry/NoOpScopes.java index fb8372d832..5ea3acb22d 100644 --- a/sentry/src/main/java/io/sentry/NoOpScopes.java +++ b/sentry/src/main/java/io/sentry/NoOpScopes.java @@ -237,6 +237,12 @@ public boolean isAncestorOf(@Nullable IScopes otherScopes) { return NoOpTransaction.getInstance(); } + @Override + public @NotNull ISpan startSpan( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + return NoOpSpan.getInstance(); + } + @Override @Deprecated @SuppressWarnings("InlineMeSuggester") diff --git a/sentry/src/main/java/io/sentry/Scopes.java b/sentry/src/main/java/io/sentry/Scopes.java index 5bc139168c..17e88a099f 100644 --- a/sentry/src/main/java/io/sentry/Scopes.java +++ b/sentry/src/main/java/io/sentry/Scopes.java @@ -823,6 +823,95 @@ public void flush(long timeoutMillis) { return createTransaction(transactionContext, transactionOptions); } + @Override + public @NotNull ISpan startSpan( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + final @Nullable ISpan parentSpan = getSpan(); + if (parentSpan == null) { + return startTransaction( + new TransactionContext(spanContext), new TransactionOptions(spanOptions)); + } else { + return parentSpan.startChild(spanContext, spanOptions); + } + } + + // @Override + // public @NotNull ISpan startSpan(@NotNull SpanContext spanContext, @NotNull SpanOptions + // spanOptions) { + // Objects.requireNonNull(spanContext, "spanContext is required"); + // + // spanContext.setOrigin(spanOptions.getOrigin()); + // + // ISpan span; + // if (!isEnabled()) { + // getOptions() + // .getLogger() + // .log( + // SentryLevel.WARNING, + // "Instance is disabled and this 'startSpan' returns a no-op."); + // span = NoOpSpan.getInstance(); + // } else if (SpanUtils.isIgnored( + // getOptions().getIgnoredSpanOrigins(), spanContext.getOrigin())) { + // getOptions() + // .getLogger() + // .log( + // SentryLevel.DEBUG, + // "Returning no-op for span origin %s as the SDK has been configured to ignore it", + // transactionContext.getOrigin()); + // span = NoOpSpan.getInstance(); + // + // } else if (!getOptions().getInstrumenter().equals(spanContext.getInstrumenter())) { + // getOptions() + // .getLogger() + // .log( + // SentryLevel.DEBUG, + // "Returning no-op for instrumenter %s as the SDK has been configured to use + // instrumenter %s", + // spanContext.getInstrumenter(), + // getOptions().getInstrumenter()); + // span = NoOpSpan.getInstance(); + // } else if (!getOptions().isTracingEnabled()) { + // getOptions() + // .getLogger() + // .log( + // SentryLevel.INFO, "Tracing is disabled and this 'startSpan' returns a no-op."); + // span = NoOpSpan.getInstance(); + // } else { + // final SamplingContext samplingContext = + // new SamplingContext(spanContext, spanOptions.getCustomSamplingContext()); + // final @NotNull TracesSampler tracesSampler = getOptions().getInternalTracesSampler(); + // @NotNull TracesSamplingDecision samplingDecision = tracesSampler.sample(samplingContext); + // spanContext.setSamplingDecision(samplingDecision); + // + // final @Nullable ISpanFactory maybeSpanFactory = spanOptions.getSpanFactory(); + // final @NotNull ISpanFactory spanFactory = + // maybeSpanFactory == null ? getOptions().getSpanFactory() : maybeSpanFactory; + // + // // TODO [POTEL] parent span? + // span = + // spanFactory.createSpan(this, spanOptions, spanContext, null); + // + // // The listener is called only if the transaction exists, as the transaction is needed to + // // stop it + // if (samplingDecision.getSampled() && samplingDecision.getProfileSampled()) { + // final ITransactionProfiler transactionProfiler = getOptions().getTransactionProfiler(); + // // If the profiler is not running, we start and bind it here. + // if (!transactionProfiler.isRunning()) { + // transactionProfiler.start(); + // transactionProfiler.bindTransaction(transaction); + // } else if (transactionOptions.isAppStartTransaction()) { + // // If the profiler is running and the current transaction is the app start, we bind + // it. + // transactionProfiler.bindTransaction(transaction); + // } + // } + // } + // if (spanOptions.isBindToScope()) { + // span.makeCurrent(); + // } + // return span; + // } + private @NotNull ITransaction createTransaction( final @NotNull TransactionContext transactionContext, final @NotNull TransactionOptions transactionOptions) { diff --git a/sentry/src/main/java/io/sentry/ScopesAdapter.java b/sentry/src/main/java/io/sentry/ScopesAdapter.java index 436b266e8d..e3c2c60ec8 100644 --- a/sentry/src/main/java/io/sentry/ScopesAdapter.java +++ b/sentry/src/main/java/io/sentry/ScopesAdapter.java @@ -276,6 +276,12 @@ public boolean isAncestorOf(final @Nullable IScopes otherScopes) { return Sentry.startTransaction(transactionContext, transactionOptions); } + @Override + public @NotNull ISpan startSpan( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + return Sentry.startSpan(spanContext, spanOptions); + } + @Deprecated @Override @SuppressWarnings("deprecation") diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index ddf369888b..ebb0e52f59 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -1022,6 +1022,18 @@ public static void endSession() { return getCurrentScopes().startTransaction(transactionContext, transactionOptions); } + /** + * Creates a Span and returns the instance. + * + * @param spanContext the span context + * @param spanOptions options for the span + * @return created span, may be a NoOp + */ + public static @NotNull ISpan startSpan( + final @NotNull SpanContext spanContext, final @NotNull SpanOptions spanOptions) { + return getCurrentScopes().startSpan(spanContext, spanOptions); + } + /** * Returns the "sentry-trace" header that allows tracing across services. Can also be used in * <meta> HTML tags. Also see {@link Sentry#getBaggage()}. diff --git a/sentry/src/main/java/io/sentry/SpanOptions.java b/sentry/src/main/java/io/sentry/SpanOptions.java index 41ac313ae5..9bab6da059 100644 --- a/sentry/src/main/java/io/sentry/SpanOptions.java +++ b/sentry/src/main/java/io/sentry/SpanOptions.java @@ -10,6 +10,21 @@ @Open public class SpanOptions { + public SpanOptions() {} + + /** + * copy constructor + * + * @param spanOptions options to copy + */ + SpanOptions(SpanOptions spanOptions) { + startTimestamp = spanOptions.startTimestamp; + trimStart = spanOptions.trimStart; + trimEnd = spanOptions.trimEnd; + isIdle = spanOptions.isIdle; + origin = spanOptions.origin; + } + /** The start timestamp of the transaction */ private @Nullable SentryDate startTimestamp = null; @@ -53,6 +68,9 @@ public void setStartTimestamp(@Nullable SentryDate startTimestamp) { protected @Nullable String origin = DEFAULT_ORIGIN; + /** Defines if transaction should be bound to scope */ + private boolean bindToScope = false; + public boolean isTrimStart() { return trimStart; } @@ -84,4 +102,22 @@ public void setIdle(boolean idle) { public void setOrigin(final @Nullable String origin) { this.origin = origin; } + + /** + * Checks if bindToScope is enabled + * + * @return true if enabled or false otherwise + */ + public boolean isBindToScope() { + return bindToScope; + } + + /** + * Sets bindToScope to enabled or disabled + * + * @param bindToScope true if enabled or false otherwise + */ + public void setBindToScope(boolean bindToScope) { + this.bindToScope = bindToScope; + } } diff --git a/sentry/src/main/java/io/sentry/TransactionContext.java b/sentry/src/main/java/io/sentry/TransactionContext.java index d81aa1059d..9cfdee3723 100644 --- a/sentry/src/main/java/io/sentry/TransactionContext.java +++ b/sentry/src/main/java/io/sentry/TransactionContext.java @@ -140,6 +140,15 @@ public TransactionContext( this.baggage = baggage; } + @ApiStatus.Internal + TransactionContext(SpanContext spanContext) { + super(spanContext); + this.name = DEFAULT_TRANSACTION_NAME; + this.parentSamplingDecision = null; + this.transactionNameSource = DEFAULT_NAME_SOURCE; + this.baggage = null; + } + public @NotNull String getName() { return name; } diff --git a/sentry/src/main/java/io/sentry/TransactionOptions.java b/sentry/src/main/java/io/sentry/TransactionOptions.java index 782e35a039..a36ced59fc 100644 --- a/sentry/src/main/java/io/sentry/TransactionOptions.java +++ b/sentry/src/main/java/io/sentry/TransactionOptions.java @@ -15,9 +15,6 @@ public final class TransactionOptions extends SpanOptions { */ private @Nullable CustomSamplingContext customSamplingContext = null; - /** Defines if transaction should be bound to scope */ - private boolean bindToScope = false; - /** Defines if transaction refers to the app start process */ private boolean isAppStartTransaction = false; @@ -57,6 +54,12 @@ public final class TransactionOptions extends SpanOptions { /** Span factory to use. Uses factory configured in {@link SentryOptions} if `null`. */ @ApiStatus.Internal private @Nullable ISpanFactory spanFactory = null; + public TransactionOptions() {} + + TransactionOptions(SpanOptions spanOptions) { + super(spanOptions); + } + /** * Gets the customSamplingContext * @@ -75,24 +78,6 @@ public void setCustomSamplingContext(@Nullable CustomSamplingContext customSampl this.customSamplingContext = customSamplingContext; } - /** - * Checks if bindToScope is enabled - * - * @return true if enabled or false otherwise - */ - public boolean isBindToScope() { - return bindToScope; - } - - /** - * Sets bindToScope to enabled or disabled - * - * @param bindToScope true if enabled or false otherwise - */ - public void setBindToScope(boolean bindToScope) { - this.bindToScope = bindToScope; - } - /** * Checks if waitForChildren is enabled *