Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dd-sdk-android-core/api/apiSurface
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ interface com.datadog.android.api.feature.Feature
const val FLAGS_FEATURE_NAME: String
const val FLAGS_EVALUATIONS_FEATURE_NAME: String
const val TRACING_FEATURE_NAME: String
const val TRACING_CLIENT_STATS_FEATURE_NAME: String
const val SESSION_REPLAY_FEATURE_NAME: String
const val SESSION_REPLAY_RESOURCES_FEATURE_NAME: String
const val NDK_CRASH_REPORTS_FEATURE_NAME: String
Expand Down
2 changes: 2 additions & 0 deletions dd-sdk-android-core/api/dd-sdk-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ public abstract interface class com/datadog/android/api/feature/Feature {
public static final field RUM_FEATURE_NAME Ljava/lang/String;
public static final field SESSION_REPLAY_FEATURE_NAME Ljava/lang/String;
public static final field SESSION_REPLAY_RESOURCES_FEATURE_NAME Ljava/lang/String;
public static final field TRACING_CLIENT_STATS_FEATURE_NAME Ljava/lang/String;
public static final field TRACING_FEATURE_NAME Ljava/lang/String;
public abstract fun getName ()Ljava/lang/String;
public abstract fun onInitialize (Landroid/content/Context;)V
Expand All @@ -400,6 +401,7 @@ public final class com/datadog/android/api/feature/Feature$Companion {
public static final field RUM_FEATURE_NAME Ljava/lang/String;
public static final field SESSION_REPLAY_FEATURE_NAME Ljava/lang/String;
public static final field SESSION_REPLAY_RESOURCES_FEATURE_NAME Ljava/lang/String;
public static final field TRACING_CLIENT_STATS_FEATURE_NAME Ljava/lang/String;
public static final field TRACING_FEATURE_NAME Ljava/lang/String;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ interface Feature {
*/
const val TRACING_FEATURE_NAME: String = "tracing"

/**
* Tracing Client Stats feature name.
*/
const val TRACING_CLIENT_STATS_FEATURE_NAME: String = "tracing-client-stats"

/**
* Session Replay feature name.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2686,6 +2686,7 @@ public class com/datadog/trace/core/CoreTracer$CoreTracerBuilder {
public fun injectBaggageAsTags (Z)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
public fun injector (Lcom/datadog/trace/core/propagation/HttpCodec$Injector;)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
public fun localRootSpanTags (Ljava/util/Map;)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
public fun metricsAggregator (Lcom/datadog/trace/common/metrics/MetricsAggregator;)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
public fun partialFlushMinSpans (I)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
public fun sampler (Lcom/datadog/trace/common/sampling/Sampler;)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
public fun scopeManager (Lcom/datadog/trace/bootstrap/instrumentation/api/AgentScopeManager;)Lcom/datadog/trace/core/CoreTracer$CoreTracerBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ public static class CoreTracerBuilder {
private Config config;
private String serviceName;
private Writer writer = new NoOpWriter();
private MetricsAggregator metricsAggregator = NoOpMetricsAggregator.INSTANCE;
private IdGenerationStrategy idGenerationStrategy;
private Sampler sampler;
private HttpCodec.Extractor extractor;
Expand Down Expand Up @@ -238,6 +239,11 @@ public CoreTracerBuilder writer(Writer writer) {
return this;
}

public CoreTracerBuilder metricsAggregator(MetricsAggregator metricsAggregator) {
this.metricsAggregator = metricsAggregator;
return this;
}

public CoreTracerBuilder idGenerationStrategy(IdGenerationStrategy idGenerationStrategy) {
this.idGenerationStrategy = idGenerationStrategy;
return this;
Expand Down Expand Up @@ -350,6 +356,7 @@ public CoreTracer build() {
config,
serviceName,
writer,
metricsAggregator,
idGenerationStrategy,
sampler,
injector,
Expand All @@ -375,6 +382,7 @@ private CoreTracer(
final Config config,
final String serviceName,
final Writer writer,
final MetricsAggregator metricsAggregator,
final IdGenerationStrategy idGenerationStrategy,
final Sampler sampler,
final HttpCodec.Injector injector,
Expand Down Expand Up @@ -479,7 +487,7 @@ private CoreTracer(
pendingTraceBuffer.start();

this.writer.start();
metricsAggregator = NoOpMetricsAggregator.INSTANCE;
this.metricsAggregator = metricsAggregator;
// Schedule the metrics aggregator to begin reporting after a random delay of 1 to 10 seconds
// (using milliseconds granularity.) This avoids a fleet of traced applications starting at the
// same time from sending metrics in sync.
Expand Down
1 change: 1 addition & 0 deletions features/dd-sdk-android-trace/api/apiSurface
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ data class com.datadog.android.trace.TraceConfiguration
fun setEventMapper(com.datadog.android.trace.event.SpanEventMapper): Builder
fun setNetworkInfoEnabled(Boolean): Builder
fun setStatsComputationEnabled(Boolean): Builder
fun useCustomStatsEndpoint(String): Builder
fun build(): TraceConfiguration
enum com.datadog.android.trace.TraceContextInjection
- ALL
Expand Down
5 changes: 3 additions & 2 deletions features/dd-sdk-android-trace/api/dd-sdk-android-trace.api
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public final class com/datadog/android/trace/Trace {
}

public final class com/datadog/android/trace/TraceConfiguration {
public final fun copy (Ljava/lang/String;Lcom/datadog/android/trace/event/SpanEventMapper;ZZ)Lcom/datadog/android/trace/TraceConfiguration;
public static synthetic fun copy$default (Lcom/datadog/android/trace/TraceConfiguration;Ljava/lang/String;Lcom/datadog/android/trace/event/SpanEventMapper;ZZILjava/lang/Object;)Lcom/datadog/android/trace/TraceConfiguration;
public final fun copy (Ljava/lang/String;Lcom/datadog/android/trace/event/SpanEventMapper;ZZLjava/lang/String;)Lcom/datadog/android/trace/TraceConfiguration;
public static synthetic fun copy$default (Lcom/datadog/android/trace/TraceConfiguration;Ljava/lang/String;Lcom/datadog/android/trace/event/SpanEventMapper;ZZLjava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/trace/TraceConfiguration;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand All @@ -82,6 +82,7 @@ public final class com/datadog/android/trace/TraceConfiguration$Builder {
public final fun setNetworkInfoEnabled (Z)Lcom/datadog/android/trace/TraceConfiguration$Builder;
public final fun setStatsComputationEnabled (Z)Lcom/datadog/android/trace/TraceConfiguration$Builder;
public final fun useCustomEndpoint (Ljava/lang/String;)Lcom/datadog/android/trace/TraceConfiguration$Builder;
public final fun useCustomStatsEndpoint (Ljava/lang/String;)Lcom/datadog/android/trace/TraceConfiguration$Builder;
}

public final class com/datadog/android/trace/TraceContextInjection : java/lang/Enum {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import com.datadog.android.api.feature.Feature
import com.datadog.android.api.feature.FeatureSdkCore
import com.datadog.android.trace.api.tracer.DatadogTracerBuilder
import com.datadog.android.trace.api.tracer.NoOpDatadogTracerBuilder
import com.datadog.android.trace.internal.ClientStatsFeature
import com.datadog.android.trace.internal.DatadogSpanWriterWrapper
import com.datadog.android.trace.internal.DatadogTracerBuilderAdapter
import com.datadog.android.trace.internal._TraceInternalProxy
import com.datadog.trace.common.metrics.NoOpMetricsAggregator
import com.datadog.trace.common.writer.NoOpWriter
import com.datadog.trace.core.CoreTracer

Expand Down Expand Up @@ -47,6 +49,13 @@ object DatadogTracing {
val internalCoreWriterProvider = tracingFeature as? InternalCoreWriterProvider
val writer = (internalCoreWriterProvider?.getCoreTracerWriter() as? DatadogSpanWriterWrapper)?.delegate

val metricsFeature = if (tracingFeature != null) {
sdkCore.getFeature(Feature.TRACING_CLIENT_STATS_FEATURE_NAME)?.unwrap<ClientStatsFeature>()
} else {
null
}
val internalMetricsAggregator = metricsFeature?.aggregator

when {
null == tracingFeature -> internalLogger.log(
InternalLogger.Level.ERROR,
Expand Down Expand Up @@ -80,7 +89,9 @@ object DatadogTracing {
DatadogTracerBuilderAdapter(
sdkCore = sdkCore,
serviceName = sdkCore.service,
delegate = CoreTracer.CoreTracerBuilder(sdkCore.internalLogger).writer(writer ?: NoOpWriter())
delegate = CoreTracer.CoreTracerBuilder(sdkCore.internalLogger)
.writer(writer ?: NoOpWriter())
.metricsAggregator(internalMetricsAggregator ?: NoOpMetricsAggregator.INSTANCE)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.datadog.android.trace
import com.datadog.android.Datadog
import com.datadog.android.api.SdkCore
import com.datadog.android.api.feature.FeatureSdkCore
import com.datadog.android.trace.internal.ClientStatsFeature
import com.datadog.android.trace.internal.TracingFeature

/**
Expand All @@ -34,5 +35,13 @@ object Trace {
)

sdkCore.registerFeature(tracingFeature)

if (traceConfiguration.statsComputationEnabled) {
val stats = ClientStatsFeature(
customEndpointUrl = traceConfiguration.customStatsEndpointUrl
)

sdkCore.registerFeature(stats)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ data class TraceConfiguration internal constructor(
internal val customEndpointUrl: String?,
internal val eventMapper: SpanEventMapper,
internal val networkInfoEnabled: Boolean,
internal val statsComputationEnabled: Boolean
internal val statsComputationEnabled: Boolean,
internal val customStatsEndpointUrl: String?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve TraceConfiguration copy binary compatibility

Adding customStatsEndpointUrl to the primary constructor of this public data class changes the generated copy(...) and copy$default(...) JVM signatures, as reflected in the API diff. Apps compiled against the previous SDK that call TraceConfiguration.copy(...) can then fail with NoSuchMethodError after upgrading the runtime artifact, even though their source still compiles; keep the generated data-class constructor/copy shape stable and store the new internal value outside the primary constructor or behind an overload.

Useful? React with 👍 / 👎.

) {

/**
Expand All @@ -27,6 +28,7 @@ data class TraceConfiguration internal constructor(
private var spanEventMapper: SpanEventMapper = NoOpSpanEventMapper()
private var networkInfoEnabled: Boolean = true
private var statsComputationEnabled: Boolean = false
private var customStatsEndpointUrl: String? = null

/**
* Let the Tracing feature target a custom server.
Expand Down Expand Up @@ -71,6 +73,15 @@ data class TraceConfiguration internal constructor(
return this
}

/**
* Let the Tracing client-side stats feature target a custom server.
* The provided url should be the full endpoint url, e.g.: https://example.com/stats/upload
*/
fun useCustomStatsEndpoint(endpoint: String): Builder {
customStatsEndpointUrl = endpoint
return this
}

/**
* Builds a [TraceConfiguration] based on the current state of this Builder.
*/
Expand All @@ -79,7 +90,8 @@ data class TraceConfiguration internal constructor(
customEndpointUrl = customEndpointUrl,
eventMapper = spanEventMapper,
networkInfoEnabled = networkInfoEnabled,
statsComputationEnabled = statsComputationEnabled
statsComputationEnabled = statsComputationEnabled,
customStatsEndpointUrl = customStatsEndpointUrl
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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.trace.internal

import android.content.Context
import com.datadog.android.api.feature.Feature
import com.datadog.android.api.feature.StorageBackedFeature
import com.datadog.android.api.storage.FeatureStorageConfiguration
import com.datadog.android.trace.internal.net.ClientStatsRequestFactory
import com.datadog.trace.common.metrics.NoOpMetricsAggregator

internal class ClientStatsFeature(
customEndpointUrl: String?
) : StorageBackedFeature {
override val name = Feature.TRACING_CLIENT_STATS_FEATURE_NAME

override val storageConfiguration = FeatureStorageConfiguration(
// 512 KB
maxItemSize = 512L * 1024,
maxItemsPerBatch = 4000,
// 15 MB
maxBatchSize = 15L * 1024 * 1024,
// 18 hours
oldBatchThreshold = 18L * 60L * 60L * 1000L
)

// TODO RUM-16565 Implement stats aggregator
internal val aggregator = NoOpMetricsAggregator()

override val requestFactory = ClientStatsRequestFactory(customEndpointUrl)

override fun onInitialize(appContext: Context) {}

override fun onStop() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.trace.internal.net

import com.datadog.android.api.context.DatadogContext
import com.datadog.android.api.net.Request
import com.datadog.android.api.net.RequestExecutionContext
import com.datadog.android.api.net.RequestFactory
import com.datadog.android.api.storage.RawBatchEvent
import com.datadog.android.trace.internal.domain.metrics.StatsPayload
import java.util.UUID

internal class ClientStatsRequestFactory(
internal val customStatsEndpointUrl: String?
) : RequestFactory {

override fun create(
context: DatadogContext,
executionContext: RequestExecutionContext,
batchData: List<RawBatchEvent>,
batchMetadata: ByteArray?
): Request {
val requestId = UUID.randomUUID().toString()

val baseUrl = customStatsEndpointUrl ?: (context.site.intakeEndpoint + "/api/v0.2/stats")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it indeed like that - v0.2 or it should be v2 here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Batches can't be split currently due to we can't create more than 1 Request in this class,
// nor can the batch building system report back when a batch will be filled before writing it,
// so we cant set a splitPayload flag in the batch's metadata.
val payload = StatsPayload(batchData.map { it.data }, splitPayload = false)

return Request(
id = requestId,
description = "Client Stats Request",
url = baseUrl,
headers = buildHeaders(
requestId,
context.clientToken,
context.source,
context.sdkVersion
),
body = payload.toMsgPackPayload(),
contentType = "application/msgpack"
)
}

private fun buildHeaders(
requestId: String,
clientToken: String,
source: String,
sdkVersion: String
): Map<String, String> {
return mapOf(
RequestFactory.HEADER_API_KEY to clientToken,
RequestFactory.HEADER_EVP_ORIGIN to source,
RequestFactory.HEADER_EVP_ORIGIN_VERSION to sdkVersion,
RequestFactory.HEADER_REQUEST_ID to requestId
)
}
}
Loading
Loading