Skip to content

Commit

Permalink
Merge 314686f into a4fb390
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanosiano committed Oct 18, 2022
2 parents a4fb390 + 314686f commit c6d0735
Show file tree
Hide file tree
Showing 20 changed files with 243 additions and 275 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -10,8 +10,8 @@

### Features

- Profile envelopes are sent directly from profiler ([#2298](https://github.com/getsentry/sentry-java/pull/2298))
- Add support for using Encoder with logback.SentryAppender ([#2246](https://github.com/getsentry/sentry-java/pull/2246))
- Add captureProfile method to hub and client ([#2290](https://github.com/getsentry/sentry-java/pull/2290))
- Report Startup Crashes ([#2277](https://github.com/getsentry/sentry-java/pull/2277))

## 6.5.0
Expand Down
Expand Up @@ -11,13 +11,16 @@
import android.os.Debug;
import android.os.Process;
import android.os.SystemClock;
import io.sentry.HubAdapter;
import io.sentry.IHub;
import io.sentry.ITransaction;
import io.sentry.ITransactionProfiler;
import io.sentry.ProfilingTraceData;
import io.sentry.ProfilingTransactionData;
import io.sentry.SentryEnvelope;
import io.sentry.SentryLevel;
import io.sentry.android.core.internal.util.CpuInfoUtils;
import io.sentry.util.CollectionUtils;
import io.sentry.exception.SentryEnvelopeException;
import io.sentry.util.Objects;
import java.io.File;
import java.util.ArrayList;
Expand Down Expand Up @@ -48,9 +51,9 @@ final class AndroidTransactionProfiler implements ITransactionProfiler {
private @Nullable File traceFile = null;
private @Nullable File traceFilesDir = null;
private @Nullable Future<?> scheduledFinish = null;
private volatile @Nullable ProfilingTraceData timedOutProfilingData = null;
private final @NotNull Context context;
private final @NotNull SentryAndroidOptions options;
private final @NotNull IHub hub;
private final @NotNull BuildInfoProvider buildInfoProvider;
private final @Nullable PackageInfo packageInfo;
private long transactionStartNanos = 0;
Expand All @@ -63,8 +66,17 @@ public AndroidTransactionProfiler(
final @NotNull Context context,
final @NotNull SentryAndroidOptions sentryAndroidOptions,
final @NotNull BuildInfoProvider buildInfoProvider) {
this(context, sentryAndroidOptions, buildInfoProvider, HubAdapter.getInstance());
}

public AndroidTransactionProfiler(
final @NotNull Context context,
final @NotNull SentryAndroidOptions sentryAndroidOptions,
final @NotNull BuildInfoProvider buildInfoProvider,
final @NotNull IHub hub) {
this.context = Objects.requireNonNull(context, "The application context is required");
this.options = Objects.requireNonNull(sentryAndroidOptions, "SentryAndroidOptions is required");
this.hub = Objects.requireNonNull(hub, "Hub is required");
this.buildInfoProvider =
Objects.requireNonNull(buildInfoProvider, "The BuildInfoProvider is required.");
this.packageInfo = ContextUtils.getPackageInfo(context, options.getLogger(), buildInfoProvider);
Expand Down Expand Up @@ -137,9 +149,7 @@ public synchronized void onTransactionStart(@NotNull ITransaction transaction) {
scheduledFinish =
options
.getExecutorService()
.schedule(
() -> timedOutProfilingData = onTransactionFinish(transaction, true),
PROFILING_TIMEOUT_MILLIS);
.schedule(() -> onTransactionFinish(transaction, true), PROFILING_TIMEOUT_MILLIS);

transactionStartNanos = SystemClock.elapsedRealtimeNanos();
profileStartCpuMillis = Process.getElapsedCpuTime();
Expand All @@ -166,53 +176,28 @@ public synchronized void onTransactionStart(@NotNull ITransaction transaction) {
}

@Override
public synchronized @Nullable ProfilingTraceData onTransactionFinish(
@NotNull ITransaction transaction) {
return onTransactionFinish(transaction, false);
public synchronized void onTransactionFinish(@NotNull ITransaction transaction) {
onTransactionFinish(transaction, false);
}

@SuppressLint("NewApi")
private synchronized @Nullable ProfilingTraceData onTransactionFinish(
private synchronized void onTransactionFinish(
@NotNull ITransaction transaction, boolean isTimeout) {

// onTransactionStart() is only available since Lollipop
// and SystemClock.elapsedRealtimeNanos() since Jelly Bean
if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP) return null;

final ProfilingTraceData profilingData = timedOutProfilingData;
if (buildInfoProvider.getSdkInfoVersion() < Build.VERSION_CODES.LOLLIPOP) return;

// Transaction finished, but it's not in the current profile
// Transaction finished, but it's not in the current profile. We can skip it
if (!transactionMap.containsKey(transaction.getEventId().toString())) {
// We check if we cached a profiling data due to a timeout with this profile in it
// If so, we return it back, otherwise we would simply lose it
if (profilingData != null) {
// Don't use method reference. This can cause issues on Android
List<String> ids =
CollectionUtils.map(profilingData.getTransactions(), (data) -> data.getId());
if (ids.contains(transaction.getEventId().toString())) {
timedOutProfilingData = null;
return profilingData;
} else {
// Another transaction is finishing before the timed out one
options
.getLogger()
.log(
SentryLevel.INFO,
"A timed out profiling data exists, but the finishing transaction %s (%s) is not part of it",
transaction.getName(),
transaction.getSpanContext().getTraceId().toString());
return null;
}
}
// A transaction is finishing, but it's not profiled. We can skip it
options
.getLogger()
.log(
SentryLevel.INFO,
"Transaction %s (%s) finished, but was not currently being profiled. Skipping",
transaction.getName(),
transaction.getSpanContext().getTraceId().toString());
return null;
return;
}

if (transactionsCounter > 0) {
Expand All @@ -239,7 +224,7 @@ public synchronized void onTransactionStart(@NotNull ITransaction transaction) {
Process.getElapsedCpuTime(),
profileStartCpuMillis);
}
return null;
return;
}

Debug.stopMethodTracing();
Expand All @@ -259,7 +244,7 @@ public synchronized void onTransactionStart(@NotNull ITransaction transaction) {

if (traceFile == null) {
options.getLogger().log(SentryLevel.ERROR, "Trace file does not exists");
return null;
return;
}

String versionName = "";
Expand Down Expand Up @@ -287,26 +272,42 @@ public synchronized void onTransactionStart(@NotNull ITransaction transaction) {

// cpu max frequencies are read with a lambda because reading files is involved, so it will be
// done in the background when the trace file is read
return new ProfilingTraceData(
traceFile,
transactionList,
transaction,
Long.toString(transactionDurationNanos),
buildInfoProvider.getSdkInfoVersion(),
abis != null && abis.length > 0 ? abis[0] : "",
() -> CpuInfoUtils.getInstance().readMaxFrequencies(),
buildInfoProvider.getManufacturer(),
buildInfoProvider.getModel(),
buildInfoProvider.getVersionRelease(),
buildInfoProvider.isEmulator(),
totalMem,
options.getProguardUuid(),
versionName,
versionCode,
options.getEnvironment(),
isTimeout
? ProfilingTraceData.TRUNCATION_REASON_TIMEOUT
: ProfilingTraceData.TRUNCATION_REASON_NORMAL);
ProfilingTraceData profilingTraceData =
new ProfilingTraceData(
traceFile,
transactionList,
transaction,
Long.toString(transactionDurationNanos),
buildInfoProvider.getSdkInfoVersion(),
abis != null && abis.length > 0 ? abis[0] : "",
() -> CpuInfoUtils.getInstance().readMaxFrequencies(),
buildInfoProvider.getManufacturer(),
buildInfoProvider.getModel(),
buildInfoProvider.getVersionRelease(),
buildInfoProvider.isEmulator(),
totalMem,
options.getProguardUuid(),
versionName,
versionCode,
options.getEnvironment(),
isTimeout
? ProfilingTraceData.TRUNCATION_REASON_TIMEOUT
: ProfilingTraceData.TRUNCATION_REASON_NORMAL);

SentryEnvelope envelope;
try {
envelope =
SentryEnvelope.from(
options.getSerializer(),
profilingTraceData,
options.getMaxTraceFileSize(),
options.getSdkVersion());
} catch (SentryEnvelopeException e) {
options.getLogger().log(SentryLevel.ERROR, "Failed to capture profile.", e);
return;
}

hub.captureEnvelope(envelope);
}

/**
Expand Down

0 comments on commit c6d0735

Please sign in to comment.