Skip to content

Commit

Permalink
RUMM-2608: Use event write context for traces
Browse files Browse the repository at this point in the history
  • Loading branch information
0xnm committed Oct 27, 2022
1 parent 67cc7c3 commit 9720e9c
Show file tree
Hide file tree
Showing 18 changed files with 402 additions and 306 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
package com.datadog.android.tracing

import com.datadog.android.Datadog
import com.datadog.android.core.internal.persistence.NoOpDataWriter
import com.datadog.android.core.internal.utils.devLogger
import com.datadog.android.log.LogAttributes
import com.datadog.android.log.Logger
import com.datadog.android.rum.GlobalRum
import com.datadog.android.tracing.internal.data.TraceWriter
import com.datadog.android.tracing.internal.data.NoOpWriter
import com.datadog.android.tracing.internal.handlers.AndroidSpanLogsHandler
import com.datadog.android.v2.core.DatadogCore
import com.datadog.opentracing.DDTracer
import com.datadog.opentracing.LogHandler
import com.datadog.trace.api.Config
import com.datadog.trace.common.writer.Writer
import io.opentracing.Span
import io.opentracing.log.Fields
import java.security.SecureRandom
Expand All @@ -34,7 +34,7 @@ import java.util.Random
*/
class AndroidTracer internal constructor(
config: Config,
writer: TraceWriter,
writer: Writer,
random: Random,
private val logsHandler: LogHandler,
private val bundleWithRum: Boolean
Expand Down Expand Up @@ -95,10 +95,9 @@ class AndroidTracer internal constructor(
devLogger.e(RUM_NOT_ENABLED_ERROR_MESSAGE)
bundleWithRumEnabled = false
}
val writer = tracingFeature?.persistenceStrategy?.getWriter() ?: NoOpDataWriter()
return AndroidTracer(
config(),
TraceWriter(writer),
tracingFeature?.dataWriter ?: NoOpWriter(),
random,
logsHandler,
bundleWithRumEnabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,44 @@
package com.datadog.android.tracing.internal

import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.internal.CoreFeature
import com.datadog.android.core.internal.persistence.NoOpPersistenceStrategy
import com.datadog.android.core.internal.persistence.PersistenceStrategy
import com.datadog.android.core.internal.utils.sdkLogger
import com.datadog.android.tracing.internal.domain.TracesFilePersistenceStrategy
import com.datadog.android.v2.core.internal.storage.Storage
import com.datadog.opentracing.DDSpan
import com.datadog.android.tracing.internal.data.NoOpWriter
import com.datadog.android.tracing.internal.data.TraceWriter
import com.datadog.android.tracing.internal.domain.event.DdSpanToSpanEventMapper
import com.datadog.android.tracing.internal.domain.event.SpanEventMapperWrapper
import com.datadog.android.tracing.internal.domain.event.SpanEventSerializer
import com.datadog.android.v2.api.SdkCore
import com.datadog.trace.common.writer.Writer
import java.util.concurrent.atomic.AtomicBoolean

internal class TracingFeature(
private val coreFeature: CoreFeature,
private val storage: Storage
private val sdkCore: SdkCore
) {

internal var persistenceStrategy: PersistenceStrategy<DDSpan> = NoOpPersistenceStrategy()
internal var dataWriter: Writer = NoOpWriter()
internal val initialized = AtomicBoolean(false)

// region SdkFeature

fun initialize(configuration: Configuration.Feature.Tracing) {
persistenceStrategy = createPersistenceStrategy(storage, configuration)
dataWriter = createDataWriter(configuration)
initialized.set(true)
}

fun stop() {
persistenceStrategy = NoOpPersistenceStrategy()
dataWriter = NoOpWriter()
initialized.set(false)
}

private fun createPersistenceStrategy(
storage: Storage,
private fun createDataWriter(
configuration: Configuration.Feature.Tracing
): PersistenceStrategy<DDSpan> {
return TracesFilePersistenceStrategy(
coreFeature.contextProvider,
coreFeature.persistenceExecutorService,
coreFeature,
coreFeature.envName,
sdkLogger,
configuration.spanEventMapper,
storage
): Writer {
return TraceWriter(
sdkCore,
legacyMapper = DdSpanToSpanEventMapper(),
eventMapper = SpanEventMapperWrapper(configuration.spanEventMapper),
serializer = SpanEventSerializer(),
internalLogger = sdkLogger
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.tracing.internal.data

import com.datadog.opentracing.DDSpan
import com.datadog.trace.common.writer.Writer

internal class NoOpWriter : Writer {
override fun close() {
// no-op
}

override fun write(trace: MutableList<DDSpan>?) {
// no-op
}

override fun start() {
// no-op
}

override fun incrementTraceCount() {
// no-op
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,27 @@

package com.datadog.android.tracing.internal.data

import com.datadog.android.core.internal.persistence.DataWriter
import androidx.annotation.WorkerThread
import com.datadog.android.event.EventMapper
import com.datadog.android.log.Logger
import com.datadog.android.log.internal.utils.errorWithTelemetry
import com.datadog.android.tracing.internal.TracingFeature
import com.datadog.android.tracing.model.SpanEvent
import com.datadog.android.v2.api.EventBatchWriter
import com.datadog.android.v2.api.SdkCore
import com.datadog.android.v2.api.context.DatadogContext
import com.datadog.android.v2.core.internal.storage.ContextAwareMapper
import com.datadog.android.v2.core.internal.storage.ContextAwareSerializer
import com.datadog.opentracing.DDSpan
import com.datadog.trace.common.writer.Writer
import java.util.Locale

internal class TraceWriter(
val writer: DataWriter<DDSpan>
private val sdkCore: SdkCore,
private val legacyMapper: ContextAwareMapper<DDSpan, SpanEvent>,
internal val eventMapper: EventMapper<SpanEvent>,
private val serializer: ContextAwareSerializer<SpanEvent>,
private val internalLogger: Logger
) : Writer {

// region Writer
Expand All @@ -20,10 +35,14 @@ internal class TraceWriter(
}

override fun write(trace: MutableList<DDSpan>?) {
trace?.let {
@Suppress("ThreadSafety") // TODO RUMM-1503 delegate to another thread
writer.write(it)
}
if (trace == null) return
sdkCore.getFeature(TracingFeature.TRACING_FEATURE_NAME)
?.withWriteContext { datadogContext, eventBatchWriter ->
trace.forEach { span ->
@Suppress("ThreadSafety") // called in the worker context
writeSpan(datadogContext, eventBatchWriter, span)
}
}
}

override fun close() {
Expand All @@ -35,4 +54,31 @@ internal class TraceWriter(
}

// endregion

@WorkerThread
private fun writeSpan(
datadogContext: DatadogContext,
writer: EventBatchWriter,
span: DDSpan
) {
val spanEvent = legacyMapper.map(datadogContext, span)
val mapped = eventMapper.map(spanEvent) ?: return
try {
val serialized = serializer
.serialize(datadogContext, mapped)
?.toByteArray(Charsets.UTF_8) ?: return
synchronized(this) {
writer.write(serialized, null)
}
} catch (@Suppress("TooGenericExceptionCaught") e: Throwable) {
internalLogger.errorWithTelemetry(
ERROR_SERIALIZING.format(Locale.US, mapped.javaClass.simpleName),
e
)
}
}

companion object {
internal const val ERROR_SERIALIZING = "Error serializing %s model"
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@

package com.datadog.android.tracing.internal.domain.event

import com.datadog.android.core.internal.CoreFeature
import com.datadog.android.core.internal.Mapper
import com.datadog.android.core.internal.utils.toHexString
import com.datadog.android.core.model.NetworkInfo
import com.datadog.android.tracing.model.SpanEvent
import com.datadog.android.v2.api.context.DatadogContext
import com.datadog.android.v2.api.context.NetworkInfo
import com.datadog.android.v2.core.internal.storage.ContextAwareMapper
import com.datadog.opentracing.DDSpan

internal class DdSpanToSpanEventMapper(
private val coreFeature: CoreFeature
) : Mapper<DDSpan, SpanEvent> {
internal class DdSpanToSpanEventMapper : ContextAwareMapper<DDSpan, SpanEvent> {

// region Mapper

override fun map(model: DDSpan): SpanEvent {
val serverOffset = coreFeature.timeProvider.getServerOffsetNanos()
override fun map(datadogContext: DatadogContext, model: DDSpan): SpanEvent {
val serverOffset = datadogContext.time.serverTimeOffsetNs
val metrics = resolveMetrics(model)
val metadata = resolveMeta(model)
val metadata = resolveMeta(datadogContext, model)
return SpanEvent(
traceId = model.traceId.toHexString(),
spanId = model.spanId.toHexString(),
Expand All @@ -47,8 +45,8 @@ internal class DdSpanToSpanEventMapper(
additionalProperties = event.metrics
)

private fun resolveMeta(event: DDSpan): SpanEvent.Meta {
val networkInfo = coreFeature.networkInfoProvider.getLatestNetworkInfo()
private fun resolveMeta(datadogContext: DatadogContext, event: DDSpan): SpanEvent.Meta {
val networkInfo = datadogContext.networkInfo
val simCarrier = resolveSimCarrier(networkInfo)
val networkInfoClient = SpanEvent.Client(
simCarrier = simCarrier,
Expand All @@ -58,19 +56,19 @@ internal class DdSpanToSpanEventMapper(
connectivity = networkInfo.connectivity.toString()
)
val networkInfoMeta = SpanEvent.Network(networkInfoClient)
val userInfo = coreFeature.userInfoProvider.getUserInfo()
val userInfo = datadogContext.userInfo
val usrMeta = SpanEvent.Usr(
id = userInfo.id,
name = userInfo.name,
email = userInfo.email,
additionalProperties = userInfo.additionalProperties
additionalProperties = userInfo.additionalProperties.toMutableMap()
)
return SpanEvent.Meta(
version = coreFeature.packageVersionProvider.version,
dd = SpanEvent.Dd(source = coreFeature.sourceName),
version = datadogContext.version,
dd = SpanEvent.Dd(source = datadogContext.source),
span = SpanEvent.Span(),
tracer = SpanEvent.Tracer(
version = coreFeature.sdkVersion
version = datadogContext.sdkVersion
),
usr = usrMeta,
network = networkInfoMeta,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@ package com.datadog.android.tracing.internal.domain.event

import com.datadog.android.core.internal.constraints.DataConstraints
import com.datadog.android.core.internal.constraints.DatadogDataConstraints
import com.datadog.android.core.internal.persistence.Serializer
import com.datadog.android.core.internal.utils.NULL_MAP_VALUE
import com.datadog.android.tracing.model.SpanEvent
import com.datadog.android.v2.api.context.DatadogContext
import com.datadog.android.v2.core.internal.storage.ContextAwareSerializer
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import java.util.Date

internal class SpanEventSerializer(
private val envName: String,
private val dataConstraints: DataConstraints = DatadogDataConstraints()
) : Serializer<SpanEvent> {
) : ContextAwareSerializer<SpanEvent> {

// region Serializer

override fun serialize(model: SpanEvent): String {
override fun serialize(datadogContext: DatadogContext, model: SpanEvent): String {
val span = sanitizeKeys(model).toJson()
val spans = JsonArray(1)
spans.add(span)

val jsonObject = JsonObject()
jsonObject.add(TAG_SPANS, spans)
jsonObject.addProperty(TAG_ENV, envName)
jsonObject.addProperty(TAG_ENV, datadogContext.env)

return jsonObject.toString()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ internal class DatadogCore(
)
features[TracingFeature.TRACING_FEATURE_NAME]?.let {
it.initialize(appContext, configuration.plugins)
tracingFeature = TracingFeature(coreFeature, it.storage).also {
tracingFeature = TracingFeature(this).also {
it.initialize(configuration)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.core.internal.storage

import com.datadog.android.v2.api.context.DatadogContext

internal interface ContextAwareMapper<R, T> {

fun map(datadogContext: DatadogContext, model: R): T
}
Loading

0 comments on commit 9720e9c

Please sign in to comment.