Skip to content

Commit

Permalink
Merge branch 'main' into feat/test-error-otel-transaction-link
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed Dec 20, 2022
2 parents 8b47a99 + ad3465a commit 319b527
Show file tree
Hide file tree
Showing 90 changed files with 2,042 additions and 378 deletions.
2 changes: 1 addition & 1 deletion .craft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ targets:
mavenRepoUrl: https://oss.sonatype.org/service/local/staging/deploy/maven2/
android:
distDirRegex: /^(sentry-android-|.*-android).*$/
fileReplaceeRegex: /\d\.\d\.\d(-\w+(\.\d)?)?(-SNAPSHOT)?/
fileReplaceeRegex: /\d+\.\d+\.\d+(-\w+(\.\d+)?)?(-SNAPSHOT)?/
fileReplacerStr: release.aar
- name: github
excludeNames: /^libsentry.*\.so$/
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ jobs:
${{ runner.os }}-gradle-
- name: Initialize CodeQL
uses: github/codeql-action/init@c3b6fce4ee2ca25bc1066aa3bf73962fda0e8898 # pin@v2
uses: github/codeql-action/init@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # pin@v2
with:
languages: ${{ matrix.language }}

- run: |
./gradlew assemble
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c3b6fce4ee2ca25bc1066aa3bf73962fda0e8898 # pin@v2
uses: github/codeql-action/analyze@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # pin@v2
2 changes: 1 addition & 1 deletion .github/workflows/generate-javadocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
run: |
./gradlew aggregateJavadocs
- name: Deploy
uses: JamesIves/github-pages-deploy-action@132898c54c57c7cc6b80eb3a89968de8fc283505 # pin@3.7.1
uses: JamesIves/github-pages-deploy-action@ba1486788b0490a235422264426c45848eac35c6 # pin@4.4.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
Expand Down
21 changes: 17 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@

## Unreleased

### Fixes

