Skip to content

Trace Configuration

Trace Initialization Configuration

FTSdk.initTraceWithConfig(new FTTraceConfig()
    .setSamplingRate(0.8f)
    .setEnableAutoTrace(true)
    .setEnableLinkRUMData(true));
FTSdk.initTraceWithConfig(
    FTTraceConfig()
        .setSamplingRate(0.8f)
        .setEnableAutoTrace(true)
        .setEnableLinkRUMData(true)
)
Method Name Type Required Description
setSamplingRate Float No Sets the sampling rate, range [0,1]. 0 means no sampling, 1 means full sampling. Default is 1.
setTraceType TraceType No Sets the type of trace. Default is DDTrace. Currently supports Zipkin, Jaeger, DDTrace, Skywalking (8.0+), TraceParent (W3C). When integrating OpenTelemetry and selecting the corresponding trace type, please refer to the supported types and agent configuration.
setEnableLinkRUMData Boolean No Whether to correlate with RUM data. Default is false.
setEnableAutoTrace Boolean No Sets whether to enable automatic HTTP Trace. This configuration depends on ft-plugin. Currently only supports automatic tracing for OkHttp. Default is false.
setOkHttpTraceHeaderHandler Callback No ASM sets the global FTTraceInterceptor.HeaderHandler. Not set by default. Supported in ft-sdk 1.6.8 and above. Starting from ft-sdk 1.6.17, overriding getTraceContext(Request) is prioritized, which can return Header, traceId, and spanId at once. Example reference Custom Trace.

Tracer Network Trace

Configure FTTraceConfig to enable enableAutoTrace for automatic trace data addition, or manually use FTTraceManager to add Propagation Header in HTTP requests, as shown below.

String url = "https://request.url";
String uuid = "uuid";
// Get trace header parameters
Map<String, String> headers = FTTraceManager.get().getTraceHeader(uuid, url);

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(chain -> {
    Request original = chain.request();
    Request.Builder requestBuilder = original.newBuilder();
    // Add trace header parameters to the request
    for (String key : headers.keySet()) {
        requestBuilder.header(key, headers.get(key));
    }
    Request request = requestBuilder.build();

    Response response = chain.proceed(request);

    if (response != null) {
        Map<String, String> requestHeaderMap = new HashMap<>();
        Map<String, String> responseHeaderMap = new HashMap<>();
        for (Pair<String, String> header : response.request().headers()) {
            requestHeaderMap.put(header.first, header.second);
        }
        for (Pair<String, String> header : response.headers()) {
            responseHeaderMap.put(header.first, header.second);
        }
    }

    return response;
}).build();

Request.Builder builder = new Request.Builder().url(url).method(RequestMethod.GET.name(), null);
client.newCall(builder.build()).execute();
val url = "https://request.url"
val uuid = "uuid"
// Get trace header parameters
val headers = FTTraceManager.get().getTraceHeader(uuid, url)

val client: OkHttpClient = OkHttpClient.Builder().addInterceptor { chain ->
    val original = chain.request()
    val requestBuilder = original.newBuilder()
    // Add trace header parameters to the request
    for (key in headers.keys) {
        requestBuilder.header(key!!, headers[key]!!)
    }
    val request = requestBuilder.build()

    val response = chain.proceed(request)

    if (response != null) {
        val requestHeaderMap = HashMap<String, String>()
        val responseHeaderMap = HashMap<String, String>()
        request.headers.forEach {
            requestHeaderMap[it.first] = it.second
        }
        response.headers.forEach {
            responseHeaderMap[it.first] = it.second
        }
    }

    response
}.build()

val builder: Request.Builder = Request.Builder().url(url).method(RequestMethod.GET.name, null)
client.newCall(builder.build()).execute()

Customizing Resource and TraceHeader via OKHttp Interceptor

Resource

When FTRUMConfig.setEnableTraceUserResource(true) or FTRUMConfig.setOkHttpResourceContentHandler(...) is enabled, custom Interceptor in OkHttp will be loaded first.

new OkHttpClient.Builder()
    .addInterceptor(new FTTraceInterceptor())
    .addInterceptor(new FTResourceInterceptor(new FTResourceInterceptor.ContentHandlerHelper() {
        @Override
        public void onRequest(Request request, HashMap<String, Object> extraData) {
            String contentType = request.header("Content-Type");
            extraData.put("df_request_header", request.headers().toString());
            if ("application/json".equals(contentType) ||
                    "application/x-www-form-urlencoded".equals(contentType) ||
                    "application/xml".equals(contentType)) {
                extraData.put("df_request_body", request.body());
            }
        }

        @Override
        public void onResponse(Response response, HashMap<String, Object> extraData) throws IOException {
            String contentType = response.header("Content-Type");
            extraData.put("df_response_header", response.headers().toString());
            if ("application/json".equals(contentType) ||
                    "application/xml".equals(contentType)) {
                // Copy and read part of the body to avoid high data processing consumption
                ResponseBody body = response.peekBody(33554432);
                extraData.put("df_response_body", body.string());
            }
        }

        @Override
        public void onException(Exception e, HashMap<String, Object> extraData) {
        }
    }))
    .eventListenerFactory(new FTResourceEventListener.FTFactory())
    .build();
