Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-2165: Add trace sampling for instrumented network requests #934

Merged
merged 3 commits into from
May 23, 2022
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
4 changes: 3 additions & 1 deletion dd-sdk-android-glide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ Doing so will automatically track Glide's network requests (creating both APM Tr
@GlideModule
class CustomGlideModule :
DatadogGlideModule(
listOf("example.com", "example.eu")
listOf("example.com", "example.eu"), traceSamplingRate = 20f
)
```

Network requests are sampled with an adjustable sampling rate. A sampling of 20% is applied by default.


## Contributing

Expand Down
2 changes: 1 addition & 1 deletion dd-sdk-android-glide/apiSurface
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
open class com.datadog.android.glide.DatadogGlideModule : com.bumptech.glide.module.AppGlideModule
constructor(List<String> = emptyList())
constructor(List<String> = emptyList(), Float = DEFAULT_SAMPLING_RATE)
override fun registerComponents(android.content.Context, com.bumptech.glide.Glide, com.bumptech.glide.Registry)
override fun applyOptions(android.content.Context, com.bumptech.glide.GlideBuilder)
open fun getClientBuilder(): okhttp3.OkHttpClient.Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ import okhttp3.Request
* - be wrapped in a Span and have trace id injected to get a full flame-graph in APM.
* If no host provided the interceptor won't trace any OkHttp [Request], nor propagate tracing
* information to the backend, but RUM Resource events will still be sent for each request.
* @param samplingRate the sampling rate for APM traces created for auto-instrumented
* requests. It must be a value between `0.0` and `100.0`. A value of `0.0` means no trace will
* be kept, `100.0` means all traces will be kept (default value is `20.0`).
*/
open class DatadogGlideModule
@JvmOverloads constructor(
private val firstPartyHosts: List<String> = emptyList()
private val firstPartyHosts: List<String> = emptyList(),
private val samplingRate: Float = DEFAULT_SAMPLING_RATE
) : AppGlideModule() {

// region AppGlideModule
Expand Down Expand Up @@ -76,9 +80,13 @@ open class DatadogGlideModule
*/
open fun getClientBuilder(): OkHttpClient.Builder {
return OkHttpClient.Builder()
.addInterceptor((DatadogInterceptor(firstPartyHosts)))
.addInterceptor(DatadogInterceptor(firstPartyHosts, traceSamplingRate = samplingRate))
.eventListenerFactory(DatadogEventListener.Factory())
}

// endregion

private companion object {
private const val DEFAULT_SAMPLING_RATE: Float = 20f
}
}
10 changes: 5 additions & 5 deletions dd-sdk-android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class SampleApplication : Application() {

### Setup for Europe

If you're targetting our [Europe servers](https://datadoghq.eu), you can
If you're targeting our [Europe servers](https://datadoghq.eu), you can
initialize the library like this:

```kotlin
Expand Down Expand Up @@ -139,12 +139,12 @@ do so by providing a map alongside the message, each entry being added as an att

In Java you can do so as follows:
```java
mLogger.d(
Map<String, Object> attributes = new HashMap<>();
attributes.put("http.url", url);
logger.d(
"onPageStarted",
null,
new HashMap<String, Object>() {{
put("http.url", url);
}}
attributes
);
```

