Skip to content

Commit bfd421e

Browse files
author
yuguo.dtpe
committed
feature(debugger): add debug info
1 parent 16f12aa commit bfd421e

File tree

13 files changed

+572
-49
lines changed

13 files changed

+572
-49
lines changed

SDK_Integration_zh.md

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
- [退避策略](#退避策略)
3333
- [异常处理](#异常处理)
3434
- [Debug机制](#debug机制)
35+
- [开启Debug模式](#开启debug模式)
3536

3637
# 集成SDK
3738

@@ -641,23 +642,17 @@ public class SampleCode {
641642

642643
为便于客户在处理请求时进行问题排查和调试,SDK 支持日志功能,并提供多种日志级别设置。客户可根据实际需求配置日志级别,获取详细的请求与响应信息,以提升排障效率和系统可 observability(可观测性)。
643644

645+
## 开启Debug模式
646+
644647
> **默认**
645-
> * `debugging` - `false` (表示不开启debug模式)
648+
> * `debug` - `false` (表示不开启debug模式)
646649
647-
Java SDK使用的是`com.squareup.okhttp.OkHttpClient`,可以通过设置`debugging`来开启debug模式
650+
Java SDK日志使用的是slf4j,需要依赖客户的配置文件,客户可以根据自己的需求,配置日志级别
648651

649-
```java
650-
import com.volcengine.ApiClient;
651-
import com.volcengine.sign.Credentials;
652-
653-
public class SampleCode {
654-
public static void main(String[] args) {
655-
String regionId = "cn-beijing";
656-
ApiClient apiClient = new ApiClient()
657-
.setCredentials(Credentials.getEnvCredentials())
658-
.setRegion(regionId)
659-
.setDebugging(true);
660-
}
661-
}
652+
**配置示例:**
662653

654+
```xml
655+
<!--开启debug日志-->
656+
<logger name="com.volcengine.sdkcore" level="debug"/>
663657
```
658+

volcengine-java-sdk-core/src/main/java/com/volcengine/ApiClient.java

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@
2727
import com.squareup.okhttp.Response;
2828
import com.squareup.okhttp.internal.http.HttpMethod;
2929
import com.squareup.okhttp.logging.HttpLoggingInterceptor;
30-
import com.squareup.okhttp.logging.HttpLoggingInterceptor.Level;
3130
import com.volcengine.auth.Authentication;
3231
import com.volcengine.auth.CredentialProvider;
32+
import com.volcengine.observability.debugger.LogLevel;
33+
import com.volcengine.observability.debugger.SdkConfigLog;
3334
import com.volcengine.endpoint.DefaultEndpointProvider;
3435
import com.volcengine.endpoint.EndpointResolver;
3536
import com.volcengine.interceptor.BuildRequestInterceptor;
@@ -42,6 +43,7 @@
4243
import com.volcengine.interceptor.SignRequestInterceptor;
4344
import com.volcengine.model.AbstractResponse;
4445
import com.volcengine.model.ResponseMetadata;
46+
import com.volcengine.observability.debugger.SdkDebugLog;
4547
import com.volcengine.retryer.BackoffStrategy;
4648
import com.volcengine.retryer.DefaultRetryerSetting;
4749
import com.volcengine.retryer.RetryCondition;
@@ -97,6 +99,9 @@
9799
import java.util.regex.Matcher;
98100
import java.util.regex.Pattern;
99101

102+
import static com.volcengine.observability.debugger.LogLevel.LOG_DEBUG_WITH_CONFIG;
103+
import static com.volcengine.observability.debugger.SdkDebugLog.SDK_CORE_LOGGER;
104+
100105
public class ApiClient extends BaseClient{
101106
private final static String DefaultAuthentication = "volcengineSign";
102107

@@ -144,6 +149,7 @@ public class ApiClient extends BaseClient{
144149

145150
private String httpProxy;
146151
private String httpsProxy;
152+
private SdkConfigLog sdkConfigLog;
147153

148154
/*
149155
* Constructor for ApiClient
@@ -1082,6 +1088,7 @@ public <T> ApiResponse<T> execute(Call call, final Type returnType, boolean... i
10821088
responseInterceptorContext.setReturnType(returnType);
10831089
context.setResponseContext(responseInterceptorContext);
10841090
context.setApiClient(this);
1091+
logSdkConfig();
10851092

10861093
int numMaxRetries = retryer.getNumMaxRetries();
10871094
ApiException apiException;
@@ -1135,10 +1142,12 @@ private ApiException handleApiResponseException(ApiException apiException) {
11351142

11361143
private boolean requestShouldRetry(ApiResponse apiResponse, int retryCount, ApiException lastException) throws ApiException {
11371144
if (autoRetry && retryer.shouldRetry(apiResponse, retryCount, lastException)) {
1145+
SDK_CORE_LOGGER.debugRetry("maxReryCout:{}, currentRetryCount:{}, backoffStrategy:{}", retryer.getNumMaxRetries(), retryCount + 1, retryer.getBackoffStrategy().getClass().getSimpleName());
11381146
try {
11391147
long delay = retryer.getBackoffDelay(retryCount);
11401148
Thread.sleep(delay);
11411149
} catch (Exception e) {
1150+
SDK_CORE_LOGGER.error(()->"Failed to getBackoffDelay or sleep", e);
11421151
throw new ApiException(e);
11431152
}
11441153
return true;
@@ -1179,6 +1188,7 @@ public <T> void executeAsync(Call call, final Type returnType, final ApiCallback
11791188
context.setResponseContext(responseInterceptorContext);
11801189

11811190
context.setApiClient(this);
1191+
logSdkConfig();
11821192

11831193
final int maxRetries = retryer.getNumMaxRetries();
11841194
final AtomicInteger retryCount = new AtomicInteger(0);
@@ -1999,4 +2009,76 @@ public ApiClient setBackoffStrategy(BackoffStrategy backoffStrategy) throws ApiE
19992009
public OkHttpClient getOkHttpClient() {
20002010
return this.httpClient;
20012011
}
2012+
2013+
/**
2014+
* 设置日志级别。
2015+
*
2016+
* <p>logLevel 的值应来自 {@link LogLevel} 枚举的 {@link LogLevel#mask()},
2017+
* 可以通过 {@link LogLevel#combine(LogLevel...)} 组合多个模式。</p>
2018+
*
2019+
* <p>常见用法示例:</p>
2020+
* <pre>{@code
2021+
* // 只启用请求日志
2022+
* logger.setLogLevel(LogLevel.LOG_DEBUG_WITH_REQUEST.mask());
2023+
*
2024+
* // 启用请求和响应日志
2025+
* logger.setLogLevel(LogLevel.combine(
2026+
* LogLevel.LOG_DEBUG_WITH_REQUEST,
2027+
* LogLevel.LOG_DEBUG_WITH_RESPONSE));
2028+
*
2029+
* // 启用所有调试日志
2030+
* logger.setLogLevel(LogLevel.LOG_DEBUG_ALL.mask());
2031+
* }</pre>
2032+
*
2033+
* @param logLevel 日志级别标志位,参考 {@link LogLevel}
2034+
*/
2035+
public ApiClient setLogLevel(long logLevel) {
2036+
SdkDebugLog.SDK_CORE_LOGGER.setLogLevel(logLevel);
2037+
return this;
2038+
}
2039+
2040+
public long getLogLevel() {
2041+
return SdkDebugLog.SDK_CORE_LOGGER.getLogLevel();
2042+
}
2043+
2044+
private void logSdkConfig() {
2045+
if (!SDK_CORE_LOGGER.isDebugEnabled() || !SDK_CORE_LOGGER.matches(LOG_DEBUG_WITH_CONFIG)){
2046+
return;
2047+
}
2048+
2049+
if (this.sdkConfigLog != null) {
2050+
this.sdkConfigLog.log();
2051+
}
2052+
synchronized (this){
2053+
2054+
if (this.sdkConfigLog != null) {
2055+
this.sdkConfigLog.log();
2056+
}
2057+
2058+
SdkConfigLog sdkConfigLog = new SdkConfigLog();
2059+
sdkConfigLog.setMaxIdleConns(this.maxIdleConns);
2060+
sdkConfigLog.setKeepAliveDurationMs(this.keepAliveDurationMs);
2061+
sdkConfigLog.setDisableSSL(this.disableSSL);
2062+
sdkConfigLog.setVerifyingSsl(this.verifyingSsl);
2063+
sdkConfigLog.setHttpProxy(this.httpProxy);
2064+
sdkConfigLog.setHttpsProxy(this.httpsProxy);
2065+
sdkConfigLog.setConnectTimeout(this.getConnectTimeout());
2066+
sdkConfigLog.setReadTimeout(this.getReadTimeout());
2067+
sdkConfigLog.setWriteTimeout(this.getWriteTimeout());
2068+
sdkConfigLog.setAutoRetry(this.autoRetry);
2069+
sdkConfigLog.setMinRetryDelayMs(this.getMinRetryDelayMs());
2070+
sdkConfigLog.setMaxRetryDelayMs(this.getMaxRetryDelayMs());
2071+
sdkConfigLog.setRetryCondition(this.getRetryCondition());
2072+
sdkConfigLog.setBackoffStrategy(this.getBackoffStrategy());
2073+
sdkConfigLog.setRetryErrorCode(this.getRetryErrorCodes());
2074+
sdkConfigLog.setRegion(this.region);
2075+
sdkConfigLog.setEndpoint(this.endpoint);
2076+
sdkConfigLog.setUseDualStack(this.useDualStack);
2077+
sdkConfigLog.setCustomBootstrapRegion(this.customBootstrapRegion);
2078+
sdkConfigLog.setEndpointResolver(this.endpointResolver);
2079+
sdkConfigLog.log();
2080+
this.sdkConfigLog = sdkConfigLog;
2081+
}
2082+
2083+
}
20022084
}

volcengine-java-sdk-core/src/main/java/com/volcengine/endpoint/DefaultEndpointProvider.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.HashSet;
77
import java.util.Map;
88
import java.util.Set;
9+
import static com.volcengine.observability.debugger.SdkDebugLog.SDK_CORE_LOGGER;
910

1011
public class DefaultEndpointProvider implements EndpointResolver {
1112

@@ -735,30 +736,37 @@ private static String getDefaultEndpointByServiceInfo(String service, String reg
735736
String resultEndpoint = ENDPOINT;
736737
ServiceEndpointInfo endpointInfo = DEFAULT_ENDPOINT_MAP.get(service);
737738
if (endpointInfo == null || !inBootstrapRegionList(regionCode, customBootstrapRegion)) {
739+
SDK_CORE_LOGGER.debugEndpoint("Service '{}' not found in default endpoint map, fallback to default: {}, Or Region '{}' not in bootstrap region list, fallback to default: {}", service, resultEndpoint, regionCode, resultEndpoint);
738740
return resultEndpoint;
739741
}
740742

743+
741744
String endpointSuffix = hasEnabledDualstack(useDualStack) ? DUALSTACK_ENDPOINT_SUFFIX : ENDPOINT_SUFFIX;
745+
SDK_CORE_LOGGER.debugEndpoint("Endpoint suffix is: " + endpointSuffix);
742746

743747
if (endpointInfo.isGlobal) {
744748
if (!endpointInfo.globalEndpoint.isEmpty()) {
749+
SDK_CORE_LOGGER.debugEndpoint("Service '{}' is global, using predefined global endpoint: {}", service, resultEndpoint);
745750
resultEndpoint = endpointInfo.globalEndpoint;
746751
return resultEndpoint;
747752
}
748753

749754
resultEndpoint = standardizeDomainServiceCode(service) + endpointSuffix;
755+
SDK_CORE_LOGGER.debugEndpoint("Service '{}' is global, constructing endpoint: {}", service, resultEndpoint);
750756
return resultEndpoint;
751757
}
752758

753759
if (endpointInfo.regionEndpointMap != null) {
754760
String regionEndpoint = endpointInfo.regionEndpointMap.get(regionCode);
755761
if (regionEndpoint != null) {
756762
resultEndpoint = regionEndpoint;
763+
SDK_CORE_LOGGER.debugEndpoint("Found predefined endpoint for service '{}' in region '{}': {}", service, regionCode, resultEndpoint);
757764
return resultEndpoint;
758765
}
759766
}
760767

761768
resultEndpoint = standardizeDomainServiceCode(service) + SEPARATOR + regionCode + endpointSuffix;
769+
SDK_CORE_LOGGER.debugEndpoint("Constructing endpoint for service '{}' in region '{}': {}", service, regionCode, resultEndpoint);
762770
return resultEndpoint;
763771
}
764772

@@ -767,6 +775,7 @@ private static boolean inBootstrapRegionList(String region, Set<String> customBo
767775
String bsRegionListPath = System.getenv("VOLC_BOOTSTRAP_REGION_LIST_CONF");
768776

769777
if (bsRegionListPath != null && !bsRegionListPath.isEmpty()) {
778+
SDK_CORE_LOGGER.debugEndpoint("Checking for region in file specified by VOLC_BOOTSTRAP_REGION_LIST_CONF: " + bsRegionListPath);
770779
try {
771780
BufferedReader reader = new BufferedReader(new FileReader(bsRegionListPath));
772781
String line;
@@ -777,23 +786,28 @@ private static boolean inBootstrapRegionList(String region, Set<String> customBo
777786
}
778787
if (line.equals(regionCode)) {
779788
reader.close();
789+
SDK_CORE_LOGGER.debugEndpoint("Region '{}' found in {}.", regionCode, bsRegionListPath);
780790
return true;
781791
}
782792
}
783793
reader.close();
784794
} catch (Exception e) {
785-
System.err.println("Error when reading " + bsRegionListPath + ": " + e.getMessage());
795+
SDK_CORE_LOGGER.error(()->"Error when reading " + bsRegionListPath + ": ", e);
786796
}
787797
}
788798

789799
if (BOOTSTRAP_REGION.contains(region)) {
800+
SDK_CORE_LOGGER.debugEndpoint("Region '{}' found in default bootstrap list.", region);
790801
return true;
791802
}
792803

793-
if (customBootstrapRegion != null) {
794-
return customBootstrapRegion.contains(region);
804+
if (customBootstrapRegion != null && customBootstrapRegion.contains(region)) {
805+
SDK_CORE_LOGGER.debugEndpoint("Region '{}' found in custom bootstrap list.", region);
806+
return true;
795807
}
796808

809+
SDK_CORE_LOGGER.debugEndpoint("Region '{}' not found in any bootstrap list.", region);
810+
797811
return false;
798812
}
799813

volcengine-java-sdk-core/src/main/java/com/volcengine/endpoint/EndpointResolver.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22

33
public interface EndpointResolver {
44

5-
public ResolvedEndpoint endpointFor(ResolveEndpointOption option);
5+
ResolvedEndpoint endpointFor(ResolveEndpointOption option);
6+
67
}

volcengine-java-sdk-core/src/main/java/com/volcengine/interceptor/HttpLoggingInterceptor.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313
import java.io.IOException;
1414
import java.nio.charset.Charset;
1515
import java.util.concurrent.TimeUnit;
16-
import com.volcengine.utils.LoggerUtil;
16+
import com.volcengine.ApiClient;
17+
import com.volcengine.observability.debugger.LogLevel;
1718
import okio.Buffer;
1819
import okio.BufferedSource;
1920
import static com.volcengine.utils.ConstantsUtil.NEW_LINE;
21+
import static com.volcengine.observability.debugger.SdkDebugLog.SDK_CORE_LOGGER;
2022

2123
public final class HttpLoggingInterceptor implements Interceptor {
2224

23-
private static final LoggerUtil REQUEST_LOGGER = LoggerUtil.loggerFor("com.volcengine.request");
24-
private static final LoggerUtil REQUEST_ID_LOGGER = LoggerUtil.loggerFor("com.volcengine.request.requestId");
2525
private static final String HEAD_LOG_ID = "X-Tt-Logid";
2626

2727
private static final Charset UTF8 = Charset.forName("UTF-8");
@@ -45,12 +45,13 @@ public Response intercept(Chain chain) throws IOException {
4545

4646
private void logResponseLog(Response response, long tookMs) throws IOException {
4747
Headers headers = response.headers();
48-
if (REQUEST_ID_LOGGER.isDebugEnabled()){
48+
if (SDK_CORE_LOGGER.matches(LogLevel.LOG_DEBUG_WITH_REQUEST_ID) || SDK_CORE_LOGGER.isDebugEnabled()){
4949
String responseState = response.isSuccessful() ? "successful" : "failed";
50-
REQUEST_ID_LOGGER.debug("Received " + responseState + " response: " + response.code() + ", " + "RequestId: " + headers.get(HEAD_LOG_ID));
50+
SDK_CORE_LOGGER.debugRequestID("Received " + responseState + " response: " + response.code() + ", " + "RequestId: " + headers.get(HEAD_LOG_ID));
5151
}
5252

53-
if (REQUEST_LOGGER.isDebugEnabled() || REQUEST_LOGGER.isTraceEnabled()) {
53+
boolean logBody = SDK_CORE_LOGGER.matches(LogLevel.LOG_DEBUG_WITH_RESPONSE_BODY);
54+
if (SDK_CORE_LOGGER.matches(LogLevel.LOG_DEBUG_WITH_RESPONSE)) {
5455
StringBuilder responseInfo = new StringBuilder();
5556
ResponseBody responseBody = response.body();
5657
responseInfo.append(NEW_LINE + "<-- " + protocol(response.protocol()) + ' ' + response.code() + ' '
@@ -61,7 +62,7 @@ private void logResponseLog(Response response, long tookMs) throws IOException {
6162
responseInfo.append(NEW_LINE + headers.name(i) + ": " + headers.value(i));
6263
}
6364

64-
if (!REQUEST_LOGGER.isTraceEnabled() || !HttpEngine.hasBody(response)) {
65+
if (!logBody || !HttpEngine.hasBody(response)) {
6566
responseInfo.append(NEW_LINE + "<-- END HTTP");
6667
} else if (bodyEncoded(response.headers())) {
6768
responseInfo.append(NEW_LINE + "<-- END HTTP (encoded body omitted)");
@@ -83,34 +84,33 @@ private void logResponseLog(Response response, long tookMs) throws IOException {
8384

8485
responseInfo.append(NEW_LINE + "<-- END HTTP (" + buffer.size() + "-byte body)");
8586
}
86-
REQUEST_LOGGER.debug(responseInfo::toString);
87-
REQUEST_LOGGER.trace(responseInfo::toString);
87+
88+
if (logBody){
89+
SDK_CORE_LOGGER.debugResponseBody(responseInfo.toString());
90+
}else {
91+
SDK_CORE_LOGGER.debugResponse(responseInfo.toString());
92+
}
93+
8894
}
8995

9096
}
9197

9298
private void logRequestLog(Chain chain) throws IOException {
9399

94-
REQUEST_ID_LOGGER.debug(()->{
95-
Request request = chain.request();
96-
Connection connection = chain.connection();
97-
Protocol protocol = connection != null ? connection.getProtocol() : Protocol.HTTP_1_1;
98-
return request.method() + ' ' + request.httpUrl() + ' ' + protocol(protocol);
99-
});
100-
101-
if (REQUEST_LOGGER.isDebugEnabled()){
100+
boolean logBody = SDK_CORE_LOGGER.matches(LogLevel.LOG_DEBUG_WITH_REQUEST_BODY);
101+
if (SDK_CORE_LOGGER.matches(LogLevel.LOG_DEBUG_WITH_REQUEST)){
102102
Request request = chain.request();
103103
RequestBody requestBody = request.body();
104104
boolean hasRequestBody = requestBody != null;
105105
Connection connection = chain.connection();
106106
Protocol protocol = connection != null ? connection.getProtocol() : Protocol.HTTP_1_1;
107107
StringBuilder requestLog = new StringBuilder();
108108
requestLog.append("--> " + request.method() + ' ' + request.httpUrl() + ' ' + protocol(protocol));
109-
if (hasRequestBody) {
109+
if (logBody && hasRequestBody) {
110110
requestLog.append(" (" + requestBody.contentLength() + "-byte body)");
111111
}
112112

113-
if (hasRequestBody) {
113+
if (logBody && hasRequestBody) {
114114
// Request body headers are only present when installed as a network interceptor. Force
115115
// them to be included (when available) so there values are known.
116116
if (requestBody.contentType() != null) {
@@ -130,7 +130,7 @@ private void logRequestLog(Chain chain) throws IOException {
130130
}
131131
}
132132

133-
if (!hasRequestBody) {
133+
if (!hasRequestBody || !logBody) {
134134
requestLog.append(NEW_LINE + "--> END " + request.method());
135135
} else if (bodyEncoded(request.headers())) {
136136
requestLog.append(NEW_LINE + "--> END " + request.method() + " (encoded body omitted)");
@@ -150,7 +150,12 @@ private void logRequestLog(Chain chain) throws IOException {
150150
requestLog.append("--> END " + request.method()
151151
+ " (" + requestBody.contentLength() + "-byte body)");
152152
}
153-
REQUEST_LOGGER.debug(requestLog.toString());
153+
if (logBody && hasRequestBody) {
154+
SDK_CORE_LOGGER.debugRequestBody(requestLog.toString());
155+
}else {
156+
SDK_CORE_LOGGER.debugRequest(requestLog.toString());
157+
}
158+
154159
}
155160
}
156161

0 commit comments

Comments
 (0)