OkHttpClient.Builder()
    .addInterceptor(FTTraceInterceptor())
    .addInterceptor(FTResourceInterceptor(object : FTResourceInterceptor.ContentHandlerHelper {
        override fun onRequest(request: Request, extraData: HashMap<String, Any>) {
            val contentType = request.header("Content-Type")
            extraData["df_request_header"] = request.headers().toString()
            if ("application/json" == contentType ||
                "application/x-www-form-urlencoded" == contentType ||
                "application/xml" == contentType) {
                extraData["df_request_body"] = request.body()
            }
        }

        override fun onResponse(response: Response, extraData: HashMap<String, Any>) {
            val contentType = response.header("Content-Type")
            extraData["df_response_header"] = response.headers().toString()
            if ("application/json" == contentType ||
                "application/xml" == contentType) {
                // Copy part of the response body to avoid high data consumption
                val body = response.peekBody(33554432)
                extraData["df_response_body"] = body.string()
            }
        }

        override fun onException(e: Exception, extraData: HashMap<String, Any>) {
            // Handle exception cases
        }
    }))
    .eventListenerFactory(FTResourceEventListener.FTFactory())
    .build()

TraceHeader

When FTTraceConfig.setEnableAutoTrace(true) or FTTraceConfig.setOkHttpTraceHeaderHandler(...) is enabled, custom Interceptor in OkHttp will be loaded first. The following example uses W3C Trace Context.

When ft-sdk < 1.4.1, FTTraceConfig.setEnableAutoTrace(false) needs to be disabled. ft-sdk > 1.6.7 supports custom Trace Header correlation with RUM data. ft-sdk >= 1.6.17 adds getTraceContext(Request), which can return request Header, traceId, and spanId at once. It is recommended to use this method first.

new OkHttpClient.Builder()
    .addInterceptor(new FTTraceInterceptor(new FTTraceInterceptor.HeaderHandler() {
        @Override
        public TraceContext getTraceContext(Request request) {
            HashMap<String, String> headers = FTTraceManager.get()
                    .getTraceHeader(request.url().toString());
            return TraceContext.Simple.fromTraceType(headers);
        }
    }))
    .addInterceptor(new FTResourceInterceptor())
    .eventListenerFactory(new FTResourceEventListener.FTFactory())
    .build();
OkHttpClient.Builder()
    .addInterceptor(
        FTTraceInterceptor(object : FTTraceInterceptor.HeaderHandler() {
            override fun getTraceContext(request: Request): TraceContext? {
                val headers = FTTraceManager.get().getTraceHeader(request.url.toString())
                return TraceContext.Simple.fromTraceType(headers)
            }
        })
    )
    .addInterceptor(FTResourceInterceptor())
    .eventListenerFactory(FTResourceEventListener.FTFactory())
    .build()

Compatible Old Method: Implementing getTraceHeader / getTraceID / getSpanID Separately

new OkHttpClient.Builder()
    .addInterceptor(new FTTraceInterceptor(new FTTraceInterceptor.HeaderHandler() {
        private String[] splits;

        @Override
        public HashMap<String, String> getTraceHeader(Request request) {
            HashMap<String, String> map = new HashMap<>();

            String headerString = FTTraceManager.get()
                    .getTraceHeader(request.url().toString())
                    // Get propagation header from header
                    .get(FTTraceHandler.W3C_TRACEPARENT_KEY);

            splits = headerString.split("-");
            map.put(W3C_TRACEPARENT_KEY, headerString);
            return map;
        }

        @Override
        public String getSpanID() {
            if (splits != null) {
                return splits[2];
            }
            return null;
        }

        @Override
        public String getTraceID() {
            if (splits != null) {
                return splits[1];
            }
            return null;
        }
    }))
    .addInterceptor(new FTResourceInterceptor())
    .eventListenerFactory(new FTResourceEventListener.FTFactory())
    .build();
OkHttpClient.Builder()
    .addInterceptor(
        FTTraceInterceptor(object : FTTraceInterceptor.HeaderHandler {
            private var splits: Array<String>? = null

            override fun getTraceHeader(request: Request): HashMap<String, String> {
                val map = HashMap<String, String>()

                val headerString = FTTraceManager.get()
                    .getTraceHeader(request.url.toString())
                    // Get propagation header from header
                    .get(FTTraceHandler.W3C_TRACEPARENT_KEY)

                splits = headerString?.split("-")?.toTypedArray()

                headerString?.let {
                    map[W3C_TRACEPARENT_KEY] = it
                }

                return map
            }

            override fun getSpanID(): String? {
                return splits?.getOrNull(2)
            }

            override fun getTraceID(): String? {
                return splits?.getOrNull(1)
            }
        })
    )
    .addInterceptor(FTResourceInterceptor())
    .eventListenerFactory(FTResourceEventListener.FTFactory())
    .build()

Adding ResourceID to OKHttp

Add uuid to OkHttp Request. It is recommended to enable this for high-frequency concurrent scenarios with the same request. After enabling FTSDKConfig.setEnableOkhttpRequestTag(true) in ft-plugin version 1.3.5 and above, and ft-sdk version 1.6.10 and above, ResourceID can be automatically added to the Request.

new Request.Builder()
    .tag(ResourceID.class, new ResourceID());
Request.Builder()
    .tag(ResourceID::class.java, ResourceID())