콘텐츠로 이동

Trace 설정

Trace 초기화 설정

FTSdk.initTraceWithConfig(new FTTraceConfig()
    .setSamplingRate(0.8f)
    .setEnableAutoTrace(true)
    .setEnableLinkRUMData(true));
FTSdk.initTraceWithConfig(
    FTTraceConfig()
        .setSamplingRate(0.8f)
        .setEnableAutoTrace(true)
        .setEnableLinkRUMData(true)
)
메서드명 유형 필수 설명
setSamplingRate Float 아니요 수집률 설정. 값 범위는 [0,1]이며, 0은 수집 안 함, 1은 전체 수집을 의미합니다. 기본값은 1입니다.
setTraceType TraceType 아니요 분산 추적 유형 설정. 기본값은 DDTrace이며, 현재 Zipkin, Jaeger, DDTrace, Skywalking (8.0+), TraceParent (W3C)를 지원합니다. OpenTelemetry를 연동할 때 해당 링크 유형을 선택하는 경우, 지원 유형 및 에이전트 관련 설정을 확인하시기 바랍니다.
setEnableLinkRUMData Boolean 아니요 RUM 데이터와 연결 여부를 설정합니다. 기본값은 false입니다.
setEnableAutoTrace Boolean 아니요 자동 HTTP Trace 활성화 여부를 설정합니다. 이 설정은 ft-plugin에 의존하며, 현재는 OkHttp의 자동 추적만 지원합니다. 기본값은 false입니다.
setOkHttpTraceHeaderHandler Callback 아니요 ASM 전역 FTTraceInterceptor.HeaderHandler를 설정합니다. 기본적으로 설정되지 않으며, ft-sdk 1.6.8 이상에서 지원됩니다. ft-sdk 1.6.17부터는 getTraceContext(Request)를 재정의하는 방식이 우선 지원되며, 한 번에 Header, traceIdspanId를 반환할 수 있습니다. 예제는 사용자 정의 Trace를 참조하세요.

Tracer 네트워크 분산 추적

FTTraceConfig 설정에서 enableAutoTrace를 활성화하여 링크 데이터를 자동으로 추가하거나, 수동으로 FTTraceManager를 사용하여 HTTP 요청에 Propagation Header를 추가할 수 있습니다. 예제는 다음과 같습니다.

String url = "https://request.url";
String uuid = "uuid";
// 링크 헤더 매개변수 가져오기
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();
    // 요청에 링크 헤더 매개변수 추가
    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"
// 링크 헤더 매개변수 가져오기
val headers = FTTraceManager.get().getTraceHeader(uuid, url)

val client: OkHttpClient = OkHttpClient.Builder().addInterceptor { chain ->
    val original = chain.request()
    val requestBuilder = original.newBuilder()
    // 요청에 링크 헤더 매개변수 추가
    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()

OkHttp Interceptor를 통한 Resource 및 TraceHeader 사용자 정의

Resource

FTRUMConfig.setEnableTraceUserResource(true) 또는 FTRUMConfig.setOkHttpResourceContentHandler(...)가 활성화되면 OkHttp의 사용자 정의 Interceptor가 우선 로드됩니다.

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)) {
                // 대용량 데이터 처리 부하를 방지하기 위해 body의 일부만 복사하여 읽음
                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) {
                // 대용량 데이터 소비를 방지하기 위해 응답 본문의 일부를 복사
                val body = response.peekBody(33554432)
                extraData["df_response_body"] = body.string()
            }
        }

        override fun onException(e: Exception, extraData: HashMap<String, Any>) {
            // 예외 상황 처리
        }
    }))
    .eventListenerFactory(FTResourceEventListener.FTFactory())
    .build()

TraceHeader

FTTraceConfig.setEnableAutoTrace(true) 또는 FTTraceConfig.setOkHttpTraceHeaderHandler(...)가 활성화되면 OkHttp의 사용자 정의 Interceptor가 우선 로드됩니다. 다음은 W3C Trace Context를 예시로 설명합니다.

ft-sdk < 1.4.1인 경우 FTTraceConfig.setEnableAutoTrace(false)를 비활성화해야 합니다. ft-sdk > 1.6.7에서 사용자 정의 Trace Header와 RUM 데이터 연결을 지원합니다. ft-sdk >= 1.6.17에서 getTraceContext(Request)가 추가되어 요청 Header, traceIdspanId를 한 번에 반환할 수 있습니다. 이 방식을 우선 사용하는 것을 권장합니다.

권장 방식: getTraceContext(Request) 사용

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()

구형 방식 호환: getTraceHeader / getTraceID / getSpanID 각각 구현

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())
                    // header에서 propagation 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())
                    // header에서 propagation 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()

OkHttp에 ResourceID 추가

OkHttp Request에 uuid를 추가합니다. 동일한 요청이 고빈도로 동시에 발생하는 시나리오에서 활성화하는 것이 좋습니다. ft-plugin 1.3.5 이상, ft-sdk 1.6.10 이상에서 FTSDKConfig.setEnableOkhttpRequestTag(true)를 활성화하면 RequestResourceID가 자동으로 추가됩니다.

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

문서 평가

이 페이지가 도움이 되었나요?