Skip to content

Commit

Permalink
Merge pull request #878 from embrace-io/inline-v1-collator
Browse files Browse the repository at this point in the history
Break dependency on v1 collator
  • Loading branch information
fractalwrench authored May 23, 2024
2 parents 6fa0274 + fb256aa commit d290a2b
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,20 @@ internal class SessionModuleImpl(
override val v2PayloadMessageCollator: V2PayloadMessageCollator by singleton {
V2PayloadMessageCollator(
essentialServiceModule.gatingService,
v1PayloadMessageCollator,
payloadModule.sessionEnvelopeSource,
essentialServiceModule.metadataService,
dataContainerModule.eventService,
customerLogModule.logMessageService,
dataContainerModule.performanceInfoService,
nativeModule.nativeThreadSamplerService,
androidServicesModule.preferencesService,
openTelemetryModule.spanRepository,
openTelemetryModule.spanSink,
openTelemetryModule.currentSessionSpan,
sessionPropertiesService,
dataCaptureServiceModule.startupService,
anrModule.anrOtelMapper,
nativeModule.nativeAnrOtelMapper,
initModule.logger
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,66 @@
package io.embrace.android.embracesdk.session.message

import io.embrace.android.embracesdk.anr.AnrOtelMapper
import io.embrace.android.embracesdk.anr.ndk.NativeAnrOtelMapper
import io.embrace.android.embracesdk.anr.ndk.NativeThreadSamplerService
import io.embrace.android.embracesdk.arch.schema.AppTerminationCause
import io.embrace.android.embracesdk.capture.PerformanceInfoService
import io.embrace.android.embracesdk.capture.envelope.session.SessionEnvelopeSource
import io.embrace.android.embracesdk.capture.metadata.MetadataService
import io.embrace.android.embracesdk.capture.startup.StartupService
import io.embrace.android.embracesdk.event.EventService
import io.embrace.android.embracesdk.event.LogMessageService
import io.embrace.android.embracesdk.gating.GatingService
import io.embrace.android.embracesdk.internal.payload.Span
import io.embrace.android.embracesdk.internal.payload.toOldPayload
import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpan
import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData
import io.embrace.android.embracesdk.internal.spans.SpanRepository
import io.embrace.android.embracesdk.internal.spans.SpanSink
import io.embrace.android.embracesdk.logging.EmbLogger
import io.embrace.android.embracesdk.payload.Session
import io.embrace.android.embracesdk.payload.SessionMessage
import io.embrace.android.embracesdk.prefs.PreferencesService
import io.embrace.android.embracesdk.session.captureDataSafely
import io.embrace.android.embracesdk.session.orchestrator.SessionSnapshotType
import io.embrace.android.embracesdk.session.properties.SessionPropertiesService

/**
* Generates a V2 payload. This currently calls through to the V1 collator for
* backwards compatibility.
*/
internal class V2PayloadMessageCollator(
private val gatingService: GatingService,
private val v1Collator: V1PayloadMessageCollator,
private val sessionEnvelopeSource: SessionEnvelopeSource,
private val logger: EmbLogger
private val metadataService: MetadataService,
private val eventService: EventService,
private val logMessageService: LogMessageService,
private val performanceInfoService: PerformanceInfoService,
private val nativeThreadSamplerService: NativeThreadSamplerService?,
private val preferencesService: PreferencesService,
private val spanRepository: SpanRepository,
private val spanSink: SpanSink,
private val currentSessionSpan: CurrentSessionSpan,
private val sessionPropertiesService: SessionPropertiesService,
private val startupService: StartupService,
private val anrOtelMapper: AnrOtelMapper,
private val nativeAnrOtelMapper: NativeAnrOtelMapper,
private val logger: EmbLogger,
) : PayloadMessageCollator {

override fun buildInitialSession(params: InitialEnvelopeParams): Session {
return v1Collator.buildInitialSession(params)
return with(params) {
Session(
sessionId = currentSessionSpan.getSessionId(),
startTime = startTime,
isColdStart = coldStart,
messageType = Session.MESSAGE_TYPE_END,
appState = appState,
startType = startType,
number = getSessionNumber(preferencesService),
properties = getProperties(sessionPropertiesService),
)
}
}

override fun buildFinalSessionMessage(params: FinalEnvelopeParams.SessionParams): SessionMessage {
Expand All @@ -32,8 +73,31 @@ internal class V2PayloadMessageCollator(
captureSpans = false,
logger = logger
)
return v1Collator.buildFinalSessionMessage(newParams)
.convertToV2Payload(newParams.endType)
val obj = with(newParams) {
val base = buildFinalBackgroundActivity(newParams)
val startupInfo = getStartupEventInfo(eventService)

val endSession = base.copy(
isEndedCleanly = endType.endedCleanly,
networkLogIds = captureDataSafely(logger) {
logMessageService.findNetworkLogIds(
initial.startTime,
endTime
)
},
properties = captureDataSafely(logger, sessionPropertiesService::getProperties),
terminationTime = terminationTime,
isReceivedTermination = receivedTermination,
endTime = endTimeVal,
sdkStartupDuration = startupService.getSdkStartupDuration(initial.isColdStart),
startupDuration = startupInfo?.duration,
startupThreshold = startupInfo?.threshold,
symbols = captureDataSafely(logger) { nativeThreadSamplerService?.getNativeSymbols() }
)
val envelope = buildWrapperEnvelope(newParams, endSession, initial.startTime, endTime)
gatingService.gateSessionMessage(envelope)
}
return obj.convertToV2Payload(newParams.endType)
}

override fun buildFinalBackgroundActivityMessage(params: FinalEnvelopeParams.BackgroundActivityParams): SessionMessage {
Expand All @@ -46,8 +110,12 @@ internal class V2PayloadMessageCollator(
captureSpans = false,
logger = logger
)
return v1Collator.buildFinalBackgroundActivityMessage(newParams)
.convertToV2Payload(newParams.endType)
val msg = buildFinalBackgroundActivity(newParams)
val startTime = msg.startTime
val endTime = newParams.endTime
val envelope = buildWrapperEnvelope(newParams, msg, startTime, endTime)
val obj = gatingService.gateSessionMessage(envelope)
return obj.convertToV2Payload(newParams.endType)
}

private fun SessionMessage.convertToV2Payload(endType: SessionSnapshotType): SessionMessage {
Expand All @@ -61,12 +129,74 @@ internal class V2PayloadMessageCollator(
type = envelope.type,

// make legacy fields null
userInfo = null,
version = null,
spans = null,
)
}

/**
* Creates a background activity stop message.
*/
private fun buildFinalBackgroundActivity(
params: FinalEnvelopeParams
): Session = with(params) {
return initial.copy(
endTime = endTime,
eventIds = captureDataSafely(logger) {
eventService.findEventIdsForSession()
},
lastHeartbeatTime = endTime,
endType = lifeEventType,
crashReportId = crashId
)
}

private fun buildWrapperEnvelope(
params: FinalEnvelopeParams,
finalPayload: Session,
startTime: Long,
endTime: Long,
): SessionMessage {
val spans: List<EmbraceSpanData>? = captureDataSafely(logger) {
val result = when {
!params.captureSpans -> null
!params.isCacheAttempt -> {
val appTerminationCause = when {
finalPayload.crashReportId != null -> AppTerminationCause.Crash
else -> null
}
val spans = currentSessionSpan.endSession(appTerminationCause)
if (appTerminationCause == null) {
sessionPropertiesService.populateCurrentSession()
}
spans
}

else -> spanSink.completedSpans()
}
// add ANR spans if the payload is capturing spans.
result?.plus(anrOtelMapper.snapshot(!params.isCacheAttempt).map(Span::toOldPayload))
?.plus(nativeAnrOtelMapper.snapshot(!params.isCacheAttempt).map(Span::toOldPayload))
?: result
}
val spanSnapshots = captureDataSafely(logger) {
spanRepository.getActiveSpans().mapNotNull { it.snapshot()?.toOldPayload() }
}

// future: make appInfo, deviceInfo, performanceInfo, breadcrumbs null.
// this is blocked until we can migrate others
return SessionMessage(
session = finalPayload,
appInfo = captureDataSafely(logger, metadataService::getAppInfo),
deviceInfo = captureDataSafely(logger, metadataService::getDeviceInfo),
performanceInfo = captureDataSafely(logger) {
performanceInfoService.getSessionPerformanceInfo(
startTime,
endTime,
finalPayload.isColdStart,
null
)
},
spans = spans,
spanSnapshots = spanSnapshots,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,24 @@ internal class PayloadFactoryBaTest {
resourceSource = FakeEnvelopeResourceSource(),
sessionPayloadSource = FakeSessionPayloadSource()
)
val v2Collator = V2PayloadMessageCollator(gatingService, collator, sessionEnvelopeSource, logger)
val v2Collator = V2PayloadMessageCollator(
gatingService,
sessionEnvelopeSource,
metadataService,
eventService,
logMessageService,
performanceInfoService,
null,
preferencesService,
spanRepository,
spanSink,
currentSessionSpan,
FakeSessionPropertiesService(),
FakeStartupService(),
AnrOtelMapper(FakeAnrService()),
NativeAnrOtelMapper(null, EmbraceSerializer()),
logger
)
return PayloadFactoryImpl(collator, v2Collator, configService, logger).apply {
if (createInitialSession) {
startPayloadWithState(ProcessState.BACKGROUND, clock.now(), true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,43 @@
package io.embrace.android.embracesdk.session

import io.embrace.android.embracesdk.FakeDeliveryService
import io.embrace.android.embracesdk.FakeNdkService
import io.embrace.android.embracesdk.FakeSessionPropertiesService
import io.embrace.android.embracesdk.anr.AnrOtelMapper
import io.embrace.android.embracesdk.anr.ndk.NativeAnrOtelMapper
import io.embrace.android.embracesdk.capture.envelope.session.SessionEnvelopeSourceImpl
import io.embrace.android.embracesdk.capture.metadata.MetadataService
import io.embrace.android.embracesdk.capture.user.UserService
import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService
import io.embrace.android.embracesdk.config.LocalConfigParser
import io.embrace.android.embracesdk.config.local.LocalConfig
import io.embrace.android.embracesdk.event.EventService
import io.embrace.android.embracesdk.event.LogMessageService
import io.embrace.android.embracesdk.fakes.FakeAnrService
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeEnvelopeMetadataSource
import io.embrace.android.embracesdk.fakes.FakeEnvelopeResourceSource
import io.embrace.android.embracesdk.fakes.FakeEventService
import io.embrace.android.embracesdk.fakes.FakeGatingService
import io.embrace.android.embracesdk.fakes.FakeInternalErrorService
import io.embrace.android.embracesdk.fakes.FakeLogMessageService
import io.embrace.android.embracesdk.fakes.FakeMetadataService
import io.embrace.android.embracesdk.fakes.FakePerformanceInfoService
import io.embrace.android.embracesdk.fakes.FakePreferenceService
import io.embrace.android.embracesdk.fakes.FakeProcessStateService
import io.embrace.android.embracesdk.fakes.FakeSessionIdTracker
import io.embrace.android.embracesdk.fakes.FakeSessionPayloadSource
import io.embrace.android.embracesdk.fakes.FakeStartupService
import io.embrace.android.embracesdk.fakes.FakeUserService
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer
import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpan
import io.embrace.android.embracesdk.internal.spans.SpanRepository
import io.embrace.android.embracesdk.internal.spans.SpanService
import io.embrace.android.embracesdk.internal.spans.SpanSink
import io.embrace.android.embracesdk.logging.EmbLoggerImpl
import io.embrace.android.embracesdk.logging.InternalErrorService
import io.embrace.android.embracesdk.session.lifecycle.ProcessState
import io.embrace.android.embracesdk.session.message.PayloadFactory
import io.embrace.android.embracesdk.session.message.PayloadFactoryImpl
Expand All @@ -36,6 +62,22 @@ internal class PayloadFactorySessionTest {
private lateinit var service: PayloadFactory
private lateinit var deliveryService: FakeDeliveryService
private lateinit var configService: FakeConfigService
private lateinit var clock: FakeClock
private lateinit var performanceInfoService: FakePerformanceInfoService
private lateinit var metadataService: MetadataService
private lateinit var sessionIdTracker: FakeSessionIdTracker
private lateinit var activityService: FakeProcessStateService
private lateinit var eventService: EventService
private lateinit var logMessageService: LogMessageService
private lateinit var userService: UserService
private lateinit var internalErrorService: InternalErrorService
private lateinit var ndkService: FakeNdkService
private lateinit var localConfig: LocalConfig
private lateinit var spanRepository: SpanRepository
private lateinit var currentSessionSpan: CurrentSessionSpan
private lateinit var spanService: SpanService
private lateinit var preferencesService: FakePreferenceService
private lateinit var blockingExecutorService: BlockingScheduledExecutorService

companion object {

Expand All @@ -59,7 +101,33 @@ internal class PayloadFactorySessionTest {
fun before() {
deliveryService = FakeDeliveryService()
configService = FakeConfigService()
clock = FakeClock(10000L)
spanSink = FakeInitModule(clock = clock).openTelemetryModule.spanSink

performanceInfoService = FakePerformanceInfoService()
metadataService = FakeMetadataService()
sessionIdTracker = FakeSessionIdTracker()
activityService = FakeProcessStateService(isInBackground = true)
eventService = FakeEventService()
logMessageService = FakeLogMessageService()
internalErrorService = FakeInternalErrorService()
ndkService = FakeNdkService()
preferencesService = FakePreferenceService(backgroundActivityEnabled = true)
userService = FakeUserService()
val initModule = FakeInitModule(clock = clock)
spanRepository = initModule.openTelemetryModule.spanRepository
currentSessionSpan = initModule.openTelemetryModule.currentSessionSpan
spanService = initModule.openTelemetryModule.spanService
configService.updateListeners()
localConfig = LocalConfigParser.buildConfig(
"GrCPU",
false,
"{\"background_activity\": {\"max_background_activity_seconds\": 3600}}",
EmbraceSerializer(),
EmbLoggerImpl()
)

blockingExecutorService = BlockingScheduledExecutorService(blockingMode = false)
}

@After
Expand Down Expand Up @@ -100,7 +168,25 @@ internal class PayloadFactorySessionTest {
)
val logger = EmbLoggerImpl()
val v1Collator = mockk<V1PayloadMessageCollator>(relaxed = true)
val v2Collator = V2PayloadMessageCollator(FakeGatingService(), v1Collator, sessionEnvelopeSource, logger)
val gatingService = FakeGatingService()
val v2Collator = V2PayloadMessageCollator(
gatingService,
sessionEnvelopeSource,
metadataService,
eventService,
logMessageService,
performanceInfoService,
null,
preferencesService,
spanRepository,
spanSink,
currentSessionSpan,
FakeSessionPropertiesService(),
FakeStartupService(),
AnrOtelMapper(FakeAnrService()),
NativeAnrOtelMapper(null, EmbraceSerializer()),
logger
)
service = PayloadFactoryImpl(v1Collator, v2Collator, FakeConfigService(), logger)
}
}
Loading

0 comments on commit d290a2b

Please sign in to comment.