diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt index 58aa76e73..aaabf0990 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DeliveryModuleImpl.kt @@ -187,7 +187,8 @@ internal class DeliveryModuleImpl( workerThreadModule.backgroundWorker(Worker.Background.IoRegWorker), workerThreadModule.backgroundWorker(Worker.Background.HttpRequestWorker), initModule.clock, - initModule.logger + initModule.logger, + deliveryTracer ) } } diff --git a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTraceState.kt b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTraceState.kt index 5fd658b21..c221c1f33 100644 --- a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTraceState.kt +++ b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTraceState.kt @@ -50,14 +50,16 @@ internal sealed class DeliveryTraceState { * The payload store returned a list of payloads by priority */ internal class GetPayloadsByPriority(val payloads: List) : DeliveryTraceState() { - override fun toString(): String = "GetPayloadsByPriority, count=${payloads.size},\n${payloads.reportListString()}" + override fun toString(): String = + "GetPayloadsByPriority, count=${payloads.size},\n${payloads.reportListString()}" } /** * The payload store returned a list of undelivered payloads */ internal class GetUndeliveredPayloads(val payloads: List) : DeliveryTraceState() { - override fun toString(): String = "GetUndeliveredPayloads, count=${payloads.size},\n${payloads.reportListString()}" + override fun toString(): String = + "GetUndeliveredPayloads, count=${payloads.size},\n${payloads.reportListString()}" } /** @@ -92,6 +94,43 @@ internal sealed class DeliveryTraceState { override fun toString(): String = "SessionCacheAttempt" } + /** + * The delivery loop was started + */ + internal class StartDeliveryLoop(private val loopAlreadyActive: Boolean) : DeliveryTraceState() { + override fun toString(): String = "StartDeliveryLoop loopAlreadyActive=$loopAlreadyActive" + } + + /** + * A payload was enqueued for delivery + */ + class PayloadEnqueued(private val payload: StoredTelemetryMetadata) : DeliveryTraceState() { + override fun toString(): String = "PayloadEnqueued, ${payload.toReportString()}" + } + + /** + * A payload result was obtained + */ + class PayloadResult( + private val payload: StoredTelemetryMetadata, + private val result: ExecutionResult, + ) : DeliveryTraceState() { + override fun toString(): String = "PayloadResult, ${payload.toReportString()}, result=${result.javaClass.simpleName}" + } + + /** + * A payload queue was created + */ + class PayloadQueueCreated( + private val payloadsByPriority: List, + private val payloadsToSend: List, + ) : DeliveryTraceState() { + override fun toString(): String { + return "PayloadQueueCreated, payloadsByPriority=${payloadsByPriority.map { it.uuid }}, " + + "payloadsToSend=${payloadsToSend.map { it.uuid }}" + } + } + internal fun StoredTelemetryMetadata.toReportString(): String { return "$timestamp, $uuid, $payloadType, complete=$complete" } diff --git a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTracer.kt b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTracer.kt index 6d4f0e09a..c6412abc2 100644 --- a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTracer.kt +++ b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/debug/DeliveryTracer.kt @@ -59,4 +59,23 @@ class DeliveryTracer { "#$k, $state" }.joinToString("\n") } + + fun onStartDeliveryLoop(sendLoopActive: Boolean) { + events.add(DeliveryTraceState.StartDeliveryLoop(sendLoopActive)) + } + + fun onPayloadQueueCreated( + payloadsByPriority: List, + payloadsToSend: List, + ) { + events.add(DeliveryTraceState.PayloadQueueCreated(payloadsByPriority, payloadsToSend)) + } + + fun onPayloadEnqueued(payload: StoredTelemetryMetadata) { + events.add(DeliveryTraceState.PayloadEnqueued(payload)) + } + + fun onPayloadResult(payload: StoredTelemetryMetadata, result: ExecutionResult) { + events.add(DeliveryTraceState.PayloadResult(payload, result)) + } } diff --git a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/intake/IntakeServiceImpl.kt b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/intake/IntakeServiceImpl.kt index 64887a6a8..75cf8cb78 100644 --- a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/intake/IntakeServiceImpl.kt +++ b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/intake/IntakeServiceImpl.kt @@ -60,8 +60,8 @@ class IntakeServiceImpl( val lastReference = cacheReferences[metadata.envelopeType] if (metadata.complete) { - schedulingService.onPayloadIntake() deliveryTracer?.onPayloadIntake(metadata) + schedulingService.onPayloadIntake() } else { cacheReferences[metadata.envelopeType] = metadata if (!cacheableEnvelopeTypes.contains(metadata.envelopeType)) { diff --git a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/scheduling/SchedulingServiceImpl.kt b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/scheduling/SchedulingServiceImpl.kt index 913a1f819..d66eaa71d 100644 --- a/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/scheduling/SchedulingServiceImpl.kt +++ b/embrace-android-delivery/src/main/kotlin/io/embrace/android/embracesdk/internal/delivery/scheduling/SchedulingServiceImpl.kt @@ -4,6 +4,7 @@ import io.embrace.android.embracesdk.internal.clock.Clock import io.embrace.android.embracesdk.internal.comms.api.Endpoint import io.embrace.android.embracesdk.internal.comms.delivery.NetworkStatus import io.embrace.android.embracesdk.internal.delivery.StoredTelemetryMetadata +import io.embrace.android.embracesdk.internal.delivery.debug.DeliveryTracer import io.embrace.android.embracesdk.internal.delivery.execution.ExecutionResult import io.embrace.android.embracesdk.internal.delivery.execution.RequestExecutionService import io.embrace.android.embracesdk.internal.delivery.storage.PayloadStorageService @@ -25,7 +26,8 @@ class SchedulingServiceImpl( private val schedulingWorker: BackgroundWorker, private val deliveryWorker: BackgroundWorker, private val clock: Clock, - private val logger: EmbLogger + private val logger: EmbLogger, + private val deliveryTracer: DeliveryTracer? = null, ) : SchedulingService { private val blockedEndpoints: MutableMap = ConcurrentHashMap() @@ -65,9 +67,12 @@ class SchedulingServiceImpl( // When a payload arrives, check to see if there's already an active job try to deliver payloads // If not, schedule job. If so, do nothing. if (sendLoopActive.compareAndSet(false, true)) { + deliveryTracer?.onStartDeliveryLoop(true) schedulingWorker.submit { deliveryLoop() } + } else { + deliveryTracer?.onStartDeliveryLoop(false) } } @@ -120,13 +125,20 @@ class SchedulingServiceImpl( } } - private fun createPayloadQueue(exclude: Set = emptySet()) = LinkedList( - storageService.getPayloadsByPriority() + private fun createPayloadQueue(exclude: Set = emptySet()): LinkedList { + val payloadsByPriority = storageService.getPayloadsByPriority() + val payloadsToSend = payloadsByPriority .filter { it.shouldSendPayload() && !exclude.contains(it) } .sortedWith(storedTelemetryComparator) - ) + deliveryTracer?.onPayloadQueueCreated( + payloadsByPriority, + payloadsToSend, + ) + return LinkedList(payloadsToSend) + } private fun queueDelivery(payload: StoredTelemetryMetadata): Future { + deliveryTracer?.onPayloadEnqueued(payload) activeSends.add(payload) return deliveryWorker.submit { val result: ExecutionResult = @@ -149,6 +161,8 @@ class SchedulingServiceImpl( ExecutionResult.Incomplete(exception = t, retry = false) } + deliveryTracer?.onPayloadResult(payload, result) + with(result) { if (!shouldRetry) { // If the response is such that we should not ever retry the delivery of this payload,