Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR] Add redact options and align naming #3328

Merged
merged 10 commits into from
Apr 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ final class ManifestMetadataReader {

static final String REPLAYS_ERROR_SAMPLE_RATE = "io.sentry.session-replay.error-sample-rate";

static final String REPLAYS_REDACT_ALL_TEXT = "io.sentry.session-replay.redact-all-text";

static final String REPLAYS_REDACT_ALL_IMAGES = "io.sentry.session-replay.redact-all-images";

/** ManifestMetadataReader ctor */
private ManifestMetadataReader() {}

Expand Down Expand Up @@ -376,23 +380,40 @@ static void applyMetadata(
readBool(
metadata, logger, ENABLE_APP_START_PROFILING, options.isEnableAppStartProfiling()));

if (options.getExperimental().getSessionReplayOptions().getSessionSampleRate() == null) {
if (options.getExperimental().getSessionReplay().getSessionSampleRate() == null) {
final Double sessionSampleRate =
readDouble(metadata, logger, REPLAYS_SESSION_SAMPLE_RATE);
if (sessionSampleRate != -1) {
options
.getExperimental()
.getSessionReplayOptions()
.setSessionSampleRate(sessionSampleRate);
options.getExperimental().getSessionReplay().setSessionSampleRate(sessionSampleRate);
}
}

if (options.getExperimental().getSessionReplayOptions().getErrorSampleRate() == null) {
if (options.getExperimental().getSessionReplay().getErrorSampleRate() == null) {
final Double errorSampleRate = readDouble(metadata, logger, REPLAYS_ERROR_SAMPLE_RATE);
if (errorSampleRate != -1) {
options.getExperimental().getSessionReplayOptions().setErrorSampleRate(errorSampleRate);
options.getExperimental().getSessionReplay().setErrorSampleRate(errorSampleRate);
}
}

options
.getExperimental()
.getSessionReplay()
.setRedactAllText(
readBool(
metadata,
logger,
REPLAYS_REDACT_ALL_TEXT,
options.getExperimental().getSessionReplay().getRedactAllText()));

options
.getExperimental()
.getSessionReplay()
.setRedactAllImages(
readBool(
metadata,
logger,
REPLAYS_REDACT_ALL_IMAGES,
options.getExperimental().getSessionReplay().getRedactAllImages()));
}

options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1383,22 +1383,22 @@ class ManifestMetadataReaderTest {
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
assertEquals(expectedSampleRate.toDouble(), fixture.options.experimental.sessionReplayOptions.errorSampleRate)
assertEquals(expectedSampleRate.toDouble(), fixture.options.experimental.sessionReplay.errorSampleRate)
}

@Test
fun `applyMetadata does not override replays errorSampleRate from options`() {
// Arrange
val expectedSampleRate = 0.99f
fixture.options.experimental.sessionReplayOptions.errorSampleRate = expectedSampleRate.toDouble()
fixture.options.experimental.sessionReplay.errorSampleRate = expectedSampleRate.toDouble()
val bundle = bundleOf(ManifestMetadataReader.REPLAYS_ERROR_SAMPLE_RATE to 0.1f)
val context = fixture.getContext(metaData = bundle)

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
assertEquals(expectedSampleRate.toDouble(), fixture.options.experimental.sessionReplayOptions.errorSampleRate)
assertEquals(expectedSampleRate.toDouble(), fixture.options.experimental.sessionReplay.errorSampleRate)
}

@Test
Expand All @@ -1410,6 +1410,33 @@ class ManifestMetadataReaderTest {
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
assertNull(fixture.options.experimental.sessionReplayOptions.errorSampleRate)
assertNull(fixture.options.experimental.sessionReplay.errorSampleRate)
}

@Test
fun `applyMetadata reads session replay redact flags to options`() {
// Arrange
val bundle = bundleOf(ManifestMetadataReader.REPLAYS_REDACT_ALL_TEXT to false, ManifestMetadataReader.REPLAYS_REDACT_ALL_IMAGES to false)
val context = fixture.getContext(metaData = bundle)

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
assertFalse(fixture.options.experimental.sessionReplay.redactAllImages)
assertFalse(fixture.options.experimental.sessionReplay.redactAllText)
}

@Test
fun `applyMetadata reads session replay redact flags to options and keeps default if not found`() {
// Arrange
val context = fixture.getContext()

// Act
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)

// Assert
assertTrue(fixture.options.experimental.sessionReplay.redactAllImages)
assertTrue(fixture.options.experimental.sessionReplay.redactAllText)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ class SentryAndroidTest {
options.release = "prod"
options.dsn = "https://[email protected]/123"
options.isEnableAutoSessionTracking = true
options.experimental.sessionReplayOptions.errorSampleRate = 1.0
options.experimental.sessionReplay.errorSampleRate = 1.0
}

var session: Session? = null
Expand Down
10 changes: 6 additions & 4 deletions sentry-android-replay/api/sentry-android-replay.api
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ public final class io/sentry/android/replay/ReplayCache : java/io/Closeable {
public fun <init> (Lio/sentry/SentryOptions;Lio/sentry/protocol/SentryId;Lio/sentry/android/replay/ScreenshotRecorderConfig;)V
public final fun addFrame (Ljava/io/File;J)V
public fun close ()V
public final fun createVideoOf (JJILjava/io/File;)Lio/sentry/android/replay/GeneratedVideo;
public static synthetic fun createVideoOf$default (Lio/sentry/android/replay/ReplayCache;JJILjava/io/File;ILjava/lang/Object;)Lio/sentry/android/replay/GeneratedVideo;
public final fun createVideoOf (JJIIILjava/io/File;)Lio/sentry/android/replay/GeneratedVideo;
public static synthetic fun createVideoOf$default (Lio/sentry/android/replay/ReplayCache;JJIIILjava/io/File;ILjava/lang/Object;)Lio/sentry/android/replay/GeneratedVideo;
public final fun rotate (J)V
}

public final class io/sentry/android/replay/ReplayIntegration : io/sentry/Integration, io/sentry/ReplayController, io/sentry/android/replay/ScreenshotRecorderCallback, java/io/Closeable {
public final class io/sentry/android/replay/ReplayIntegration : android/content/ComponentCallbacks, io/sentry/Integration, io/sentry/ReplayController, io/sentry/android/replay/ScreenshotRecorderCallback, java/io/Closeable {
public fun <init> (Landroid/content/Context;Lio/sentry/transport/ICurrentDateProvider;)V
public fun close ()V
public fun isRecording ()Z
public fun onConfigurationChanged (Landroid/content/res/Configuration;)V
public fun onLowMemory ()V
public fun onScreenshotRecorded (Landroid/graphics/Bitmap;)V
public fun pause ()V
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
Expand Down Expand Up @@ -118,6 +120,6 @@ public final class io/sentry/android/replay/viewhierarchy/ViewHierarchyNode {
}

public final class io/sentry/android/replay/viewhierarchy/ViewHierarchyNode$Companion {
public final fun fromView (Landroid/view/View;)Lio/sentry/android/replay/viewhierarchy/ViewHierarchyNode;
public final fun fromView (Landroid/view/View;Lio/sentry/SentryOptions;)Lio/sentry/android/replay/viewhierarchy/ViewHierarchyNode;
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,23 @@ public class ReplayCache internal constructor(
private val options: SentryOptions,
private val replayId: SentryId,
private val recorderConfig: ScreenshotRecorderConfig,
private val encoderCreator: (File) -> SimpleVideoEncoder
private val encoderCreator: (videoFile: File, height: Int, width: Int) -> SimpleVideoEncoder
) : Closeable {

public constructor(
options: SentryOptions,
replayId: SentryId,
recorderConfig: ScreenshotRecorderConfig
) : this(options, replayId, recorderConfig, encoderCreator = { videoFile ->
) : this(options, replayId, recorderConfig, encoderCreator = { videoFile, height, width ->
SimpleVideoEncoder(
options,
MuxerConfig(file = videoFile, recorderConfig = recorderConfig)
MuxerConfig(
file = videoFile,
recordingHeight = height,
recordingWidth = width,
frameRate = recorderConfig.frameRate,
bitRate = recorderConfig.bitRate
)
).also { it.start() }
})

Expand Down Expand Up @@ -113,6 +119,10 @@ public class ReplayCache internal constructor(
* @param from desired start of the video represented as unix timestamp in milliseconds
* @param segmentId current segment id, used for inferring the filename to store the
* result video under [replayCacheDir], e.g. "replay_<uuid>/0.mp4", where segmentId=0
* @param height desired height of the video in pixels (e.g. it can change from the initial one
* in case of window resize or orientation change)
* @param width desired width of the video in pixels (e.g. it can change from the initial one
* in case of window resize or orientation change)
* @param videoFile optional, location of the file to store the result video. If this is
* provided, [segmentId] from above is disregarded and not used.
* @return a generated video of type [GeneratedVideo], which contains the resulting video file
Expand All @@ -122,6 +132,8 @@ public class ReplayCache internal constructor(
duration: Long,
from: Long,
segmentId: Int,
height: Int,
width: Int,
videoFile: File = File(replayCacheDir, "$segmentId.mp4")
): GeneratedVideo? {
if (frames.isEmpty()) {
Expand All @@ -133,7 +145,7 @@ public class ReplayCache internal constructor(
}

// TODO: reuse instance of encoder and just change file path to create a different muxer
encoder = synchronized(encoderLock) { encoderCreator(videoFile) }
encoder = synchronized(encoderLock) { encoderCreator(videoFile, height, width) }

val step = 1000 / recorderConfig.frameRate.toLong()
var frameCount = 0
Expand Down
Loading
Loading