- Use minSdk compatible `Objects` class ([#2436](https://github.com/getsentry/sentry-java/pull/2436))

### Features

- Add logging for OpenTelemetry integration ([#2425](https://github.com/getsentry/sentry-java/pull/2425))

## 6.10.0

### Features

- Add time-to-initial-display span to Activity transactions ([#2369](https://github.com/getsentry/sentry-java/pull/2369))
- Start a session after init if AutoSessionTracking is enabled ([#2356](https://github.com/getsentry/sentry-java/pull/2356))
- Provide automatic breadcrumbs and transactions for click/scroll events for Compose ([#2390](https://github.com/getsentry/sentry-java/pull/2390))
- Add `blocked_main_thread` and `call_stack` to File I/O spans to detect performance issues ([#2382](https://github.com/getsentry/sentry-java/pull/2382))

### Dependencies

- Bump Native SDK from v0.5.2 to v0.5.3 ([#2423](https://github.com/getsentry/sentry-java/pull/2423))
Expand Down Expand Up @@ -59,15 +72,15 @@

## 6.8.0

### Features

- Add FrameMetrics to Android profiling data ([#2342](https://github.com/getsentry/sentry-java/pull/2342))

### Fixes

- Remove profiler main thread io ([#2348](https://github.com/getsentry/sentry-java/pull/2348))
- Fix ensure all options are processed before integrations are loaded ([#2377](https://github.com/getsentry/sentry-java/pull/2377))

### Features

- Add FrameMetrics to Android profiling data ([#2342](https://github.com/getsentry/sentry-java/pull/2342))

## 6.7.1

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ subprojects {
}
}

if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-test-support") {
if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-test-support" && this.name != "sentry-compose-helper") {
apply<DistributionPlugin>()

val sep = File.separator
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ org.gradle.parallel=true
android.useAndroidX=true

# Release information
versionName=6.9.2
versionName=6.10.0

# Override the SDK name on native crashes on Android
sentryAndroidSdkName=sentry.native.android
Expand Down
5 changes: 1 addition & 4 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public final class io/sentry/android/core/ActivityLifecycleIntegration : android
public fun onActivityDestroyed (Landroid/app/Activity;)V
public fun onActivityPaused (Landroid/app/Activity;)V
public fun onActivityPostResumed (Landroid/app/Activity;)V
public fun onActivityPrePaused (Landroid/app/Activity;)V
public fun onActivityResumed (Landroid/app/Activity;)V
public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityStarted (Landroid/app/Activity;)V
Expand Down Expand Up @@ -159,8 +160,6 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
public fun isEnableAutoActivityLifecycleTracing ()Z
public fun isEnableFramesTracking ()Z
public fun isEnableSystemEventBreadcrumbs ()Z
public fun isEnableUserInteractionBreadcrumbs ()Z
public fun isEnableUserInteractionTracing ()Z
public fun setAnrEnabled (Z)V
public fun setAnrReportInDebug (Z)V
public fun setAnrTimeoutIntervalMillis (J)V
Expand All @@ -174,8 +173,6 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
public fun setEnableAutoActivityLifecycleTracing (Z)V
public fun setEnableFramesTracking (Z)V
public fun setEnableSystemEventBreadcrumbs (Z)V
public fun setEnableUserInteractionBreadcrumbs (Z)V
public fun setEnableUserInteractionTracing (Z)V
public fun setProfilingTracesHz (I)V
public fun setProfilingTracesIntervalMillis (I)V
}
Expand Down
1 change: 1 addition & 0 deletions sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ dependencies {
api(projects.sentry)
compileOnly(projects.sentryAndroidFragment)
compileOnly(projects.sentryAndroidTimber)
compileOnly(projects.sentryCompose)

// lifecycle processor, session tracking
implementation(Config.Libs.lifecycleProcess)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import androidx.core.app.FrameMetricsAggregator;
import io.sentry.MeasurementUnit;
import io.sentry.SentryLevel;
import io.sentry.android.core.internal.util.MainThreadChecker;
import io.sentry.android.core.internal.util.AndroidMainThreadChecker;
import io.sentry.protocol.MeasurementValue;
import io.sentry.protocol.SentryId;
import java.util.HashMap;
Expand Down Expand Up @@ -208,7 +208,7 @@ public synchronized void stop() {

private void runSafelyOnUiThread(final Runnable runnable, final String tag) {
try {
if (MainThreadChecker.isMainThread()) {
if (AndroidMainThreadChecker.getInstance().isMainThread()) {
runnable.run();
} else {
handler.post(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.view.View;
import androidx.annotation.NonNull;
import io.sentry.Breadcrumb;
import io.sentry.DateUtils;
import io.sentry.Hint;
import io.sentry.IHub;
import io.sentry.ISpan;
Expand All @@ -23,6 +29,7 @@
import io.sentry.SpanStatus;
import io.sentry.TransactionContext;
import io.sentry.TransactionOptions;
import io.sentry.android.core.internal.util.FirstDrawDoneListener;
import io.sentry.protocol.TransactionNameSource;
import io.sentry.util.Objects;
import java.io.Closeable;
Expand All @@ -43,8 +50,10 @@ public final class ActivityLifecycleIntegration
static final String UI_LOAD_OP = "ui.load";
static final String APP_START_WARM = "app.start.warm";
static final String APP_START_COLD = "app.start.cold";
static final String TTID_OP = "ui.load.initial_display";

private final @NotNull Application application;
private final @NotNull BuildInfoProvider buildInfoProvider;
private @Nullable IHub hub;
private @Nullable SentryAndroidOptions options;

Expand All @@ -57,6 +66,9 @@ public final class ActivityLifecycleIntegration
private boolean foregroundImportance = false;

private @Nullable ISpan appStartSpan;
private final @NotNull WeakHashMap<Activity, ISpan> ttidSpanMap = new WeakHashMap<>();
private @NotNull Date lastPausedTime = DateUtils.getCurrentDateTime();
private final @NotNull Handler mainHandler = new Handler(Looper.getMainLooper());

// WeakHashMap isn't thread safe but ActivityLifecycleCallbacks is only called from the
// main-thread
Expand All @@ -70,7 +82,8 @@ public ActivityLifecycleIntegration(
final @NotNull BuildInfoProvider buildInfoProvider,
final @NotNull ActivityFramesTracker activityFramesTracker) {
this.application = Objects.requireNonNull(application, "Application is required");
Objects.requireNonNull(buildInfoProvider, "BuildInfoProvider is required");
this.buildInfoProvider =
Objects.requireNonNull(buildInfoProvider, "BuildInfoProvider is required");
this.activityFramesTracker =
Objects.requireNonNull(activityFramesTracker, "ActivityFramesTracker is required");

Expand Down Expand Up @@ -146,7 +159,8 @@ private void stopPreviousTransactions() {
for (final Map.Entry<Activity, ITransaction> entry :
activitiesWithOngoingTransactions.entrySet()) {
final ITransaction transaction = entry.getValue();
finishTransaction(transaction);
final ISpan ttidSpan = ttidSpanMap.get(entry.getKey());
finishTransaction(transaction, ttidSpan);
}
}

Expand Down Expand Up @@ -202,6 +216,18 @@ private void startTracing(final @NotNull Activity activity) {
getAppStartDesc(coldStart),
appStartTime,
Instrumenter.SENTRY);
// The first activity ttidSpan should start at the same time as the app start time
ttidSpanMap.put(
activity,
transaction.startChild(
TTID_OP, getTtidDesc(activityName), appStartTime, Instrumenter.SENTRY));
} else {
// Other activities (or in case appStartTime is not available) the ttid span should
// start when the previous activity called its onPause method.
ttidSpanMap.put(
activity,
transaction.startChild(
TTID_OP, getTtidDesc(activityName), lastPausedTime, Instrumenter.SENTRY));
}

// lets bind to the scope so other integrations can pick it up
Expand Down Expand Up @@ -250,18 +276,22 @@ private boolean isRunningTransaction(final @NotNull Activity activity) {
private void stopTracing(final @NotNull Activity activity, final boolean shouldFinishTracing) {
if (performanceEnabled && shouldFinishTracing) {
final ITransaction transaction = activitiesWithOngoingTransactions.get(activity);
finishTransaction(transaction);
finishTransaction(transaction, null);
}
}

private void finishTransaction(final @Nullable ITransaction transaction) {
private void finishTransaction(
final @Nullable ITransaction transaction, final @Nullable ISpan ttidSpan) {
if (transaction != null) {
// if io.sentry.traces.activity.auto-finish.enable is disabled, transaction may be already
// finished manually when this method is called.
if (transaction.isFinished()) {
return;
}

// in case the ttidSpan isn't completed yet, we finish it as cancelled to avoid memory leak
finishSpan(ttidSpan, SpanStatus.CANCELLED);

SpanStatus status = transaction.getStatus();
// status might be set by other integrations, let's not overwrite it
if (status == null) {
Expand Down Expand Up @@ -301,6 +331,7 @@ public synchronized void onActivityStarted(final @NotNull Activity activity) {
addBreadcrumb(activity, "started");
}

@SuppressLint("NewApi")
@Override
public synchronized void onActivityResumed(final @NotNull Activity activity) {
if (!firstActivityResumed) {
Expand All @@ -326,6 +357,17 @@ public synchronized void onActivityResumed(final @NotNull Activity activity) {
firstActivityResumed = true;
}

final ISpan ttidSpan = ttidSpanMap.get(activity);
final View rootView = activity.findViewById(android.R.id.content);
if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN
&& rootView != null) {
FirstDrawDoneListener.registerForNextDraw(
rootView, () -> finishSpan(ttidSpan), buildInfoProvider);
} else {
// Posting a task to the main thread's handler will make it executed after it finished
// its current job. That is, right after the activity draws the layout.
mainHandler.post(() -> finishSpan(ttidSpan));
}
addBreadcrumb(activity, "resumed");

// fallback call for API < 29 compatibility, otherwise it happens on onActivityPostResumed
Expand All @@ -344,8 +386,20 @@ public synchronized void onActivityPostResumed(final @NotNull Activity activity)
}
}

@Override
public void onActivityPrePaused(@NonNull Activity activity) {
// only executed if API >= 29 otherwise it happens on onActivityPaused
if (isAllActivityCallbacksAvailable) {
lastPausedTime = DateUtils.getCurrentDateTime();
}
}

@Override
public synchronized void onActivityPaused(final @NotNull Activity activity) {
// only executed if API < 29 otherwise it happens on onActivityPrePaused
if (!isAllActivityCallbacksAvailable) {
lastPausedTime = DateUtils.getCurrentDateTime();
}
addBreadcrumb(activity, "paused");
}

Expand All @@ -366,16 +420,19 @@ public synchronized void onActivityDestroyed(final @NotNull Activity activity) {

// in case the appStartSpan isn't completed yet, we finish it as cancelled to avoid
// memory leak
if (appStartSpan != null && !appStartSpan.isFinished()) {
appStartSpan.finish(SpanStatus.CANCELLED);
}
finishSpan(appStartSpan, SpanStatus.CANCELLED);

// we finish the ttidSpan as cancelled in case it isn't completed yet
final ISpan ttidSpan = ttidSpanMap.get(activity);
finishSpan(ttidSpan, SpanStatus.CANCELLED);

// in case people opt-out enableActivityLifecycleTracingAutoFinish and forgot to finish it,
// we make sure to finish it when the activity gets destroyed.
stopTracing(activity, true);

// set it to null in case its been just finished as cancelled
appStartSpan = null;
ttidSpanMap.remove(activity);

// clear it up, so we don't start again for the same activity if the activity is in the activity
// stack still.
Expand All @@ -385,6 +442,18 @@ public synchronized void onActivityDestroyed(final @NotNull Activity activity) {
}
}

private void finishSpan(@Nullable ISpan span) {
if (span != null && !span.isFinished()) {
span.finish();
}
}

private void finishSpan(@Nullable ISpan span, @NotNull SpanStatus status) {
if (span != null && !span.isFinished()) {
span.finish(status);
}
}

@TestOnly
@NotNull
WeakHashMap<Activity, ITransaction> getActivitiesWithOngoingTransactions() {
Expand All @@ -403,6 +472,12 @@ ISpan getAppStartSpan() {
return appStartSpan;
}

@TestOnly
@NotNull
WeakHashMap<Activity, ISpan> getTtidSpanMap() {
return ttidSpanMap;
}

private void setColdStart(final @Nullable Bundle savedInstanceState) {
if (!firstActivityCreated) {
// if Activity has savedInstanceState then its a warm start
Expand All @@ -411,6 +486,10 @@ private void setColdStart(final @Nullable Bundle savedInstanceState) {
}
}

private @NotNull String getTtidDesc(final @NotNull String activityName) {
return activityName + " initial display";
}

private @NotNull String getAppStartDesc(final boolean coldStart) {
if (coldStart) {
return "Cold Start";
Expand Down
Loading

0 comments on commit 319b527

Please sign in to comment.