Skip to content

Commit 31badab

Browse files
committed
adding stories for todos
1 parent b16b617 commit 31badab

File tree

9 files changed

+41
-38
lines changed

9 files changed

+41
-38
lines changed

sdk/@launchdarkly/observability-android/lib/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dependencies {
5252
// Android crash instrumentation
5353
implementation("io.opentelemetry.android.instrumentation:crash:0.11.0-alpha")
5454

55-
// TODO: move replay instrumentation and associated compose dependencies into dedicated package
55+
// TODO: O11Y-626 - move replay instrumentation and associated compose dependencies into dedicated package
5656
// Compose dependencies for capture functionality
5757
implementation("androidx.compose.ui:ui:1.7.5")
5858
implementation("androidx.compose.ui:ui-tooling:1.7.5")

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/client/InstrumentationManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class InstrumentationManager(
108108

109109
val builder = OpenTelemetryRum.builder(application, otelRumConfig)
110110
.addLoggerProviderCustomizer { sdkLoggerProviderBuilder, _ ->
111-
// TODO: need to refactor this so that the disableLogs option is specific to core logging functionality. when logs are disabled, session replay logs should not be blocked
111+
// TODO: O11Y-627 - need to refactor this so that the disableLogs option is specific to core logging functionality. when logs are disabled, session replay logs should not be blocked
112112
return@addLoggerProviderCustomizer if (options.disableLogs && options.disableErrorTracking) {
113113
sdkLoggerProviderBuilder
114114
} else {

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/CaptureSource.kt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import androidx.compose.ui.geometry.Rect as ComposeRect
4343
class CaptureSource(
4444
private val sessionManager: SessionManager,
4545
private val privacyProfile: PrivacyProfile,
46-
// TODO: add captureQuality options
46+
// TODO: O11Y-628 - add captureQuality options
4747
) :
4848
Application.ActivityLifecycleCallbacks {
4949

@@ -70,7 +70,7 @@ class CaptureSource(
7070
* Requests a [Capture] be taken now.
7171
*/
7272
fun captureNow() {
73-
// TODO: don't use global scope
73+
// TODO: O11Y-621 - don't use global scope
7474
CoroutineScope(Dispatchers.Default).launch {
7575
val capture = doCapture()
7676
if (capture != null) {
@@ -121,16 +121,16 @@ class CaptureSource(
121121

122122
val rect = Rect(0, 0, decorViewWidth, decorViewHeight)
123123

124-
// TODO: optimize memory allocations
125-
// TODO: see if holding bitmap is more efficient than base64 encoding immediately after compression
126-
// TODO: use captureQuality option for scaling and adjust this bitmap accordingly, may need to investigate power of 2 rounding for performance
124+
// TODO: O11Y-625 - optimize memory allocations
125+
// TODO: O11Y-625 - see if holding bitmap is more efficient than base64 encoding immediately after compression
126+
// TODO: O11Y-628 - use captureQuality option for scaling and adjust this bitmap accordingly, may need to investigate power of 2 rounding for performance
127127
// Create a bitmap with the window dimensions
128128
val bitmap = Bitmap.createBitmap(decorViewWidth, decorViewHeight, Bitmap.Config.ARGB_8888)
129129

130130
// Use PixelCopy to capture the window content
131131
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
132132
suspendCancellableCoroutine { continuation ->
133-
// TODO: read PixelCopy exception recommendations and adjust logic to account for such cases
133+
// TODO: O11Y-624 - read PixelCopy exception recommendations and adjust logic to account for such cases
134134
PixelCopy.request(
135135
window,
136136
rect,
@@ -148,9 +148,9 @@ class CaptureSource(
148148
postMask = bitmap
149149
}
150150

151-
// TODO: optimize memory allocations here, re-use byte arrays and such
151+
// TODO: O11Y-625 - optimize memory allocations here, re-use byte arrays and such
152152
val outputStream = ByteArrayOutputStream()
153-
// TODO: calculate quality using captureQuality options
153+
// TODO: O11Y-628 - calculate quality using captureQuality options
154154
postMask.compress(Bitmap.CompressFormat.WEBP, 30, outputStream)
155155
val byteArray = outputStream.toByteArray()
156156
val compressedImage = Base64.encodeToString(byteArray, Base64.NO_WRAP)
@@ -164,19 +164,19 @@ class CaptureSource(
164164
)
165165
continuation.resume(capture)
166166
} else {
167-
// TODO: implement handling/shutdown for errors and unsupported API levels
167+
// TODO: O11Y-624 - implement handling/shutdown for errors and unsupported API levels
168168
continuation.resumeWithException(Exception("PixelCopy failed with result: $result"))
169169
}
170170
},
171171
Handler(Looper.getMainLooper()) // Handler for main thread
172172
)
173173
}
174174
} else {
175-
// TODO: implement handling/shutdown for errors and unsupported API levels
175+
// TODO: O11Y-624 - implement handling/shutdown for errors and unsupported API levels
176176
throw NotImplementedError("CaptureSource does not work on unsupported Android SDK version")
177177
}
178178
} catch (e: Exception) {
179-
// TODO: implement handling/shutdown for errors and unsupported API levels
179+
// TODO: O11Y-624 - implement handling/shutdown for errors and unsupported API levels
180180
throw RuntimeException(e);
181181
}
182182
}
@@ -189,7 +189,7 @@ class CaptureSource(
189189
* @param activity The activity that the bitmap was captured from.
190190
*/
191191
private fun maskSensitiveAreas(bitmap: Bitmap, activity: Activity): Bitmap {
192-
// TODO: remove this bitmap copy if possible for memory optimization purposes
192+
// TODO: O11Y-625 - remove this bitmap copy if possible for memory optimization purposes
193193
val maskedBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
194194
val canvas = Canvas(maskedBitmap)
195195
val paint = Paint().apply {
@@ -274,7 +274,7 @@ class CaptureSource(
274274
if (composeView.childCount > 0) {
275275
val androidComposeView = composeView.getChildAt(0)
276276

277-
// TODO: determine if there is a more robust long term way to achieve this, this reflection is fragile.
277+
// TODO: O11Y-620 - determine if there is a more robust long term way to achieve this, this reflection is fragile.
278278
// Use reflection to check if this is an AndroidComposeView
279279
val androidComposeViewClass =
280280
Class.forName("androidx.compose.ui.platform.AndroidComposeView")
@@ -342,7 +342,7 @@ class CaptureSource(
342342
* Check if a semantic node contains sensitive content based on test tags or content descriptions.
343343
*/
344344
private fun isSensitiveNode(node: SemanticsNode): Boolean {
345-
// TODO: refactor to utilize generic MaskMatchers
345+
// TODO: O11Y-620 - refactor to utilize generic MaskMatchers
346346

347347
// Check for content description containing "sensitive"
348348
val contentDescriptions = node.config.getOrNull(SemanticsProperties.ContentDescription)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.launchdarkly.observability.replay
22

3-
// TODO: implement full PrivacyProfiles and MaskingMatchers
3+
// TODO: O11Y-620 - implement full PrivacyProfiles and MaskingMatchers
44
enum class PrivacyProfile {
55
NO_MASK, STRICT
66
}

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/RRwebGraphQLReplayLogExporter.kt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class RRwebGraphQLReplayLogExporter(
3131
private var graphqlClient: GraphQLClient = GraphQLClient(backendUrl)
3232
private var replayApiService: SessionReplayApiService = SessionReplayApiService(graphqlClient)
3333

34-
// TODO: need to implement sid, payloadId reset when multiple sessions occur in one application process lifecycle.
34+
// TODO: O11Y-624 - need to implement sid, payloadId reset when multiple sessions occur in one application process lifecycle.
3535
private var sidCounter = 0
3636
private var payloadIdCounter = 0
3737
private var lastSentHeight = 0
@@ -48,7 +48,7 @@ class RRwebGraphQLReplayLogExporter(
4848
for (log in logs) {
4949
val capture = extractCaptureFromLog(log)
5050
if (capture != null) {
51-
// TODO: investigate if there is a size limit on the push that is imposed server side.
51+
// TODO: O11Y-624 - investigate if there is a size limit on the push that is imposed server side.
5252
val success = if (!capture.session.equals(lastSessionId)) {
5353
sendCaptureInitial(capture)
5454
} else {
@@ -66,7 +66,7 @@ class RRwebGraphQLReplayLogExporter(
6666
resultCode.fail()
6767
}
6868
} catch (e: Exception) {
69-
// TODO: pass in logger to implementation and use here
69+
// TODO: O11Y-627 - pass in logger to implementation and use here
7070
Log.e("RRwebGraphQLReplayLogExporter", "Error during export: ${e.message}", e)
7171
resultCode.fail()
7272
}
@@ -76,10 +76,12 @@ class RRwebGraphQLReplayLogExporter(
7676
}
7777

7878
override fun flush(): CompletableResultCode {
79+
// TODO: O11Y-621 - Handle flush
7980
TODO("Not yet implemented")
8081
}
8182

8283
override fun shutdown(): CompletableResultCode {
84+
// TODO: O11Y-621 - Handle shutdown
8385
TODO("Not yet implemented")
8486
}
8587

@@ -126,7 +128,7 @@ class RRwebGraphQLReplayLogExporter(
126128
val eventsBatch1 = mutableListOf<Event>()
127129
val timestamp = System.currentTimeMillis()
128130

129-
// TODO: optimize JSON usage for performance since this region of code is essentially static
131+
// TODO: O11Y-625 - optimize JSON usage for performance since this region of code is essentially static
130132
val incrementalEvent = Event(
131133
type = EventType.INCREMENTAL_SNAPSHOT,
132134
timestamp = timestamp,
@@ -139,7 +141,7 @@ class RRwebGraphQLReplayLogExporter(
139141

140142
// TODO: add ViewPort event if resolution changes
141143

142-
// TODO: remove this spoofed mouse interaction when proper user interaction is instrumented
144+
// TODO: O11Y-629 - remove this spoofed mouse interaction when proper user interaction is instrumented
143145
// This spoofed mouse interaction is necessary to make the session look like it had activity
144146
eventsBatch1.add(
145147
Event(
@@ -155,7 +157,7 @@ class RRwebGraphQLReplayLogExporter(
155157
replayApiService.pushPayload(capture.session, "${nextPayloadId()}", eventsBatch1)
156158
true
157159
} catch (e: Exception) {
158-
// TODO: pass in logger to implementation and use here
160+
// TODO: O11Y-627 - pass in logger to implementation and use here
159161
Log.e(REPLAY_EXPORTER_NAME, "Error sending incremental capture for session: ${e.message}", e)
160162
false
161163
}
@@ -173,7 +175,7 @@ class RRwebGraphQLReplayLogExporter(
173175

174176
val eventBatch = mutableListOf<Event>()
175177

176-
// TODO: optimize JSON usage for performance since this region of code is essentially static
178+
// TODO: O11Y-625 - optimize JSON usage for performance since this region of code is essentially static
177179

178180
val timestamp = System.currentTimeMillis()
179181
val metaEvent = Event(
@@ -254,7 +256,7 @@ class RRwebGraphQLReplayLogExporter(
254256
)
255257
eventBatch.add(viewportEvent)
256258

257-
// TODO: double check error case handling, may need to add retries per api service request, should subsequent requests wait for previous requests to succeed?
259+
// TODO: O11Y-624 - double check error case handling, may need to add retries per api service request, should subsequent requests wait for previous requests to succeed?
258260
lastSessionId = capture.session
259261
lastSentWidth = capture.origWidth
260262
lastSentHeight = capture.origHeight
@@ -263,7 +265,7 @@ class RRwebGraphQLReplayLogExporter(
263265

264266
true
265267
} catch (e: Exception) {
266-
// TODO: pass in logger to implementation and use here
268+
// TODO: O11Y-627 - pass in logger to implementation and use here
267269
Log.e(REPLAY_EXPORTER_NAME, "Error sending initial capture for session: ${e.message}", e)
268270
false
269271
}

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/ReplayInstrumentation.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicBoolean
1818

1919
private const val INSTRUMENTATION_SCOPE_NAME = "com.launchdarkly.observability.replay"
2020

21-
// TODO: determine where these should be defined ultimately and tune accordingly. Perhaps
21+
// TODO: O11Y-625 - determine where these should be defined ultimately and tune accordingly. Perhaps
2222
// we don't need a batching exporter in this layer. Perhaps this layer shouldn't be the one
2323
// that decides the parameters of the batching exporter. Perhaps the batching should be
2424
// controlled by the instrumentation manager.
@@ -82,8 +82,8 @@ class ReplayInstrumentation(
8282
_captureSource = CaptureSource(ctx.sessionManager, options.privacyProfile)
8383
_captureSource.attachToApplication(ctx.application)
8484

85-
// TODO: don't use global scope
86-
// TODO: shutdown procedure and cleanup of dispatched jobs
85+
// TODO: O11Y-621 - don't use global scope
86+
// TODO: O11Y-621 - shutdown procedure and cleanup of dispatched jobs
8787
GlobalScope.launch(Dispatchers.Default) {
8888
_captureSource.captureFlow.collect { capture ->
8989
_otelLogger.logRecordBuilder()
@@ -101,7 +101,7 @@ class ReplayInstrumentation(
101101
internalStartCapture()
102102
}
103103

104-
// TODO: implement mechanism for customer code to invoke this method
104+
// TODO: O11Y-622 - implement mechanism for customer code to invoke this method
105105
suspend fun runCapture() {
106106
_captureMutex.withLock {
107107
// If already running (not paused), do nothing
@@ -115,7 +115,7 @@ class ReplayInstrumentation(
115115
}
116116
}
117117

118-
// TODO: implement mechanism for customer code to invoke this method
118+
// TODO: O11Y-622 - implement mechanism for customer code to invoke this method
119119
suspend fun pauseCapture() {
120120
_captureMutex.withLock {
121121
// if already paused, do nothing
@@ -131,7 +131,7 @@ class ReplayInstrumentation(
131131
}
132132

133133
private fun internalStartCapture() {
134-
// TODO: don't use global scope
134+
// TODO: O11Y-621 - don't use global scope
135135
_captureJob = GlobalScope.launch(Dispatchers.Default) {
136136
try {
137137
while (true) {

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/ReplayOptions.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ data class ReplayOptions(
1515
val debug: Boolean = false,
1616
val privacyProfile: PrivacyProfile = PrivacyProfile.STRICT,
1717
val capturePeriodMillis: Long = 1000, // defaults to ever 1 second
18+
// TODO O11Y-623 - Add storage options
1819
)

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/ReplaySessionProtocol.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ object EventTypeSerializer : KSerializer<EventType> {
6666
override fun deserialize(decoder: Decoder): EventType {
6767
val intValue = decoder.decodeInt()
6868

69-
// TODO: determine better error handling
69+
// TODO: O11Y-624 - determine better error handling
7070
return EventType.values().find { it.value == intValue }
7171
?: throw IllegalArgumentException("Unknown EventType value: $intValue")
7272
}
@@ -91,7 +91,7 @@ object NodeTypeSerializer : KSerializer<NodeType> {
9191

9292
override fun deserialize(decoder: Decoder): NodeType {
9393
val intValue = decoder.decodeInt()
94-
// TODO: determine better error handling
94+
// TODO: O11Y-624 - determine better error handling
9595
return NodeType.values().find { it.value == intValue }
9696
?: throw IllegalArgumentException("Unknown NodeType value: $intValue")
9797
}
@@ -127,7 +127,7 @@ object IncrementalSourceSerializer : KSerializer<IncrementalSource> {
127127

128128
override fun deserialize(decoder: Decoder): IncrementalSource {
129129
val intValue = decoder.decodeInt()
130-
// TODO: determine better error handling
130+
// TODO: O11Y-624 - determine better error handling
131131
return IncrementalSource.values().find { it.value == intValue }
132132
?: throw IllegalArgumentException("Unknown IncrementalSource value: $intValue")
133133
}
@@ -157,7 +157,7 @@ object MouseInteractionsSerializer : KSerializer<MouseInteractions> {
157157

158158
override fun deserialize(decoder: Decoder): MouseInteractions {
159159
val intValue = decoder.decodeInt()
160-
// TODO: determine better error handling
160+
// TODO: O11Y-624 - determine better error handling
161161
return MouseInteractions.values().find { it.value == intValue }
162162
?: throw IllegalArgumentException("Unknown MouseInteractions value: $intValue")
163163
}

sdk/@launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/SessionReplayApiService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import kotlinx.serialization.json.JsonElement
88
import kotlinx.serialization.json.JsonNull
99
import kotlinx.serialization.json.JsonPrimitive
1010

11-
// TODO: Refactor logging handling in this class
11+
// TODO: O11Y-627 - Refactor logging handling in this class
1212
class SessionReplayApiService(
1313
private val graphqlClient: GraphQLClient
1414
) {
@@ -54,7 +54,7 @@ class SessionReplayApiService(
5454
dataSerializer = InitializeReplaySessionResponse.serializer()
5555
)
5656

57-
// TODO: check graphql requests can generate errors when necessary and add error handling
57+
// TODO: O11Y-624 - check graphql requests can generate errors when necessary and add error handling
5858
if (response.errors?.isNotEmpty() == true) {
5959
printErrors(response)
6060
}

0 commit comments

Comments
 (0)