Expand Down
10 changes: 5 additions & 5 deletions dd-sdk-android/apiSurface
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class com.datadog.android.DatadogEventListener : okhttp3.EventListener
class Factory : okhttp3.EventListener.Factory
override fun create(okhttp3.Call): okhttp3.EventListener
open class com.datadog.android.DatadogInterceptor : com.datadog.android.tracing.TracingInterceptor
constructor(List<String>, com.datadog.android.tracing.TracedRequestListener = NoOpTracedRequestListener(), com.datadog.android.rum.RumResourceAttributesProvider = NoOpRumResourceAttributesProvider())
constructor(com.datadog.android.tracing.TracedRequestListener = NoOpTracedRequestListener(), com.datadog.android.rum.RumResourceAttributesProvider = NoOpRumResourceAttributesProvider())
constructor(List<String>, com.datadog.android.tracing.TracedRequestListener = NoOpTracedRequestListener(), com.datadog.android.rum.RumResourceAttributesProvider = NoOpRumResourceAttributesProvider(), Float = DEFAULT_TRACE_SAMPLING_RATE)
constructor(com.datadog.android.tracing.TracedRequestListener = NoOpTracedRequestListener(), com.datadog.android.rum.RumResourceAttributesProvider = NoOpRumResourceAttributesProvider(), Float = DEFAULT_TRACE_SAMPLING_RATE)
override fun intercept(okhttp3.Interceptor.Chain): okhttp3.Response
override fun onRequestIntercepted(okhttp3.Request, io.opentracing.Span?, okhttp3.Response?, Throwable?)
override fun canSendSpan(): Boolean
Expand Down Expand Up @@ -357,7 +357,7 @@ enum com.datadog.android.rum.RumErrorSource
- AGENT
- WEBVIEW
class com.datadog.android.rum.RumInterceptor : com.datadog.android.DatadogInterceptor
constructor(List<String> = emptyList(), RumResourceAttributesProvider = NoOpRumResourceAttributesProvider())
constructor(List<String> = emptyList(), RumResourceAttributesProvider = NoOpRumResourceAttributesProvider(), Float = DEFAULT_TRACE_SAMPLING_RATE)
interface com.datadog.android.rum.RumMonitor
fun startView(Any, String, Map<String, Any?> = emptyMap())
fun stopView(Any, Map<String, Any?> = emptyMap())
Expand Down Expand Up @@ -1439,8 +1439,8 @@ class com.datadog.android.tracing.AndroidTracer : com.datadog.opentracing.DDTrac
interface com.datadog.android.tracing.TracedRequestListener
fun onRequestIntercepted(okhttp3.Request, io.opentracing.Span, okhttp3.Response?, Throwable?)
open class com.datadog.android.tracing.TracingInterceptor : okhttp3.Interceptor
constructor(List<String>, TracedRequestListener = NoOpTracedRequestListener())
constructor(TracedRequestListener = NoOpTracedRequestListener())
constructor(List<String>, TracedRequestListener = NoOpTracedRequestListener(), Float = DEFAULT_TRACE_SAMPLING_RATE)
constructor(TracedRequestListener = NoOpTracedRequestListener(), Float = DEFAULT_TRACE_SAMPLING_RATE)
override fun intercept(okhttp3.Interceptor.Chain): okhttp3.Response
protected open fun onRequestIntercepted(okhttp3.Request, io.opentracing.Span?, okhttp3.Response?, Throwable?)
companion object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class DatadogHttpCodec {
private static final String TRACE_ID_KEY = "x-datadog-trace-id";
private static final String SPAN_ID_KEY = "x-datadog-parent-id";
private static final String SAMPLING_PRIORITY_KEY = "x-datadog-sampling-priority";
private static final String SELECTED_FOR_SAMPLE_KEY = "x-datadog-sampled";
private static final String ORIGIN_KEY = "x-datadog-origin";

private DatadogHttpCodec() {
Expand All @@ -50,8 +49,6 @@ public void inject(final DDSpanContext context, final TextMapInject carrier) {

// always use max sampling priority for Android traces
carrier.put(SAMPLING_PRIORITY_KEY, "1");
// makes this request trace selected for sampling
carrier.put(SELECTED_FOR_SAMPLE_KEY, "1");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@

package com.datadog.android

import androidx.annotation.FloatRange
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.internal.CoreFeature
import com.datadog.android.core.internal.net.FirstPartyHostDetector
import com.datadog.android.core.internal.net.identifyRequest
import com.datadog.android.core.internal.sampling.RateBasedSampler
import com.datadog.android.core.internal.sampling.Sampler
import com.datadog.android.core.internal.utils.devLogger
import com.datadog.android.core.internal.utils.sdkLogger
import com.datadog.android.rum.GlobalRum
Expand Down Expand Up @@ -65,8 +68,9 @@ import okhttp3.Response
* ```
*
* @param tracedHosts a list of all the hosts that you want to be automatically tracked
* by our APM [TracingInterceptor]. If no host provided the interceptor won't trace
* any OkHttpRequest, nor propagate tracing information to the backend.
* by our APM [TracingInterceptor]. If no host provided (via this argument or global
* configuration [Configuration.Builder.setFirstPartyHosts]) the interceptor won't trace
* any [okhttp3.Request], nor propagate tracing information to the backend.
* Please note that the host constraint will only be applied on the [TracingInterceptor] and we will
* continue to dispatch RUM Resource events for each request without applying any host filtering.
* @param tracedRequestListener which listens on the intercepted [okhttp3.Request] and offers
Expand All @@ -80,12 +84,14 @@ internal constructor(
tracedRequestListener: TracedRequestListener,
firstPartyHostDetector: FirstPartyHostDetector,
internal val rumResourceAttributesProvider: RumResourceAttributesProvider,
traceSampler: Sampler,
localTracerFactory: () -> Tracer
) : TracingInterceptor(
tracedHosts,
tracedRequestListener,
firstPartyHostDetector,
ORIGIN_RUM,
traceSampler,
localTracerFactory
) {

Expand All @@ -97,24 +103,30 @@ internal constructor(
* Requests made to a URL with any one of these hosts (or any subdomain) will:
* - be considered a first party RUM Resource and categorised as such in your RUM dashboard;
* - be wrapped in a Span and have trace id injected to get a full flame-graph in APM.
* If no host provided the interceptor won't trace any OkHttp [Request], nor propagate tracing
* If no host provided (via this argument or global configuration [Configuration.Builder.setFirstPartyHosts])
* the interceptor won't trace any OkHttp [Request], nor propagate tracing
* information to the backend, but RUM Resource events will still be sent for each request.
* @param tracedRequestListener which listens on the intercepted [okhttp3.Request] and offers
* the possibility to modify the created [io.opentracing.Span].
* @param rumResourceAttributesProvider which listens on the intercepted [okhttp3.Request]
* and offers the possibility to add custom attributes to the RUM resource events.
* @param traceSamplingRate the sampling rate for APM traces created for auto-instrumented
* requests. It must be a value between `0.0` and `100.0`. A value of `0.0` means no trace will
* be kept, `100.0` means all traces will be kept (default value is `20.0`).
*/
@JvmOverloads
constructor(
firstPartyHosts: List<String>,
tracedRequestListener: TracedRequestListener = NoOpTracedRequestListener(),
rumResourceAttributesProvider: RumResourceAttributesProvider =
NoOpRumResourceAttributesProvider()
NoOpRumResourceAttributesProvider(),
@FloatRange(from = 0.0, to = 100.0) traceSamplingRate: Float = DEFAULT_TRACE_SAMPLING_RATE
) : this(
tracedHosts = firstPartyHosts,
tracedRequestListener = tracedRequestListener,
firstPartyHostDetector = CoreFeature.firstPartyHostDetector,
rumResourceAttributesProvider = rumResourceAttributesProvider,
traceSampler = RateBasedSampler(traceSamplingRate / 100),
localTracerFactory = { AndroidTracer.Builder().build() }
)

Expand All @@ -126,17 +138,22 @@ internal constructor(
* the possibility to modify the created [io.opentracing.Span].
* @param rumResourceAttributesProvider which listens on the intercepted [okhttp3.Request]
* and offers the possibility to add custom attributes to the RUM resource events.
* @param traceSamplingRate the sampling rate for APM traces created for auto-instrumented
* requests. It must be a value between `0.0` and `100.0`. A value of `0.0` means no trace will
* be kept, `100.0` means all traces will be kept (default value is `20.0`).
*/
@JvmOverloads
constructor(
tracedRequestListener: TracedRequestListener = NoOpTracedRequestListener(),
rumResourceAttributesProvider: RumResourceAttributesProvider =
NoOpRumResourceAttributesProvider()
NoOpRumResourceAttributesProvider(),
@FloatRange(from = 0.0, to = 100.0) traceSamplingRate: Float = DEFAULT_TRACE_SAMPLING_RATE
) : this(
tracedHosts = emptyList(),
tracedRequestListener = tracedRequestListener,
firstPartyHostDetector = CoreFeature.firstPartyHostDetector,
rumResourceAttributesProvider = rumResourceAttributesProvider,
traceSampler = RateBasedSampler(traceSamplingRate / 100),
localTracerFactory = { AndroidTracer.Builder().build() }
)

Expand Down Expand Up @@ -169,7 +186,6 @@ internal constructor(
throwable: Throwable?
) {
super.onRequestIntercepted(request, span, response, throwable)

if (RumFeature.isInitialized()) {
if (response != null) {
handleResponse(request, response, span)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package com.datadog.android.rum

import androidx.annotation.FloatRange
import com.datadog.android.DatadogInterceptor
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.rum.tracking.ViewTrackingStrategy
Expand Down Expand Up @@ -36,16 +37,22 @@ import okhttp3.Request
* Requests made to a URL with any one of these hosts (or any subdomain) will:
* - be considered a first party RUM Resource and categorised as such in your RUM dashboard;
* - be wrapped in a Span and have trace id injected to get a full flame-graph in APM.
* If no host provided the interceptor won't trace any OkHttp [Request], nor propagate tracing
* If no host provided (via this argument or global configuration [Configuration.Builder.setFirstPartyHosts])
* the interceptor won't trace any OkHttp [Request], nor propagate tracing
* information to the backend, but RUM Resource events will still be sent for each request.
* @param rumResourceAttributesProvider which listens on the intercepted [okhttp3.Request]
* and offers the possibility to add custom attributes to the RUM resource events.
* @param traceSamplingRate the sampling rate for APM traces created for auto-instrumented
* requests. It must be a value between `0.0` and `100.0`. A value of `0.0` means no trace will
* be kept, `100.0` means all traces will be kept (default value is `20.0`).
*/
class RumInterceptor(
firstPartyHosts: List<String> = emptyList(),
rumResourceAttributesProvider: RumResourceAttributesProvider =
NoOpRumResourceAttributesProvider()
NoOpRumResourceAttributesProvider(),
@FloatRange(from = 0.0, to = 100.0) traceSamplingRate: Float = DEFAULT_TRACE_SAMPLING_RATE
) : DatadogInterceptor(
firstPartyHosts,
rumResourceAttributesProvider = rumResourceAttributesProvider
rumResourceAttributesProvider = rumResourceAttributesProvider,
traceSamplingRate = traceSamplingRate
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ interface TracedRequestListener {

/**
* Notifies that a span was automatically created around an OkHttp [Request].
* You can update the given [Span] (e.g.: add custom tags / baggage items) before it is persisted.
* You can update the given [Span] (e.g.: add custom tags / baggage items) before it
* is persisted. Won't be called if [Request] wasn't sampled.
* @param request the intercepted [Request]
* @param span the [Span] created around the intercepted [Request]
* @param response the [Request] response in case of any
Expand Down
Loading