From ee474ee590924f88dd9ddc32f29686d8a4c7155e Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Tue, 3 Nov 2026 12:38:42 +0800 Subject: [PATCH 1/3] fix(multimodal): ignore outputless SSE metadata frames --- pom.xml | 2 +- .../java/com/alibaba/dashscope/Version.java | 2 +- .../MultiModalConversation.java | 25 ++++++++++++ .../dashscope/common/DashScopeResult.java | 25 ++++++++++++ .../dashscope/TestMultiModalConversation.java | 39 +++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6ec5f87f..f74b3719 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ DashScope Java SDK com.alibaba dashscope-sdk-java - 2.23.4 + 2.23.5 8 diff --git a/src/main/java/com/alibaba/dashscope/Version.java b/src/main/java/com/alibaba/dashscope/Version.java index ecb9a44c..ed90f43b 100644 --- a/src/main/java/com/alibaba/dashscope/Version.java +++ b/src/main/java/com/alibaba/dashscope/Version.java @@ -3,5 +3,5 @@ package com.alibaba.dashscope; public final class Version { - public static final String version = "2.23.4"; + public static final String version = "2.23.5"; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java index d0c2d87a..56103dd5 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java +++ b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java @@ -167,6 +167,7 @@ public Flowable streamCall(MultiModalConversationP preprocessInput(param); return syncApi .streamCall(param) + .filter(MultiModalConversation::shouldEmitStreamResult) .map(MultiModalConversationResult::fromDashScopeResult) .map(result -> mergeSingleResponse(result, toMergeResponse)) .doOnComplete( @@ -214,6 +215,9 @@ public void streamCall( new ResultCallback() { @Override public void onEvent(DashScopeResult msg) { + if (!shouldEmitStreamResult(msg)) { + return; + } MultiModalConversationResult result = MultiModalConversationResult.fromDashScopeResult(msg); MultiModalConversationResult mergedResult = @@ -239,6 +243,27 @@ public void onError(Exception e) { }); } + /** + * The new gateway may emit usage/search/metadata SSE frames without a model output. They are + * successful auxiliary frames, not failed model results. Keep frames carrying an output or an + * explicit business error, and silently skip successful auxiliary frames. + */ + private static boolean shouldEmitStreamResult(DashScopeResult result) { + if (result.getOutput() != null) { + return true; + } + String code = result.getCode(); + boolean hasError = code != null && !code.isEmpty(); + if (!hasError) { + log.debug( + "Ignore streaming event without output: event={}, requestId={}, usagePresent={}", + result.getEvent(), + result.getRequestId(), + result.getUsage() != null); + } + return hasError; + } + private void preprocessInput(MultiModalConversationParam param) throws NoApiKeyException, UploadFileException { boolean hasUpload = false; diff --git a/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java b/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java index c7eab7ab..7911f8d7 100644 --- a/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java +++ b/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java @@ -35,6 +35,7 @@ public Boolean isBinaryOutput() { protected T fromResponse(Protocol protocol, NetworkResponse response) throws ApiException { this.setHeaders(changeHeaders(response.getHeaders())); + fillRequestIdFromHeaders(); if (protocol == Protocol.WEBSOCKET) { if (response.getBinary() == null) { String message = response.getMessage(); @@ -83,6 +84,7 @@ public T fromResponse( return fromResponse(protocol, response); } this.setHeaders(changeHeaders(response.getHeaders())); + fillRequestIdFromHeaders(); if (protocol == Protocol.WEBSOCKET) { if (response.getBinary() == null) { this.output = parseJson(response.getMessage(), "Failed to parse WebSocket message"); @@ -112,6 +114,7 @@ public T fromResponse( Protocol protocol, NetworkResponse response, boolean isFlattenResult, HalfDuplexRequest req) throws ApiException { this.setHeaders(changeHeaders(response.getHeaders())); + fillRequestIdFromHeaders(); if ((response.getHeaders().containsKey("X-DashScope-OutputEncrypted".toLowerCase()) || req.isEncryptRequest()) && protocol == Protocol.HTTP) { @@ -263,4 +266,26 @@ private Map changeHeaders(Map> headers) { (v1, v2) -> v1, java.util.LinkedHashMap::new)); } + + private void fillRequestIdFromHeaders() { + if (getRequestId() != null && !getRequestId().isEmpty()) { + return; + } + Map headers = getHeaders(); + if (headers == null) { + return; + } + for (Map.Entry entry : headers.entrySet()) { + String name = entry.getKey(); + if ("x-request-id".equalsIgnoreCase(name) + || "x-dashscope-requestid".equalsIgnoreCase(name) + || "x-dashscope-request-id".equalsIgnoreCase(name)) { + String value = entry.getValue() == null ? null : String.valueOf(entry.getValue()); + if (value != null && !value.isEmpty()) { + setRequestId(value); + return; + } + } + } + } } diff --git a/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java b/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java index 02ebe136..3f7de517 100644 --- a/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java +++ b/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java @@ -3,6 +3,7 @@ package com.alibaba.dashscope; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationMessage; @@ -19,6 +20,7 @@ import com.alibaba.dashscope.utils.Constants; import java.io.IOException; import java.util.Arrays; +import java.util.List; import lombok.extern.slf4j.Slf4j; import okhttp3.MediaType; import okhttp3.mockwebserver.MockResponse; @@ -97,4 +99,41 @@ public void testSendAndReceive() assertEquals(request.getMethod(), "POST"); assertEquals(request.getPath(), "/services/aigc/multimodal-generation/generation"); } + + @Test + public void testStreamIgnoresUsageOnlyFrameAndUsesHeaderRequestId() + throws ApiException, NoApiKeyException, UploadFileException { + server.enqueue( + new MockResponse() + .setHeader("content-type", "text/event-stream") + .setHeader("x-request-id", "request-from-header") + .setBody( + "data: {\"usage\":{\"input_tokens\":26,\"output_tokens\":0}}\n\n" + + "data: {\"output\":{\"choices\":[{\"finish_reason\":\"stop\"," + + "\"message\":{\"role\":\"assistant\"," + + "\"content\":[{\"text\":\"正常结果\"}]}}]}," + + "\"usage\":{\"input_tokens\":26,\"output_tokens\":4}}\n\n" + + "data: [DONE]\n\n")); + Constants.baseHttpApiUrl = String.format("http://127.0.0.1:%s", server.getPort()); + MultiModalConversationParam param = + MultiModalConversationParam.builder() + .model("qwen3.7-plus") + .message( + MultiModalConversationMessage.builder() + .role(Role.USER.getValue()) + .content(Arrays.asList(new MultiModalMessageItemText("检查材料"))) + .build()) + .build(); + + List results = + new MultiModalConversation().streamCall(param).toList().blockingGet(); + + assertEquals(1, results.size()); + MultiModalConversationResult result = results.get(0); + assertEquals("request-from-header", result.getRequestId()); + assertNotNull(result.getOutput()); + assertEquals( + "正常结果", + result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text")); + } } From 1baaeb2f22903c070d0948506019e927887d4211 Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Tue, 3 Nov 2026 15:21:04 +0800 Subject: [PATCH 2/3] fix(logging): include request IDs in request diagnostics Propagate request IDs through HTTP/SSE, WebSocket, and audio logs so users can correlate failures with service requests. Add regression coverage for header, body, task ID, and unknown fallbacks. --- .../resource/AgentStudioEventStream.java | 16 +- .../codegeneration/CodeGenerationResult.java | 6 +- .../aigc/generation/GenerationResult.java | 6 +- .../ImageGenerationListResult.java | 5 +- .../ImageGenerationResult.java | 5 +- .../ImageSynthesisListResult.java | 6 +- .../imagesynthesis/ImageSynthesisResult.java | 6 +- .../MultiModalConversation.java | 2 +- .../MultiModalConversationResult.java | 5 +- .../VideoSynthesisListResult.java | 5 +- .../videosynthesis/VideoSynthesisResult.java | 5 +- .../dashscope/app/ApplicationResult.java | 6 +- .../audio/asr/recognition/Recognition.java | 85 ++++++--- .../TranslationRecognizerChat.java | 50 +++-- .../TranslationRecognizerRealtime.java | 82 +++++--- .../audio/http_tts/HttpSpeechSynthesizer.java | 67 ++++++- .../audio/omni/OmniRealtimeConversation.java | 57 ++++-- .../audio/protocol/AudioWebsocketRequest.java | 59 +++++- .../qwen_tts_realtime/QwenTtsRealtime.java | 40 ++-- .../audio/tts/SpeechSynthesizer.java | 79 ++++++-- .../audio/ttsv2/SpeechSynthesizer.java | 160 ++++++++++------ .../audio/ttsv2/SpeechSynthesizerV2.java | 80 ++++++-- .../dashscope/common/DashScopeResult.java | 28 +-- .../com/alibaba/dashscope/common/Result.java | 4 + .../multimodal/MultiModalDialog.java | 36 +++- .../multimodal/tingwu/TingWuRealtime.java | 22 ++- .../understanding/UnderstandingResult.java | 6 +- .../dashscope/protocol/DashScopeHeaders.java | 30 +++ .../protocol/okhttp/LoggingInterceptor.java | 16 +- .../protocol/okhttp/OkHttpHttpClient.java | 33 +++- .../okhttp/OkHttpWebSocketClient.java | 178 ++++++++++++++---- .../okhttp/OkHttpWebSocketClientForAudio.java | 5 +- .../dashscope/rerank/TextReRankResult.java | 5 +- .../dashscope/task/AsyncTaskListResult.java | 6 +- .../tokenizers/TokenizationResult.java | 6 +- .../TestDashScopeResultEmptyBody.java | 42 +++++ .../dashscope/TestMultiModalConversation.java | 62 +++++- .../protocol/TestDashScopeHeaders.java | 21 +++ .../okhttp/TestWebSocketRequestIdLogging.java | 154 +++++++++++++++ 39 files changed, 1180 insertions(+), 306 deletions(-) create mode 100644 src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java diff --git a/src/main/java/com/alibaba/dashscope/agentstudio/resource/AgentStudioEventStream.java b/src/main/java/com/alibaba/dashscope/agentstudio/resource/AgentStudioEventStream.java index 24651acf..02068df9 100644 --- a/src/main/java/com/alibaba/dashscope/agentstudio/resource/AgentStudioEventStream.java +++ b/src/main/java/com/alibaba/dashscope/agentstudio/resource/AgentStudioEventStream.java @@ -5,6 +5,7 @@ import com.alibaba.dashscope.agentstudio.message.Message; import com.alibaba.dashscope.common.Status; import com.alibaba.dashscope.exception.ApiException; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; @@ -92,6 +93,7 @@ private static ApiException wrapFailure(Throwable t, Response response) { return null; } int code = response.code(); + String requestId = DashScopeHeaders.findRequestId(response.headers().toMultimap()); String body = ""; String errorCode = null; String errorMsg = null; @@ -100,24 +102,34 @@ private static ApiException wrapFailure(Throwable t, Response response) { body = rb.string(); } } catch (IOException e) { - log.debug("Failed to read SSE failure response body", e); + log.debug( + "Failed to read SSE failure response body, requestId={}", + DashScopeHeaders.requestIdOrUnknown(requestId), + e); } // Parse the agentstudio error envelope {type:error, error:{code,message}} // to surface the server's actual error code instead of a generic one. if (body != null && !body.isEmpty()) { try { JsonObject parsed = GSON.fromJson(body, JsonObject.class); + if (parsed != null && parsed.has("request_id")) { + requestId = parsed.get("request_id").getAsString(); + } if (parsed != null && parsed.has("error") && parsed.get("error").isJsonObject()) { JsonObject errObj = parsed.getAsJsonObject("error"); if (errObj.has("code")) errorCode = errObj.get("code").getAsString(); if (errObj.has("message")) errorMsg = errObj.get("message").getAsString(); } } catch (Exception e) { - log.debug("Failed to parse SSE error body as JSON", e); + log.debug( + "Failed to parse SSE error body as JSON, requestId={}", + DashScopeHeaders.requestIdOrUnknown(requestId), + e); } } Status status = Status.builder() + .requestId(requestId) .statusCode(code) .code( errorCode != null diff --git a/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java b/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java index 5ed5882d..cc37e06d 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java @@ -33,7 +33,11 @@ public static CodeGenerationResult fromDashScopeResult(DashScopeResult dashScope JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), CodeGenerationOutput.class)); } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java b/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java index cc270dba..30818219 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java @@ -43,7 +43,11 @@ public static GenerationResult fromDashScopeResult(DashScopeResult dashScopeResu JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), GenerationOutput.class)); } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationListResult.java b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationListResult.java index 0c5ff9f3..a02a1dc2 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationListResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationListResult.java @@ -46,7 +46,10 @@ public static ImageGenerationListResult fromDashScopeResult(DashScopeResult dash rs.message = dashScopeResult.getMessage(); return rs; } else { - log.error("Result no output: {}", dashScopeResult); + log.error( + "Result no output: {}, requestId={}", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown()); } return null; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationResult.java b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationResult.java index 69093b0f..90f5d615 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagegeneration/ImageGenerationResult.java @@ -41,7 +41,10 @@ public static ImageGenerationResult fromDashScopeResult(DashScopeResult dashScop JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), ImageGenerationOutput.class)); } else { - log.error("Result no output: {}", dashScopeResult); + log.error( + "Result no output: {}, requestId={}", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown()); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java index f513704e..e7caf33b 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java @@ -46,7 +46,11 @@ public static ImageSynthesisListResult fromDashScopeResult(DashScopeResult dashS rs.message = dashScopeResult.getMessage(); return rs; } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return null; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java index 74a8a4fa..f8b868b3 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java @@ -46,7 +46,11 @@ public static ImageSynthesisResult fromDashScopeResult(DashScopeResult dashScope JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), ImageSynthesisOutput.class)); } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java index 56103dd5..6b00e085 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java +++ b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversation.java @@ -258,7 +258,7 @@ private static boolean shouldEmitStreamResult(DashScopeResult result) { log.debug( "Ignore streaming event without output: event={}, requestId={}, usagePresent={}", result.getEvent(), - result.getRequestId(), + result.getRequestIdOrUnknown(), result.getUsage() != null); } return hasError; diff --git a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationResult.java b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationResult.java index 309ddc0f..b0f84c71 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/multimodalconversation/MultiModalConversationResult.java @@ -41,7 +41,10 @@ public static MultiModalConversationResult fromDashScopeResult(DashScopeResult d JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), MultiModalConversationOutput.class)); } else { - log.error("Result no output: {}", dashScopeResult); + log.error( + "Result no output: {}, requestId={}", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown()); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisListResult.java b/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisListResult.java index c5ecbc24..a24a2114 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisListResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisListResult.java @@ -45,7 +45,10 @@ public static VideoSynthesisListResult fromDashScopeResult(DashScopeResult dashS rs.message = dashScopeResult.getMessage(); return rs; } else { - log.error("Result no output: {}", dashScopeResult); + log.error( + "Result no output: {}, requestId={}", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown()); } return null; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisResult.java b/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisResult.java index 4cf6a430..aca91c5f 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/videosynthesis/VideoSynthesisResult.java @@ -46,7 +46,10 @@ public static VideoSynthesisResult fromDashScopeResult(DashScopeResult dashScope (JsonObject) dashScopeResult.getOutput(), VideoSynthesisOutput.class); result.setOutput(outputTemp); } else { - log.error("Result no output: {}", dashScopeResult); + log.error( + "Result no output: {}, requestId={}", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown()); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java b/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java index 1d5260d4..cb69eb9e 100644 --- a/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java +++ b/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java @@ -61,7 +61,11 @@ public static ApplicationResult fromDashScopeResult(DashScopeResult dashScopeRes JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), ApplicationOutput.class)); } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return result; diff --git a/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java b/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java index c6c811e5..435cf179 100644 --- a/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java +++ b/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java @@ -10,6 +10,7 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; import com.alibaba.dashscope.protocol.ConnectionOptions; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; import com.google.gson.Gson; @@ -59,6 +60,10 @@ private static class AsyncCmdBuffer { private String preRequestId = null; + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } + @SuperBuilder private static class RecognitionParamWithStream extends RecognitionParam { @@ -163,7 +168,10 @@ public Flowable streamCall( if (startStreamTimeStamp < 0) { startStreamTimeStamp = System.currentTimeMillis(); } - log.debug("send audio frame: " + buffer.remaining()); + log.debug( + "send audio frame: {}, requestId={}", + buffer.remaining(), + getRequestIdForLog()); }), preRequestId)) .doOnComplete( @@ -190,18 +198,24 @@ public Flowable streamCall( && result.getSentence().getText() != null && !result.getSentence().getText().isEmpty()) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "Recv Result: " - + result.getSentence().getText() - + ", isEnd: " - + result.isSentenceEnd()); + "Recv Result: {}, isEnd: {}, requestId={}", + result.getSentence().getText(), + result.isSentenceEnd(), + getRequestIdForLog()); }) .doOnComplete( () -> { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); }); } @@ -250,27 +264,30 @@ public void call(RecognitionParam param, ResultCallback callb @Override public void onEvent(DashScopeResult message) { RecognitionResult recognitionResult = RecognitionResult.fromDashScopeResult(message); + if (lastRequestId.get() == null && recognitionResult.getRequestId() != null) { + lastRequestId.set(recognitionResult.getRequestId()); + } if (recognitionResult.getSentence() != null && recognitionResult.getSentence().isHeartbeat()) { - log.debug("recv heartbeat"); + log.debug("recv heartbeat, requestId={}", getRequestIdForLog()); return; } - if (lastRequestId.get() == null && recognitionResult.getRequestId() != null) { - lastRequestId.set(recognitionResult.getRequestId()); - } if (!recognitionResult.isCompleteResult()) { if (firstPackageTimeStamp < 0 && recognitionResult.getSentence() != null && recognitionResult.getSentence().getText() != null && !recognitionResult.getSentence().getText().isEmpty()) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "Recv Result: " - + recognitionResult.getSentence().getText() - + ", isEnd: " - + recognitionResult.isSentenceEnd()); + "Recv Result: {}, isEnd: {}, requestId={}", + recognitionResult.getSentence().getText(), + recognitionResult.isSentenceEnd(), + getRequestIdForLog()); callback.onEvent(recognitionResult); } } @@ -278,7 +295,10 @@ public void onEvent(DashScopeResult message) { @Override public void onComplete() { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); synchronized (Recognition.this) { state = RecognitionState.IDLE; } @@ -309,7 +329,7 @@ public void onError(Exception e) { stopLatch.get().countDown(); } } - log.debug("Recognition started"); + log.debug("Recognition started, requestId={}", getRequestIdForLog()); } public String call(RecognitionParam param, File file) { @@ -361,31 +381,37 @@ public String call(RecognitionParam param, File file) { .doOnComplete( () -> { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); }) .blockingSubscribe( res -> { RecognitionResult recognitionResult = RecognitionResult.fromDashScopeResult(res); - if (recognitionResult.getSentence().isHeartbeat()) { - log.debug("recv heartbeat"); - return; - } if (lastRequestId.get() == null && recognitionResult.getRequestId() != null) { lastRequestId.set(recognitionResult.getRequestId()); } + if (recognitionResult.getSentence().isHeartbeat()) { + log.debug("recv heartbeat, requestId={}", getRequestIdForLog()); + return; + } if (!recognitionResult.isCompleteResult() && recognitionResult.getSentence() != null && recognitionResult.getSentence().getText() != null && !recognitionResult.getSentence().getText().isEmpty()) { if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "Recv Result: " - + recognitionResult.getSentence().getText() - + ", isEnd: " - + recognitionResult.isSentenceEnd()); + "Recv Result: {}, isEnd: {}, requestId={}", + recognitionResult.getSentence().getText(), + recognitionResult.isSentenceEnd(), + getRequestIdForLog()); sentenceList.add(recognitionResult.getSentence()); } }, @@ -416,7 +442,8 @@ public void sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug("send audio frame: " + audioFrame.remaining()); + log.debug( + "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (state != RecognitionState.RECOGNITION_STARTED) { throw new ApiException( diff --git a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java index 0c74dca8..e548156a 100644 --- a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java +++ b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java @@ -10,6 +10,7 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; import com.alibaba.dashscope.protocol.ConnectionOptions; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; import io.reactivex.BackpressureStrategy; @@ -55,6 +56,11 @@ private static class AsyncCmdBuffer { private AtomicBoolean isSentenceEnd = new AtomicBoolean(false); private AtomicBoolean stopped = new AtomicBoolean(false); private String preRequestId = null; + private AtomicReference lastRequestId = new AtomicReference<>(null); + + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } @SuperBuilder private static class TranslationRecognizerParamWithStream extends TranslationRecognizerParam { @@ -197,18 +203,26 @@ public void call( public void onEvent(DashScopeResult message) { TranslationRecognizerResult translationRecognizerResult = TranslationRecognizerResult.fromDashScopeResult(message); + if (translationRecognizerResult.getRequestId() != null + && !translationRecognizerResult.getRequestId().isEmpty()) { + lastRequestId.set(translationRecognizerResult.getRequestId()); + } if (!translationRecognizerResult.isCompleteResult()) { if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "[Recv Result] transcription: " - + translationRecognizerResult.getTranslationResult() - + " translation: " - + translationRecognizerResult.getTranscriptionResult()); + "[Recv Result] transcription: {}, translation: {}, requestId={}", + translationRecognizerResult.getTranslationResult(), + translationRecognizerResult.getTranscriptionResult(), + getRequestIdForLog()); if (translationRecognizerResult.isSentenceEnd()) { - log.debug("[Chat] recv sentence end, stop asr"); + log.debug( + "[Chat] recv sentence end, stop asr, requestId={}", getRequestIdForLog()); isSentenceEnd.set(true); } callback.onEvent(translationRecognizerResult); @@ -218,7 +232,10 @@ public void onEvent(DashScopeResult message) { @Override public void onComplete() { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); synchronized (TranslationRecognizerChat.this) { state = TranslationRecognizerState.IDLE; } @@ -249,7 +266,10 @@ public void onError(Exception e) { stopLatch.get().countDown(); } } - log.debug("TranslationRecognizerChat started, state is {}", state.getValue()); + log.debug( + "TranslationRecognizerChat started, state is {}, requestId={}", + state.getValue(), + getRequestIdForLog()); } /** @@ -263,7 +283,7 @@ public void onError(Exception e) { */ public boolean sendAudioFrame(ByteBuffer audioFrame) { if (isSentenceEnd.get()) { - log.debug("skip audio due to has sentence end"); + log.debug("skip audio due to has sentence end, requestId={}", getRequestIdForLog()); return false; } if (audioFrame == null) { @@ -272,7 +292,8 @@ public boolean sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug("send audio frame: " + audioFrame.remaining()); + log.debug( + "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (state != TranslationRecognizerState.SPEECH_TRANSLATION_STARTED) { throw new ApiException( @@ -295,10 +316,12 @@ public boolean sendAudioFrame(ByteBuffer audioFrame) { public void stop() { this.stopStreamTimeStamp = System.currentTimeMillis(); if (stopped.get()) { - log.debug("TranslationRecognizerChat has already been stopped, skip"); + log.debug( + "TranslationRecognizerChat has already been stopped, skip, requestId={}", + getRequestIdForLog()); return; } - log.debug("stop TranslationRecognizerChat"); + log.debug("stop TranslationRecognizerChat, requestId={}", getRequestIdForLog()); synchronized (this) { if (state != TranslationRecognizerState.SPEECH_TRANSLATION_STARTED) { throw new ApiException( @@ -314,7 +337,7 @@ public void stop() { if (stopLatch.get() != null) { try { - log.debug("start waiting for task-finished"); + log.debug("start waiting for task-finished, requestId={}", getRequestIdForLog()); stopLatch.get().await(); } catch (InterruptedException ignored) { } @@ -333,6 +356,7 @@ private void reset() { this.isSentenceEnd.set(false); this.stopped.set(false); this.preRequestId = null; + this.lastRequestId.set(null); } /** First Package Delay is the time between start sending audio and receive first words package */ diff --git a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java index 04cfb27c..f06f7fba 100644 --- a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java +++ b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java @@ -11,6 +11,7 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; import com.alibaba.dashscope.protocol.ConnectionOptions; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; import io.reactivex.BackpressureStrategy; @@ -57,6 +58,11 @@ private static class AsyncCmdBuffer { private long stopStreamTimeStamp = -1; private long onCompleteTimeStamp = -1; private String preRequestId = null; + private AtomicReference lastRequestId = new AtomicReference<>(null); + + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } @SuperBuilder private static class TranslationRecognizerParamWithStream extends TranslationRecognizerParam { @@ -164,7 +170,10 @@ public Flowable streamCall( if (startStreamTimeStamp < 0) { startStreamTimeStamp = System.currentTimeMillis(); } - log.debug("send audio frame: " + buffer.remaining()); + log.debug( + "send audio frame: {}, requestId={}", + buffer.remaining(), + getRequestIdForLog()); }), preRequestId)) .doOnComplete( @@ -183,20 +192,29 @@ public Flowable streamCall( && !item.isCompleteResult()) .doOnNext( result -> { + if (result.getRequestId() != null && !result.getRequestId().isEmpty()) { + lastRequestId.set(result.getRequestId()); + } if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "[Recv Result] transcription: " - + result.getTranslationResult() - + " translation: " - + result.getTranscriptionResult()); + "[Recv Result] transcription: {}, translation: {}, requestId={}", + result.getTranslationResult(), + result.getTranscriptionResult(), + getRequestIdForLog()); }) .doOnComplete( () -> { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); }); } @@ -256,16 +274,23 @@ public void call( public void onEvent(DashScopeResult message) { TranslationRecognizerResult translationRecognizerResult = TranslationRecognizerResult.fromDashScopeResult(message); + if (translationRecognizerResult.getRequestId() != null + && !translationRecognizerResult.getRequestId().isEmpty()) { + lastRequestId.set(translationRecognizerResult.getRequestId()); + } if (!translationRecognizerResult.isCompleteResult()) { if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "[Recv Result] transcription: " - + translationRecognizerResult.getTranslationResult() - + " translation: " - + translationRecognizerResult.getTranscriptionResult()); + "[Recv Result] transcription: {}, translation: {}, requestId={}", + translationRecognizerResult.getTranslationResult(), + translationRecognizerResult.getTranscriptionResult(), + getRequestIdForLog()); callback.onEvent(translationRecognizerResult); } } @@ -273,7 +298,10 @@ public void onEvent(DashScopeResult message) { @Override public void onComplete() { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); synchronized (TranslationRecognizerRealtime.this) { state = TranslationRecognizerState.IDLE; } @@ -304,7 +332,7 @@ public void onError(Exception e) { stopLatch.get().countDown(); } } - log.debug("TranslationRecognizerRealtime started"); + log.debug("TranslationRecognizerRealtime started, requestId={}", getRequestIdForLog()); } /** @@ -362,23 +390,33 @@ public TranslationRecognizerResultPack call(TranslationRecognizerParam param, Fi .doOnComplete( () -> { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); }) .blockingSubscribe( res -> { TranslationRecognizerResult translationRecognizerResult = TranslationRecognizerResult.fromDashScopeResult(res); + if (translationRecognizerResult.getRequestId() != null + && !translationRecognizerResult.getRequestId().isEmpty()) { + lastRequestId.set(translationRecognizerResult.getRequestId()); + } if (!translationRecognizerResult.isCompleteResult() && translationRecognizerResult.isSentenceEnd()) { if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("first package delay: " + getFirstPackageDelay()); + log.debug( + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( - "[Recv SentenceEnd]: transcription" - + translationRecognizerResult.getTranslationResult() - + ", translation: " - + translationRecognizerResult.getTranscriptionResult()); + "[Recv SentenceEnd]: transcription {}, translation: {}, requestId={}", + translationRecognizerResult.getTranslationResult(), + translationRecognizerResult.getTranscriptionResult(), + getRequestIdForLog()); results.setRequestId(translationRecognizerResult.getRequestId()); results .getTranslationResultList() @@ -418,7 +456,8 @@ public void sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug("send audio frame: " + audioFrame.remaining()); + log.debug( + "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (state != TranslationRecognizerState.SPEECH_TRANSLATION_STARTED) { throw new ApiException( @@ -471,6 +510,7 @@ private void reset() { this.stopStreamTimeStamp = -1; this.onCompleteTimeStamp = -1; preRequestId = null; + lastRequestId.set(null); } /** First Package Delay is the time between start sending audio and receive first words package */ diff --git a/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java b/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java index 2dde1ac7..2f67974a 100644 --- a/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java +++ b/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java @@ -10,6 +10,7 @@ import com.alibaba.dashscope.exception.InputRequiredException; import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.HttpMethod; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; @@ -38,6 +39,20 @@ public class HttpSpeechSynthesizer { /** Creates a new HttpSpeechSynthesizer instance with default settings. */ public HttpSpeechSynthesizer() {} + + private static String getRequestIdForLog(String requestId, Exception error) { + if (requestId != null && !requestId.isEmpty()) { + return requestId; + } + if (error instanceof ApiException) { + Status status = ((ApiException) error).getStatus(); + if (status != null) { + return DashScopeHeaders.requestIdOrUnknown(status.getRequestId()); + } + } + return "unknown"; + } + /** Creates a per-request ApiServiceOption with the specified SSE setting. */ private SynchronizeHalfDuplexApi createApi(boolean isSSE) { ApiServiceOption serviceOption = @@ -87,11 +102,15 @@ public HttpSpeechSynthesisResult call(HttpSpeechSynthesisParam param) throws ApiException, NoApiKeyException, InputRequiredException { param.validate(); SynchronizeHalfDuplexApi api = createApi(false); + DashScopeResult result = null; try { - DashScopeResult result = api.call(param); + result = api.call(param); return convertNonSSEResult(result); } catch (Exception e) { - log.error("Synchronous speech synthesis failed", e); + log.error( + "Synchronous speech synthesis failed, requestId={}", + getRequestIdForLog(result == null ? null : result.getRequestId(), e), + e); throw new ApiException(e); } } @@ -111,6 +130,7 @@ public void streamCall( throws ApiException, NoApiKeyException, InputRequiredException { param.validate(); SynchronizeHalfDuplexApi api = createApi(true); + AtomicReference requestId = new AtomicReference<>(null); try { api.streamCall( @@ -118,13 +138,19 @@ public void streamCall( new ResultCallback() { @Override public void onEvent(DashScopeResult message) { + if (message.getRequestId() != null && !message.getRequestId().isEmpty()) { + requestId.set(message.getRequestId()); + } try { HttpSpeechSynthesisResult result = convertResult(message); if (callback != null) { callback.onEvent(result); } } catch (Exception e) { - log.error("Failed to process audio result", e); + log.error( + "Failed to process audio result, requestId={}", + DashScopeHeaders.requestIdOrUnknown(requestId.get()), + e); if (callback != null) { callback.onError(e); } @@ -146,7 +172,8 @@ public void onError(Exception e) { } }); } catch (Exception e) { - log.error("Streaming call failed", e); + log.error( + "Streaming call failed, requestId={}", getRequestIdForLog(requestId.get(), e), e); throw new ApiException(e); } } @@ -167,12 +194,16 @@ public ByteBuffer callAndReturnAudio(HttpSpeechSynthesisParam param) ByteArrayOutputStream audioBuffer = new ByteArrayOutputStream(); CountDownLatch latch = new CountDownLatch(1); AtomicReference callbackError = new AtomicReference<>(); + AtomicReference requestId = new AtomicReference<>(null); streamCall( param, new ResultCallback() { @Override public void onEvent(HttpSpeechSynthesisResult result) { + if (result.getRequestId() != null && !result.getRequestId().isEmpty()) { + requestId.set(result.getRequestId()); + } try { if (result.getAudioData() != null) { audioBuffer.write(result.getAudioData()); @@ -216,7 +247,8 @@ public void onError(Exception e) { } catch (ApiException e) { throw e; } catch (Exception e) { - log.error("Failed to get audio data", e); + log.error( + "Failed to get audio data, requestId={}", getRequestIdForLog(requestId.get(), e), e); throw new ApiException(e); } } @@ -256,7 +288,10 @@ private HttpSpeechSynthesisResult convertResult(DashScopeResult dashScopeResult) dashScopeResult.getUsage().getAsJsonObject(), SpeechSynthesisUsage.class); result.setUsage(usage); } catch (Exception e) { - log.debug("Failed to parse usage information", e); + log.debug( + "Failed to parse usage information, requestId={}", + dashScopeResult.getRequestIdOrUnknown(), + e); } } @@ -290,7 +325,10 @@ private byte[] extractAudioData(DashScopeResult result) { try { return Base64.getDecoder().decode(audioBase64); } catch (IllegalArgumentException e) { - log.warn("Failed to decode Base64 audio data", e); + log.warn( + "Failed to decode Base64 audio data, requestId={}", + result.getRequestIdOrUnknown(), + e); } } } else if (audioElement.isJsonObject()) { @@ -302,7 +340,10 @@ private byte[] extractAudioData(DashScopeResult result) { try { return Base64.getDecoder().decode(audioBase64); } catch (IllegalArgumentException e) { - log.warn("Failed to decode Base64 audio data from audio.data", e); + log.warn( + "Failed to decode Base64 audio data from audio.data, requestId={}", + result.getRequestIdOrUnknown(), + e); } } } @@ -316,7 +357,10 @@ private byte[] extractAudioData(DashScopeResult result) { try { return Base64.getDecoder().decode(binaryBase64); } catch (IllegalArgumentException e) { - log.warn("Failed to decode Base64 binary data", e); + log.warn( + "Failed to decode Base64 binary data, requestId={}", + result.getRequestIdOrUnknown(), + e); } } } @@ -397,7 +441,10 @@ private HttpSpeechSynthesisResult convertNonSSEResult(DashScopeResult dashScopeR dashScopeResult.getUsage().getAsJsonObject(), SpeechSynthesisUsage.class); result.setUsage(usage); } catch (Exception e) { - log.debug("Failed to parse usage information", e); + log.debug( + "Failed to parse usage information, requestId={}", + dashScopeResult.getRequestIdOrUnknown(), + e); } } diff --git a/src/main/java/com/alibaba/dashscope/audio/omni/OmniRealtimeConversation.java b/src/main/java/com/alibaba/dashscope/audio/omni/OmniRealtimeConversation.java index 0392302a..913d7232 100644 --- a/src/main/java/com/alibaba/dashscope/audio/omni/OmniRealtimeConversation.java +++ b/src/main/java/com/alibaba/dashscope/audio/omni/OmniRealtimeConversation.java @@ -40,6 +40,20 @@ public class OmniRealtimeConversation extends WebSocketListener { private long lastFirstTextDelay = -1; private AtomicBoolean isClosed = new AtomicBoolean(false); private final AtomicReference disconnectLatch = new AtomicReference<>(null); + private volatile String requestId; + + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(requestId); + } + + private void updateRequestIdFromResponse(Response response) { + if (response != null && (requestId == null || requestId.isEmpty())) { + String responseRequestId = DashScopeHeaders.findRequestId(response.headers().toMultimap()); + if (responseRequestId != null && !responseRequestId.isEmpty()) { + requestId = responseRequestId; + } + } + } /** * Constructor @@ -160,7 +174,11 @@ public void appendAudio(String audioBase64) { OmniRealtimeConstants.PROTOCOL_TYPE, OmniRealtimeConstants.PROTOCOL_EVENT_TYPE_APPEND_AUDIO); append_request.put(OmniRealtimeConstants.PROTOCOL_AUDIO, audioBase64); - log.debug("append audio with eid: {}, length: {}", event_id, audioBase64.length()); + log.debug( + "append audio with eid: {}, length: {}, requestId={}", + event_id, + audioBase64.length(), + getRequestIdForLog()); sendMessage(createGson().toJson(append_request), false); } @@ -178,7 +196,11 @@ public void appendVideo(String videoBase64) { OmniRealtimeConstants.PROTOCOL_TYPE, OmniRealtimeConstants.PROTOCOL_EVENT_TYPE_APPEND_VIDEO); append_request.put(OmniRealtimeConstants.PROTOCOL_VIDEO, videoBase64); - log.debug("append video with eid: " + event_id + ", length: " + videoBase64.length()); + log.debug( + "append video with eid: {}, length: {}, requestId={}", + event_id, + videoBase64.length(), + getRequestIdForLog()); sendMessage(createGson().toJson(append_request), false); } @@ -337,7 +359,7 @@ private Gson createGson() { private void sendMessage(String message, boolean enableLog) { if (enableLog == true) { - log.debug("send message: " + message); + log.debug("send message: {}, requestId={}", message, getRequestIdForLog()); } Boolean isOk = websocktetClient.send(message); } @@ -349,21 +371,23 @@ private void sendMessage(ByteString message) { /** WebSocket callbacks */ @Override public void onOpen(WebSocket webSocket, Response response) { + updateRequestIdFromResponse(response); isOpen.set(true); CountDownLatch latch = connectLatch.get(); if (latch != null && latch.getCount() > 0) { latch.countDown(); } - log.debug("WebSocket opened"); + log.debug("WebSocket opened, requestId={}", getRequestIdForLog()); callback.onOpen(); } @Override public void onMessage(WebSocket webSocket, String text) { if (text.length() > 1024) { - log.debug("Received message: " + text.substring(0, 1024)); + log.debug( + "Received message: {}, requestId={}", text.substring(0, 1024), getRequestIdForLog()); } else { - log.debug("Received message: " + text); + log.debug("Received message: {}, requestId={}", text, getRequestIdForLog()); } JsonObject response = JsonUtils.parse(text); callback.onEvent(response); @@ -391,16 +415,14 @@ public void onMessage(WebSocket webSocket, String text) { break; case OmniRealtimeConstants.PROTOCOL_RESPONSE_TYPE_RESPONSE_DONE: log.debug( - "[Metric] response: " - + lastResponseId - + ", first text delay: " - + lastFirstTextDelay - + " ms, first audio delay: " - + lastFirstAudioDelay - + " ms"); + "[Metric] response: {}, first text delay: {} ms, first audio delay: {} ms, requestId={}", + lastResponseId, + lastFirstTextDelay, + lastFirstAudioDelay, + getRequestIdForLog()); break; case OmniRealtimeConstants.PROTOCOL_RESPONSE_TYPE_SESSION_FINISHED: - log.info("session: " + sessionId + " finished"); + log.info("session: {} finished, requestId={}", sessionId, getRequestIdForLog()); CountDownLatch latch = disconnectLatch.get(); if (latch != null) { latch.countDown(); @@ -417,12 +439,13 @@ public void onClosed(WebSocket webSocket, int code, String reason) { if (latch != null && latch.getCount() > 0) { latch.countDown(); } - log.debug("WebSocket closed: " + code + ", " + reason); + log.debug("WebSocket closed: {}, {}, requestId={}", code, reason, getRequestIdForLog()); callback.onClose(code, reason); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { + updateRequestIdFromResponse(response); isOpen.set(false); isClosed.set(true); CountDownLatch cLatch = connectLatch.get(); @@ -433,7 +456,7 @@ public void onFailure(WebSocket webSocket, Throwable t, Response response) { if (dLatch != null) { dLatch.countDown(); } - log.error("WebSocket failed: " + t.getMessage(), t); + log.error("WebSocket failed: {}, requestId={}", t.getMessage(), getRequestIdForLog(), t); callback.onError(t); } @@ -441,6 +464,6 @@ public void onFailure(WebSocket webSocket, Throwable t, Response response) { public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { isClosed.set(true); websocktetClient.close(code, reason); - log.debug("WebSocket closing: " + code + ", " + reason); + log.debug("WebSocket closing: {}, {}, requestId={}", code, reason, getRequestIdForLog()); } } diff --git a/src/main/java/com/alibaba/dashscope/audio/protocol/AudioWebsocketRequest.java b/src/main/java/com/alibaba/dashscope/audio/protocol/AudioWebsocketRequest.java index 69375e88..14e8cf33 100644 --- a/src/main/java/com/alibaba/dashscope/audio/protocol/AudioWebsocketRequest.java +++ b/src/main/java/com/alibaba/dashscope/audio/protocol/AudioWebsocketRequest.java @@ -5,6 +5,8 @@ import com.alibaba.dashscope.protocol.okhttp.OkHttpClientFactory; import com.alibaba.dashscope.utils.ApiKey; import com.alibaba.dashscope.utils.Constants; +import com.alibaba.dashscope.utils.JsonUtils; +import com.google.gson.JsonObject; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -20,12 +22,47 @@ public class AudioWebsocketRequest extends WebSocketListener { private OkHttpClient client; private WebSocket websocketClient; + private volatile String requestId; private AtomicBoolean isOpen = new AtomicBoolean(false); private AtomicReference connectLatch = new AtomicReference<>(null); private AtomicBoolean isClosed = new AtomicBoolean(false); private AudioWebsocketCallback callback; private Integer connectTimeout = 5000; + private String getRequestIdOrUnknown() { + return DashScopeHeaders.requestIdOrUnknown(requestId); + } + + private void updateRequestIdFromMessage(String message) { + try { + JsonObject jsonMessage = JsonUtils.fromJson(message, JsonObject.class); + if (jsonMessage == null || !jsonMessage.has("header")) { + return; + } + JsonObject header = jsonMessage.getAsJsonObject("header"); + if (header != null && header.has("task_id") && !header.get("task_id").isJsonNull()) { + String messageRequestId = header.get("task_id").getAsString(); + if (messageRequestId != null && !messageRequestId.isEmpty()) { + this.requestId = messageRequestId; + } + } + } catch (RuntimeException ignored) { + // Preserve support for non-JSON messages; the original message handling reports any error. + } + } + + private void updateRequestIdFromResponse(Response response) { + if (response != null && (requestId == null || requestId.isEmpty())) { + updateRequestId(DashScopeHeaders.findRequestId(response.headers().toMultimap())); + } + } + + private void updateRequestId(String requestId) { + if (requestId != null && !requestId.isEmpty()) { + this.requestId = requestId; + } + } + public boolean isOpen() { return isOpen.get(); } @@ -84,11 +121,14 @@ private Request buildConnectionRequest( private void sendMessage(String message, boolean enableLog) { checkStatus(); + updateRequestIdFromMessage(message); if (enableLog) { - log.debug("send message: " + message); + log.debug("send message: {}, requestId={}", message, getRequestIdOrUnknown()); } if (!websocketClient.send(message)) { - log.warn("Failed to enqueue websocket text message for sending."); + log.warn( + "Failed to enqueue websocket text message for sending. requestId={}", + getRequestIdOrUnknown()); } } @@ -110,29 +150,33 @@ public void sendTextMessage(String message) { public void sendBinaryMessage(ByteString rawData) { checkStatus(); if (!websocketClient.send(rawData)) { - log.warn("Failed to enqueue websocket binary message for sending."); + log.warn( + "Failed to enqueue websocket binary message for sending. requestId={}", + getRequestIdOrUnknown()); } } @Override public void onOpen(WebSocket webSocket, Response response) { + updateRequestIdFromResponse(response); isOpen.set(true); if (connectLatch.get() != null) { connectLatch.get().countDown(); } - log.debug("WebSocket opened"); + log.debug("WebSocket opened, requestId={}", getRequestIdOrUnknown()); callback.onOpen(); } @Override public void onMessage(WebSocket webSocket, String text) { + updateRequestIdFromMessage(text); callback.onMessage(webSocket, text); } @Override public void onMessage(WebSocket webSocket, ByteString bytes) { - log.debug("Received binary message"); + log.debug("Received binary message, requestId={}", getRequestIdOrUnknown()); callback.onMessage(webSocket, bytes.asByteBuffer()); } @@ -143,13 +187,14 @@ public void onClosed(WebSocket webSocket, int code, String reason) { if (connectLatch.get() != null) { connectLatch.get().countDown(); } - log.debug("WebSocket closed"); + log.debug("WebSocket closed, requestId={}", getRequestIdOrUnknown()); callback.onClose(code, reason); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { - log.error("WebSocket failed: " + t); + updateRequestIdFromResponse(response); + log.error("WebSocket failed: {}, requestId={}", t, getRequestIdOrUnknown()); if (connectLatch.get() != null) { connectLatch.get().countDown(); } diff --git a/src/main/java/com/alibaba/dashscope/audio/qwen_tts_realtime/QwenTtsRealtime.java b/src/main/java/com/alibaba/dashscope/audio/qwen_tts_realtime/QwenTtsRealtime.java index ced782fe..d43beced 100644 --- a/src/main/java/com/alibaba/dashscope/audio/qwen_tts_realtime/QwenTtsRealtime.java +++ b/src/main/java/com/alibaba/dashscope/audio/qwen_tts_realtime/QwenTtsRealtime.java @@ -36,6 +36,20 @@ public class QwenTtsRealtime extends WebSocketListener { private long lastFirstTextTime = -1; private long lastFirstAudioDelay = -1; private AtomicBoolean isClosed = new AtomicBoolean(false); + private volatile String requestId; + + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(requestId); + } + + private void updateRequestIdFromResponse(Response response) { + if (response != null && (requestId == null || requestId.isEmpty())) { + String responseRequestId = DashScopeHeaders.findRequestId(response.headers().toMultimap()); + if (responseRequestId != null && !responseRequestId.isEmpty()) { + requestId = responseRequestId; + } + } + } /** * Constructor @@ -236,7 +250,7 @@ private String generateSessionId() { private void sendMessage(String message, boolean enableLog) { if (enableLog == true) { - log.debug("send message: " + message); + log.debug("send message: {}, requestId={}", message, getRequestIdForLog()); } Boolean isOk = websocktetClient.send(message); } @@ -248,18 +262,20 @@ private void sendMessage(ByteString message) { /** WebSocket callbacks */ @Override public void onOpen(WebSocket webSocket, Response response) { + updateRequestIdFromResponse(response); isOpen.set(true); connectLatch.get().countDown(); - log.debug("WebSocket opened"); + log.debug("WebSocket opened, requestId={}", getRequestIdForLog()); callback.onOpen(); } @Override public void onMessage(WebSocket webSocket, String text) { if (text.length() > 1024) { - log.debug("Received message: " + text.substring(0, 1024)); + log.debug( + "Received message: {}, requestId={}", text.substring(0, 1024), getRequestIdForLog()); } else { - log.debug("Received message: " + text); + log.debug("Received message: {}, requestId={}", text, getRequestIdForLog()); } JsonObject response = JsonUtils.parse(text); callback.onEvent(response); @@ -279,11 +295,10 @@ public void onMessage(WebSocket webSocket, String text) { break; case QwenTtsRealtimeConstants.PROTOCOL_RESPONSE_TYPE_RESPONSE_DONE: log.debug( - "[Metric] response: " - + lastResponseId - + ", first audio delay: " - + lastFirstAudioDelay - + " ms"); + "[Metric] response: {}, first audio delay: {} ms, requestId={}", + lastResponseId, + lastFirstAudioDelay, + getRequestIdForLog()); break; } } @@ -293,7 +308,7 @@ public void onMessage(WebSocket webSocket, String text) { public void onClosed(WebSocket webSocket, int code, String reason) { isOpen.set(false); connectLatch.get().countDown(); - log.debug("WebSocket closed"); + log.debug("WebSocket closed, requestId={}", getRequestIdForLog()); callback.onClose(code, reason); } @@ -301,12 +316,13 @@ public void onClosed(WebSocket webSocket, int code, String reason) { public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { isClosed.set(true); websocktetClient.close(code, reason); - log.debug("WebSocket closing: " + code + ", " + reason); + log.debug("WebSocket closing: {}, {}, requestId={}", code, reason, getRequestIdForLog()); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { + updateRequestIdFromResponse(response); connectLatch.get().countDown(); - log.error("WebSocket failed: " + t.getMessage()); + log.error("WebSocket failed: {}, requestId={}", t.getMessage(), getRequestIdForLog()); } } diff --git a/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java b/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java index 686d078c..4b484635 100644 --- a/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java +++ b/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java @@ -8,6 +8,7 @@ import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; import io.reactivex.Flowable; @@ -37,6 +38,10 @@ public final class SpeechSynthesizer { private String preRequestId = null; + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } + public String getLastRequestId() { return preRequestId; } @@ -61,6 +66,7 @@ public void call(SpeechSynthesisParam param, ResultCallback parameters = new HashMap<>(); parameters.put("pre_task_id", preRequestId); param.setParameters(parameters); @@ -79,6 +85,9 @@ public void onOpen(Status status) { @Override public void onEvent(DashScopeResult message) { + if (message.getRequestId() != null && !message.getRequestId().isEmpty()) { + lastRequestId.set(message.getRequestId()); + } SpeechSynthesisResult result = SpeechSynthesisResult.fromDashScopeResult(message); try { if (result.getTimestamp() != null) { @@ -98,7 +107,10 @@ public void onEvent(DashScopeResult message) { if (result.getAudioFrame() != null) { if (recvAudioLength == 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("[TtsV2] first package delay: " + getFirstPackageDelay() + " ms"); + log.debug( + "[TtsV2] first package delay: {} ms, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } recvAudioLength += (double) result.getAudioFrame().capacity() @@ -106,20 +118,28 @@ public void onEvent(DashScopeResult message) { long current = System.currentTimeMillis(); double current_rtf = (current - startStreamTimeStamp) / recvAudioLength; log.debug( - "[TtsV2] Recv Audio Binary: " - + result.getAudioFrame().capacity() - + " bytes, total audio " - + recvAudioLength - + " ms, current_rtf: " - + current_rtf); + "[TtsV2] Recv Audio Binary: {} bytes, total audio {} ms, current_rtf: {}, requestId={}", + result.getAudioFrame().capacity(), + recvAudioLength, + current_rtf, + getRequestIdForLog()); try { channel.write(result.getAudioFrame()); } catch (IOException e) { - log.error("Failed to write audio: {}", result.getAudioFrame(), e); + log.error( + "Failed to write audio: {}, requestId={}", + result.getAudioFrame(), + getRequestIdForLog(), + e); } } } catch (Exception e) { - log.error("Failed to parse response: {}", message, e); + log.error( + "Failed to parse response, event: {}, output: {}, requestId={}", + message.getEvent(), + message.getOutput(), + getRequestIdForLog(), + e); callback.onError(e); } callback.onEvent(result); @@ -132,7 +152,8 @@ public void onComplete() { channel.close(); outputStream.close(); } catch (IOException e) { - log.error("Failed to close channel: {}", channel, e); + log.error( + "Failed to close channel: {}, requestId={}", channel, getRequestIdForLog(), e); } callback.onComplete(); } @@ -154,6 +175,7 @@ public Flowable streamCall(SpeechSynthesisParam param) { recvAudioLength = 0; firstPackageTimeStamp = -1; preRequestId = UUID.randomUUID().toString(); + lastRequestId.set(null); Map parameters = new HashMap<>(); parameters.put("pre_task_id", preRequestId); param.setParameters(parameters); @@ -167,6 +189,9 @@ public Flowable streamCall(SpeechSynthesisParam param) { .streamCall(param) .map( message -> { + if (message.getRequestId() != null && !message.getRequestId().isEmpty()) { + lastRequestId.set(message.getRequestId()); + } SpeechSynthesisResult result = SpeechSynthesisResult.fromDashScopeResult(message); if (result.getTimestamp() != null) { Sentence sentence = result.getTimestamp(); @@ -185,7 +210,10 @@ public Flowable streamCall(SpeechSynthesisParam param) { if (result.getAudioFrame() != null) { if (recvAudioLength == 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("[TtsV2] first package delay: " + getFirstPackageDelay() + " ms"); + log.debug( + "[TtsV2] first package delay: {} ms, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } recvAudioLength += (double) result.getAudioFrame().capacity() @@ -193,16 +221,19 @@ public Flowable streamCall(SpeechSynthesisParam param) { long current = System.currentTimeMillis(); double current_rtf = (current - startStreamTimeStamp) / recvAudioLength; log.debug( - "[TtsV2] Recv Audio Binary: " - + result.getAudioFrame().capacity() - + " bytes, total audio " - + recvAudioLength - + " ms, current_rtf: " - + current_rtf); + "[TtsV2] Recv Audio Binary: {} bytes, total audio {} ms, current_rtf: {}, requestId={}", + result.getAudioFrame().capacity(), + recvAudioLength, + current_rtf, + getRequestIdForLog()); try { channel.write(result.getAudioFrame()); } catch (IOException e) { - log.error("Failed to write audio: {}", result.getAudioFrame(), e); + log.error( + "Failed to write audio: {}, requestId={}", + result.getAudioFrame(), + getRequestIdForLog(), + e); } } return result; @@ -214,7 +245,11 @@ public Flowable streamCall(SpeechSynthesisParam param) { channel.close(); outputStream.close(); } catch (IOException e) { - log.error("Failed to close channel: {}", channel, e); + log.error( + "Failed to close channel: {}, requestId={}", + channel, + getRequestIdForLog(), + e); } }) .doOnError( @@ -225,7 +260,11 @@ public Flowable streamCall(SpeechSynthesisParam param) { timestamps.clear(); audioData = null; } catch (IOException ex) { - log.error("Failed to close channel: {}", channel, ex); + log.error( + "Failed to close channel: {}, requestId={}", + channel, + getRequestIdForLog(), + ex); } }); } catch (NoApiKeyException e) { diff --git a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java index 8d866870..b1e5af04 100644 --- a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java +++ b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java @@ -55,6 +55,7 @@ public final class SpeechSynthesizer { @Getter private ByteBuffer audioData; private ByteArrayOutputStream outputStream; private String preRequestId = null; + private AtomicReference lastRequestId = new AtomicReference<>(null); private boolean isFirst = true; private AtomicBoolean canceled = new AtomicBoolean(false); private final AtomicReference lastError = new AtomicReference<>(null); @@ -160,6 +161,7 @@ public void updateParamAndCallback( this.textEmitter = null; this.isFirst = true; this.lastError.set(null); + this.lastRequestId.set(null); this.asyncCall = this.callback != null; } @@ -228,6 +230,10 @@ public String getLastRequestId() { return preRequestId; } + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } + /** * Returns the given options, or a default instance routed to the dedicated audio client * (useDefaultClient=false) when null. @@ -252,6 +258,7 @@ public Flowable streamingCallAsFlowable(Flowable startStreamTimeStamp = System.currentTimeMillis(); recvAudioLength = 0; preRequestId = UUID.randomUUID().toString(); + lastRequestId.set(null); Flowable inputStream = textStream.map(text -> new TextStreamItem(text)); return duplexApi .duplexCall( @@ -262,10 +269,16 @@ public Flowable streamingCallAsFlowable(Flowable .filter(item -> !canceled.get()) .doOnNext( result -> { + if (result.getRequestId() != null && !result.getRequestId().isEmpty()) { + lastRequestId.set(result.getRequestId()); + } if (result.getAudioFrame() != null) { if (recvAudioLength == 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("[TtsV2] first package delay: " + getFirstPackageDelay() + " ms"); + log.debug( + "[TtsV2] first package delay: {} ms, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } recvAudioLength += (double) result.getAudioFrame().capacity() @@ -273,12 +286,11 @@ public Flowable streamingCallAsFlowable(Flowable long current = System.currentTimeMillis(); double currentRtf = (current - startStreamTimeStamp) / recvAudioLength; log.debug( - "[TtsV2] Recv Audio Binary: " - + result.getAudioFrame().capacity() - + " bytes, total audio " - + recvAudioLength - + " ms, current_rtf: " - + currentRtf); + "[TtsV2] Recv Audio Binary: {} bytes, total audio {} ms, current_rtf: {}, requestId={}", + result.getAudioFrame().capacity(), + recvAudioLength, + currentRtf, + getRequestIdForLog()); } }); } @@ -294,6 +306,7 @@ public Flowable callAsFlowable(String text) startStreamTimeStamp = System.currentTimeMillis(); recvAudioLength = 0; preRequestId = UUID.randomUUID().toString(); + lastRequestId.set(null); return duplexApi .duplexCall( StreamInputTtsParamWithStream.fromStreamInputTtsParam( @@ -315,10 +328,16 @@ public Flowable callAsFlowable(String text) .map(SpeechSynthesisResult::fromDashScopeResult) .doOnNext( result -> { + if (result.getRequestId() != null && !result.getRequestId().isEmpty()) { + lastRequestId.set(result.getRequestId()); + } if (result.getAudioFrame() != null) { if (recvAudioLength == 0) { firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("[TtsV2] first package delay: " + getFirstPackageDelay() + " ms"); + log.debug( + "[TtsV2] first package delay: {} ms, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } recvAudioLength += (double) result.getAudioFrame().capacity() @@ -326,12 +345,11 @@ public Flowable callAsFlowable(String text) long current = System.currentTimeMillis(); double currentRtf = (current - startStreamTimeStamp) / recvAudioLength; log.debug( - "[TtsV2] Recv Audio Binary: " - + result.getAudioFrame().capacity() - + " bytes, total audio " - + recvAudioLength - + " ms, current_rtf: " - + currentRtf); + "[TtsV2] Recv Audio Binary: {} bytes, total audio {} ms, current_rtf: {}, requestId={}", + result.getAudioFrame().capacity(), + recvAudioLength, + currentRtf, + getRequestIdForLog()); } }); } @@ -371,7 +389,7 @@ private void startStream(boolean enableSsml) { } cmdBuffer.clear(); } - log.debug("set textEmitter"); + log.debug("set textEmitter, requestId={}", getRequestIdForLog()); textEmitter = emitter; } }, @@ -384,6 +402,7 @@ private void startStream(boolean enableSsml) { startLatch = new AtomicReference<>(new CountDownLatch(1)); firstAudioLatch = new AtomicReference<>(new CountDownLatch(1)); preRequestId = UUID.randomUUID().toString(); + lastRequestId.set(null); // Bind the callback that owns this session: once updateParamAndCallback() installs a new // callback, a late event from this session must not be delivered to the next one. final ResultCallback sessionCallback = this.callback; @@ -396,6 +415,9 @@ private void startStream(boolean enableSsml) { @Override public void onEvent(DashScopeResult message) { + if (message.getRequestId() != null && !message.getRequestId().isEmpty()) { + lastRequestId.set(message.getRequestId()); + } if (message.getEvent() == WebSocketEventType.TASK_STARTED.getValue()) { startLatch.get().countDown(); return; @@ -427,7 +449,10 @@ public void onEvent(DashScopeResult message) { if (recvAudioLength == 0) { firstAudioLatch.get().countDown(); firstPackageTimeStamp = System.currentTimeMillis(); - log.debug("[TtsV2] first package delay: " + getFirstPackageDelay() + " ms"); + log.debug( + "[TtsV2] first package delay: {} ms, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } recvAudioLength += (double) speechSynthesisResult.getAudioFrame().capacity() @@ -435,23 +460,30 @@ public void onEvent(DashScopeResult message) { long current = System.currentTimeMillis(); double currentRtf = (current - startStreamTimeStamp) / recvAudioLength; log.debug( - "[TtsV2] Recv Audio Binary: " - + speechSynthesisResult.getAudioFrame().capacity() - + " bytes, total audio " - + recvAudioLength - + " ms, current_rtf: " - + currentRtf); + "[TtsV2] Recv Audio Binary: {} bytes, total audio {} ms, current_rtf: {}, requestId={}", + speechSynthesisResult.getAudioFrame().capacity(), + recvAudioLength, + currentRtf, + getRequestIdForLog()); if (!asyncCall) { try { channel.write(speechSynthesisResult.getAudioFrame()); } catch (IOException e) { log.error( - "Failed to write audio: {}", speechSynthesisResult.getAudioFrame(), e); + "Failed to write audio: {}, requestId={}", + speechSynthesisResult.getAudioFrame(), + getRequestIdForLog(), + e); } } } } catch (Exception e) { - log.error("Failed to parse response: {}", message, e); + log.error( + "Failed to parse response, event: {}, output: {}, requestId={}", + message.getEvent(), + message.getOutput(), + getRequestIdForLog(), + e); sessionCallback.onError(e); } if (speechSynthesisResult.getRequestId() == null) { @@ -462,7 +494,7 @@ public void onEvent(DashScopeResult message) { @Override public void onComplete() { - log.debug("[TtsV2] onComplete"); + log.debug("[TtsV2] onComplete, requestId={}", getRequestIdForLog()); synchronized (SpeechSynthesizer.this) { state = SpeechSynthesisState.IDLE; } @@ -470,7 +502,7 @@ public void onComplete() { try { outputStream.close(); } catch (IOException e) { - log.error("Failed to close channel: {}", e); + log.error("Failed to close channel, requestId={}", getRequestIdForLog(), e); } sessionCallback.onComplete(); if (stopLatch.get() != null) { @@ -487,7 +519,10 @@ public void onError(Exception e) { // releaseLatches() only unblocks streamingComplete()/streamingCall(); a // callback-driven caller waits on onComplete/onError and would otherwise never // get any signal. Report onComplete, matching the cancel-then-success path. - log.debug("[TtsV2] error after cancel, reported as complete: " + e.getMessage()); + log.debug( + "[TtsV2] error after cancel, reported as complete: {}, requestId={}", + e.getMessage(), + getRequestIdForLog()); synchronized (SpeechSynthesizer.this) { state = SpeechSynthesisState.IDLE; } @@ -562,10 +597,10 @@ private void submitText(String text) { "State invalid: expect stream input tts state is started but " + state.getValue())); } if (textEmitter == null) { - log.debug("submitText to new emitter: " + text); + log.debug("submitText to new emitter: {}, requestId={}", text, getRequestIdForLog()); cmdBuffer.add(AsyncCmdBuffer.builder().item(new TextStreamItem(text)).build()); } else { - log.debug("submitText to emitter: " + text); + log.debug("submitText to emitter: {}, requestId={}", text, getRequestIdForLog()); textEmitter.onNext(new TextStreamItem(text)); } } @@ -580,7 +615,10 @@ private void submitText(String text) { * will wait indefinitely. Throws TimeoutError exception if it times out. */ public void streamingComplete(long completeTimeoutMillis) { - log.debug("streamingComplete with timeout: " + completeTimeoutMillis); + log.debug( + "streamingComplete with timeout: {}, requestId={}", + completeTimeoutMillis, + getRequestIdForLog()); synchronized (this) { if (state != SpeechSynthesisState.TTS_STARTED) { throw new ApiException( @@ -588,10 +626,10 @@ public void streamingComplete(long completeTimeoutMillis) { "State invalid: expect stream input tts state is started but " + state.getValue())); } if (textEmitter == null) { - log.debug("adding stop to new emitter"); + log.debug("adding stop to new emitter, requestId={}", getRequestIdForLog()); cmdBuffer.add(AsyncCmdBuffer.builder().isStop(true).build()); } else { - log.debug("adding stop to emitter"); + log.debug("adding stop to emitter, requestId={}", getRequestIdForLog()); textEmitter.onComplete(); } } @@ -599,17 +637,19 @@ public void streamingComplete(long completeTimeoutMillis) { if (stopLatch.get() != null) { try { if (completeTimeoutMillis > 0) { - log.debug("start waiting for stopLatch"); + log.debug("start waiting for stopLatch, requestId={}", getRequestIdForLog()); if (!stopLatch.get().await(completeTimeoutMillis, TimeUnit.MILLISECONDS)) { throw new RuntimeException("TimeoutError: waiting for streaming complete"); } } else { - log.debug("start waiting for stopLatch"); + log.debug("start waiting for stopLatch, requestId={}", getRequestIdForLog()); stopLatch.get().await(); } - log.debug("stopLatch is done"); + log.debug("stopLatch is done, requestId={}", getRequestIdForLog()); } catch (InterruptedException ignored) { - log.error("Interrupted while waiting for streaming complete"); + log.error( + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog()); } } } @@ -686,11 +726,10 @@ public void streamingCall(String text) { "TimeoutError: waiting for task started more than " + this.startedTimeout + " ms."); } log.debug( - "get started within " - + this.startedTimeout - + " ms, cost: " - + (System.currentTimeMillis() - startTime) - + " ms"); + "get started within {} ms, cost: {} ms, requestId={}", + this.startedTimeout, + System.currentTimeMillis() - startTime, + getRequestIdForLog()); } this.submitText(text); if (this.firstAudioTimeout > 0 && this.firstAudioTimeout - this.startedTimeout > 0) { @@ -706,14 +745,15 @@ public void streamingCall(String text) { + " ms."); } log.debug( - "get first audio within " - + this.firstAudioTimeout - + " ms, cost: " - + (System.currentTimeMillis() - startTime) - + " ms"); + "get first audio within {} ms, cost: {} ms, requestId={}", + this.firstAudioTimeout, + System.currentTimeMillis() - startTime, + getRequestIdForLog()); } } catch (InterruptedException ignored) { - log.error("Interrupted while waiting for streaming complete"); + log.error( + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog()); } } else { this.submitText(text); @@ -732,10 +772,10 @@ public void streamingFlush(JsonObject params) { "State invalid: expect stream input tts state is started but " + state.getValue())); } if (textEmitter == null) { - log.debug("submitFlush to new emitter"); + log.debug("submitFlush to new emitter, requestId={}", getRequestIdForLog()); cmdBuffer.add(AsyncCmdBuffer.builder().item(new TextStreamItem(true, params)).build()); } else { - log.debug("submitFlush to emitter"); + log.debug("submitFlush to emitter, requestId={}", getRequestIdForLog()); textEmitter.onNext(new TextStreamItem(true, params)); } } @@ -781,11 +821,10 @@ public void onError(Exception e) {} "TimeoutError: waiting for task started more than " + this.startedTimeout + " ms."); } log.debug( - "get started within " - + this.startedTimeout - + " ms, cost: " - + (System.currentTimeMillis() - startTime) - + " ms"); + "get started within {} ms, cost: {} ms, requestId={}", + this.startedTimeout, + System.currentTimeMillis() - startTime, + getRequestIdForLog()); } this.submitText(text); if (this.firstAudioTimeout > 0 && this.firstAudioTimeout - this.startedTimeout > 0) { @@ -799,14 +838,15 @@ public void onError(Exception e) {} "TimeoutError: waiting for first audio more than " + this.firstAudioTimeout + " ms."); } log.debug( - "get first audio within " - + this.firstAudioTimeout - + " ms, cost: " - + (System.currentTimeMillis() - startTime) - + " ms"); + "get first audio within {} ms, cost: {} ms, requestId={}", + this.firstAudioTimeout, + System.currentTimeMillis() - startTime, + getRequestIdForLog()); } } catch (InterruptedException ignored) { - log.error("Interrupted while waiting for streaming complete"); + log.error( + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog()); } catch (RuntimeException e) { // The real cause may already have been recorded by the error callback, in which case the // exception raised here only masks it. diff --git a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java index edd38047..bc6fb73d 100644 --- a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java +++ b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java @@ -139,6 +139,20 @@ public String getLastRequestId() { return preRequestId; } + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(taskId); + } + + private String getRequestIdForLog(JsonObject message) { + if (message != null && message.has("header")) { + JsonObject header = message.getAsJsonObject("header"); + if (header.has(TASK_ID) && !header.get(TASK_ID).isJsonNull()) { + return DashScopeHeaders.requestIdOrUnknown(header.get(TASK_ID).getAsString()); + } + } + return getRequestIdForLog(); + } + private void checkConnectStatus() { websocketRequest.checkStatus(); } @@ -165,7 +179,10 @@ public void close() { try { websocketRequest.close(); } catch (Exception e) { - log.warn("Failed to close websocket connection: " + e.getMessage()); + log.warn( + "Failed to close websocket connection: {}, requestId={}", + e.getMessage(), + getRequestIdForLog()); } } releaseLatches(); @@ -209,7 +226,7 @@ private synchronized void sendTaskMessage(String action, JsonObject input) { wsMessage.add("header", JsonUtils.toJsonObject(bailianHeader)); wsMessage.add("payload", JsonUtils.toJsonObject(payload)); - log.debug("sendTaskMessage: {}", wsMessage.toString()); + log.debug("sendTaskMessage: {}, requestId={}", wsMessage.toString(), getRequestIdForLog()); websocketRequest.sendTextMessage(wsMessage.toString()); } @@ -251,7 +268,7 @@ public void stopSynthesizer() { @Override public void onOpen() { - log.info("WebSocket connection opened"); + log.info("WebSocket connection opened, requestId={}", getRequestIdForLog()); if (callback != null) { callback.onOpen(null); } @@ -259,7 +276,7 @@ public void onOpen() { @Override public void onMessage(WebSocket webSocket, String text) { - log.debug("Received text message: " + text); + log.debug("Received text message: {}, requestId={}", text, getRequestIdForLog()); try { JsonObject messageObj = JsonParser.parseString(text).getAsJsonObject(); if (messageObj.has("header")) { @@ -281,19 +298,27 @@ public void onMessage(WebSocket webSocket, String text) { handleResultGenerated(messageObj); break; default: - log.warn("Unknown event: " + event); + log.warn( + "Unknown event: {}, requestId={}", event, getRequestIdForLog(messageObj)); break; } } } } catch (Exception e) { - log.error("Error processing text message: " + e.getMessage(), e); + log.error( + "Error processing text message: {}, requestId={}", + e.getMessage(), + getRequestIdForLog(), + e); } } @Override public void onMessage(WebSocket webSocket, ByteBuffer bytes) { - log.debug("Received binary message, size: {}", bytes.remaining()); + log.debug( + "Received binary message, size: {}, requestId={}", + bytes.remaining(), + getRequestIdForLog()); try { ByteBuffer audioFrame = ByteBuffer.allocate(bytes.remaining()); audioFrame.put(bytes); @@ -312,7 +337,7 @@ public void onMessage(WebSocket webSocket, ByteBuffer bytes) { recvAudioLength += bytes.remaining(); } catch (Exception e) { - log.error("Error processing binary message", e); + log.error("Error processing binary message, requestId={}", getRequestIdForLog(), e); if (callback != null) { callback.onError(e); } @@ -347,12 +372,16 @@ public void onError(WebSocket webSocket, Throwable t) { @Override public void onClose(int code, String reason) { - log.warn("WebSocket connection closed: " + reason + " (" + code + ")"); + log.warn( + "WebSocket connection closed: {} ({}), requestId={}", + reason, + code, + getRequestIdForLog()); releaseLatches(); } private void handleTaskStarted(JsonObject message) { - log.info("Task started"); + log.info("Task started, requestId={}", getRequestIdForLog(message)); state = SpeechSynthesisState.TTS_STARTED; firstPackageTimeStamp = -1; CountDownLatch startLatch = this.startLatch.get(); @@ -362,7 +391,7 @@ private void handleTaskStarted(JsonObject message) { } private void handleTaskFinished(JsonObject message) { - log.info("Task finished"); + log.info("Task finished, requestId={}", getRequestIdForLog(message)); CountDownLatch stopLatch = this.stopLatch.get(); if (stopLatch != null) { stopLatch.countDown(); @@ -378,7 +407,7 @@ private void handleTaskFinished(JsonObject message) { } private void handleTaskFailed(JsonObject message) { - log.error("Task failed: " + message.toString()); + log.error("Task failed: {}, requestId={}", message, getRequestIdForLog(message)); if (callback != null) { String errorMessage = "Unknown error"; if (message.has("header") && message.getAsJsonObject("header").has("error_message")) { @@ -400,7 +429,7 @@ private void handleTaskFailed(JsonObject message) { } private void handleResultGenerated(JsonObject message) { - log.debug("Result generated: " + message.toString()); + log.debug("Result generated: {}, requestId={}", message, getRequestIdForLog(message)); if (callback == null) { return; } @@ -475,7 +504,10 @@ private void startStream() throws NoApiKeyException, InterruptedException { } public void streamingComplete(long completeTimeoutMillis) { - log.debug("streamingComplete with timeout: " + completeTimeoutMillis); + log.debug( + "streamingComplete with timeout: {}, requestId={}", + completeTimeoutMillis, + getRequestIdForLog()); synchronized (this) { if (state != SpeechSynthesisState.TTS_STARTED) { throw new ApiException( @@ -489,17 +521,19 @@ public void streamingComplete(long completeTimeoutMillis) { try { if (completeTimeoutMillis > 0) { - log.debug("start waiting for stopLatch"); + log.debug("start waiting for stopLatch, requestId={}", getRequestIdForLog()); if (!stopLatch.await(completeTimeoutMillis, TimeUnit.MILLISECONDS)) { throw new RuntimeException("TimeoutError: waiting for streaming complete"); } } else { - log.debug("start waiting for stopLatch"); + log.debug("start waiting for stopLatch, requestId={}", getRequestIdForLog()); stopLatch.await(); } - log.debug("stopLatch is done"); + log.debug("stopLatch is done, requestId={}", getRequestIdForLog()); } catch (InterruptedException ignored) { - log.error("Interrupted while waiting for streaming complete"); + log.error( + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog()); Thread.currentThread().interrupt(); } } @@ -537,7 +571,10 @@ public void streamingCall(String text) { this.submitText(text); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 - log.error("Interrupted while waiting for streaming complete", e); + log.error( + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog(), + e); throw new ApiException(e); } catch (NoApiKeyException e) { throw new ApiException(e); @@ -578,7 +615,10 @@ public ByteBuffer call(String text, long timeoutMillis) throws RuntimeException this.submitText(text); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 - log.error("Interrupted while waiting for streaming complete", e); + log.error( + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog(), + e); throw new ApiException(e); } catch (NoApiKeyException e) { throw new ApiException(e); diff --git a/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java b/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java index 7911f8d7..09026d68 100644 --- a/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java +++ b/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java @@ -3,6 +3,7 @@ package com.alibaba.dashscope.common; import com.alibaba.dashscope.exception.ApiException; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.HalfDuplexRequest; import com.alibaba.dashscope.protocol.NetworkResponse; import com.alibaba.dashscope.protocol.Protocol; @@ -41,8 +42,9 @@ protected T fromResponse(Protocol protocol, NetworkResponse r String message = response.getMessage(); if (message == null || message.isEmpty()) { log.warn( - "WebSocket response message is null or empty, httpStatusCode: {}", - response.getHttpStatusCode()); + "WebSocket response message is null or empty, httpStatusCode: {}, requestId={}", + response.getHttpStatusCode(), + getRequestIdOrUnknown()); setInternalError(); return (T) this; } @@ -62,7 +64,7 @@ protected T fromResponse(Protocol protocol, NetworkResponse r this.setMessage(""); return (T) this; } - JsonObject jsonObject = parseJson(message, "Failed to parse HTTP response as JSON: {}"); + JsonObject jsonObject = parseJson(message, "Failed to parse HTTP response as JSON"); if (jsonObject == null) { return (T) this; } @@ -237,7 +239,7 @@ private JsonObject parseJson(String raw, String logMsg) { try { return JsonUtils.parse(raw); } catch (Exception e) { - log.error(logMsg, e); + log.error("{}, requestId={}", logMsg, getRequestIdOrUnknown(), e); setInternalError(); return null; } @@ -271,21 +273,9 @@ private void fillRequestIdFromHeaders() { if (getRequestId() != null && !getRequestId().isEmpty()) { return; } - Map headers = getHeaders(); - if (headers == null) { - return; - } - for (Map.Entry entry : headers.entrySet()) { - String name = entry.getKey(); - if ("x-request-id".equalsIgnoreCase(name) - || "x-dashscope-requestid".equalsIgnoreCase(name) - || "x-dashscope-request-id".equalsIgnoreCase(name)) { - String value = entry.getValue() == null ? null : String.valueOf(entry.getValue()); - if (value != null && !value.isEmpty()) { - setRequestId(value); - return; - } - } + String requestId = DashScopeHeaders.findRequestId(getHeaders()); + if (requestId != null) { + setRequestId(requestId); } } } diff --git a/src/main/java/com/alibaba/dashscope/common/Result.java b/src/main/java/com/alibaba/dashscope/common/Result.java index 8193eabf..6c69372e 100644 --- a/src/main/java/com/alibaba/dashscope/common/Result.java +++ b/src/main/java/com/alibaba/dashscope/common/Result.java @@ -35,6 +35,10 @@ public abstract class Result { /** The message from server response */ private String message; + public String getRequestIdOrUnknown() { + return requestId == null || requestId.isEmpty() ? "unknown" : requestId; + } + /** * Load data from the server output. * diff --git a/src/main/java/com/alibaba/dashscope/multimodal/MultiModalDialog.java b/src/main/java/com/alibaba/dashscope/multimodal/MultiModalDialog.java index 2e119db8..70c4cbe8 100644 --- a/src/main/java/com/alibaba/dashscope/multimodal/MultiModalDialog.java +++ b/src/main/java/com/alibaba/dashscope/multimodal/MultiModalDialog.java @@ -8,6 +8,7 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; import com.alibaba.dashscope.protocol.ConnectionOptions; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; import com.alibaba.dashscope.utils.JsonUtils; @@ -57,6 +58,12 @@ public class MultiModalDialog { private String currentDialogId = ""; // Current dialogue ID + private final AtomicReference lastRequestId = new AtomicReference<>(null); + + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } + @SuperBuilder private static class AsyncCmdBuffer { // Asynchronous command buffer class @Builder.Default private boolean isStop = false; // Stop flag, defaults to false @@ -214,6 +221,7 @@ public void start() { BackpressureStrategy.BUFFER); closed.set(false); // Reset idempotent close guard for reuse across sessions + lastRequestId.set(null); stopLatch.set(new CountDownLatch(1)); // Initializes stop signal latch String preTaskId = @@ -228,13 +236,20 @@ public void start() { new ResultCallback() { // Registers callback handler @Override public void onEvent(DashScopeResult message) { + if (message.getRequestId() != null && !message.getRequestId().isEmpty()) { + lastRequestId.set(message.getRequestId()); + } if (message.isBinaryOutput()) { callback.onSpeechAudioData( (ByteBuffer) message.getOutput()); // Handles speech output data return; } - log.info("onEvent: {}", message); // Logs event information + log.info( + "onEvent: event={}, output={}, requestId={}", + message.getEvent(), + message.getOutput(), + message.getRequestIdOrUnknown()); // Logs event information if (message.getOutput() != null) { JsonObject output = @@ -311,8 +326,9 @@ public void onEvent(DashScopeResult message) { if (message.getEvent().equals("task-started")) { callback.onConnected(); log.debug( - "MultiModalDialog connected, state is {}", - currentState.getValue()); // Logs connection status + "MultiModalDialog connected, state is {}, requestId={}", + currentState.getValue(), + message.getRequestIdOrUnknown()); // Logs connection status } } } @@ -486,7 +502,9 @@ public void stop() { // Use timeout to prevent deadlock: if server doesn't respond in 30s, force close boolean completed = latch.await(30, TimeUnit.SECONDS); if (!completed) { - log.warn("stop() timed out waiting for server acknowledgement, forcing close"); + log.warn( + "stop() timed out waiting for server acknowledgement, forcing close, requestId={}", + getRequestIdForLog()); close(); } } catch (InterruptedException e) { @@ -555,8 +573,9 @@ public void sendAudioData(ByteBuffer audioFrame) { synchronized (MultiModalDialog.this) { // Synchronized block ensures thread safety if (conversationEmitter != null) { log.debug( - "submitAudioFrame to new emitter: " - + audioFrame); // Logs submission of audio frame information + "submitAudioFrame to new emitter: {}, requestId={}", + audioFrame, + getRequestIdForLog()); // Logs submission of audio frame information conversationEmitter.onNext(audioFrame); // Sends audio frame data } else { DialogBuffer.add( @@ -580,8 +599,9 @@ private void sendTextFrame( synchronized (MultiModalDialog.this) { // Synchronized block ensures thread safety if (conversationEmitter != null) { log.debug( - "submitText to new emitter: {}", - textFrame); // Logs submission of text frame information + "submitText to new emitter: {}, requestId={}", + textFrame, + getRequestIdForLog()); // Logs submission of text frame information if ("RequestToRespond".equals(textFrame) || "UpdateInfo".equals(textFrame)) { // RequestToRespond and UpdateInfo have special inputs and parameters diff --git a/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java b/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java index 552edc24..421a5efe 100644 --- a/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java +++ b/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java @@ -9,6 +9,7 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.protocol.ApiServiceOption; import com.alibaba.dashscope.protocol.ConnectionOptions; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.Protocol; import com.alibaba.dashscope.protocol.StreamingMode; import io.reactivex.BackpressureStrategy; @@ -49,6 +50,11 @@ private static class AsyncCmdBuffer { private long onCompleteTimeStamp = -1; private String preRequestId = null; private boolean isListenState = false; + private final AtomicReference lastRequestId = new AtomicReference<>(null); + + private String getRequestIdForLog() { + return DashScopeHeaders.requestIdOrUnknown(lastRequestId.get()); + } @SuperBuilder private static class TingWuRealtimeWithStream extends TingWuRealtimeParam { @@ -185,7 +191,10 @@ public void call(TingWuRealtimeParam param, TingWuRealtimeCallback callback) { new ResultCallback() { @Override public void onEvent(DashScopeResult message) { - log.debug("Response Result :" + message); + if (lastRequestId.get() == null && message.getRequestId() != null) { + lastRequestId.set(message.getRequestId()); + } + log.debug("Response Result: {}, requestId={}", message, getRequestIdForLog()); TingWuRealtimeResult tingWuRealtimeResult = TingWuRealtimeResult.fromDashScopeResult(message); @@ -221,7 +230,10 @@ public void onEvent(DashScopeResult message) { @Override public void onComplete() { onCompleteTimeStamp = System.currentTimeMillis(); - log.debug("last package delay: " + getLastPackageDelay()); + log.debug( + "last package delay: {}, requestId={}", + getLastPackageDelay(), + getRequestIdForLog()); callback.onClosed(); if (stopLatch.get() != null) { stopLatch.get().countDown(); @@ -246,7 +258,7 @@ public void onError(Exception e) { stopLatch.get().countDown(); } } - log.debug("TingWu Realtime client started"); + log.debug("TingWu Realtime client started, requestId={}", getRequestIdForLog()); } /** @@ -262,7 +274,8 @@ public void sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug("send audio frame: " + audioFrame.remaining()); + log.debug( + "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (audioEmitter == null || !isListenState) { cmdBuffer.add(AsyncCmdBuffer.builder().audioFrame(audioFrame).build()); @@ -305,6 +318,7 @@ private void reset() { this.firstPackageTimeStamp = -1; this.stopStreamTimeStamp = -1; this.onCompleteTimeStamp = -1; + this.lastRequestId.set(null); preRequestId = null; } diff --git a/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java b/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java index c7c9427b..3f44b849 100644 --- a/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java +++ b/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java @@ -30,7 +30,11 @@ public static UnderstandingResult fromDashScopeResult(DashScopeResult dashScopeR JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), UnderstandingOutput.class)); } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java b/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java index fc9b1ba7..f4b69b69 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java +++ b/src/main/java/com/alibaba/dashscope/protocol/DashScopeHeaders.java @@ -14,6 +14,36 @@ public final class DashScopeHeaders { private static final String SDK_CLIENT = "java-sdk"; private static final String SDK_SESSION_ID = UUID.randomUUID().toString(); + public static String findRequestId(Map headers) { + if (headers == null) { + return null; + } + for (Map.Entry entry : headers.entrySet()) { + String name = entry.getKey(); + if (name == null + || !("x-request-id".equalsIgnoreCase(name) + || "x-dashscope-requestid".equalsIgnoreCase(name) + || "x-dashscope-request-id".equalsIgnoreCase(name))) { + continue; + } + Object value = entry.getValue(); + if (value instanceof Iterable) { + for (Object item : (Iterable) value) { + if (item != null && !item.toString().isEmpty()) { + return item.toString(); + } + } + } else if (value != null && !value.toString().isEmpty()) { + return value.toString(); + } + } + return null; + } + + public static String requestIdOrUnknown(String requestId) { + return requestId == null || requestId.isEmpty() ? "unknown" : requestId; + } + public static String userAgent() { return userAgent(null); } diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/LoggingInterceptor.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/LoggingInterceptor.java index 9b164f23..68359955 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/LoggingInterceptor.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/LoggingInterceptor.java @@ -2,6 +2,7 @@ package com.alibaba.dashscope.protocol.okhttp; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.utils.StringUtils; import java.io.IOException; import lombok.extern.slf4j.Slf4j; @@ -18,15 +19,24 @@ public Response intercept(Interceptor.Chain chain) throws IOException { long t1 = System.nanoTime(); log.info( StringUtils.format( - "Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers())); + "Sending request %s on %s%n%s, requestId=%s", + request.url(), + chain.connection(), + request.headers(), + DashScopeHeaders.requestIdOrUnknown( + DashScopeHeaders.findRequestId(request.headers().toMultimap())))); Response response = chain.proceed(request); long t2 = System.nanoTime(); log.info( StringUtils.format( - "Received response for %s in %.1fms%n%s", - response.request().url(), (t2 - t1) / 1e6d, response.headers())); + "Received response for %s in %.1fms%n%s, requestId=%s", + response.request().url(), + (t2 - t1) / 1e6d, + response.headers(), + DashScopeHeaders.requestIdOrUnknown( + DashScopeHeaders.findRequestId(response.headers().toMultimap())))); return response; } diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java index 40fb6d2e..9c62736b 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java @@ -9,6 +9,7 @@ import com.alibaba.dashscope.common.Status; import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.NoApiKeyException; +import com.alibaba.dashscope.protocol.DashScopeHeaders; import com.alibaba.dashscope.protocol.HalfDuplexClient; import com.alibaba.dashscope.protocol.HalfDuplexRequest; import com.alibaba.dashscope.protocol.HttpMethod; @@ -53,6 +54,14 @@ public final class OkHttpHttpClient implements HalfDuplexClient { private static final MediaType MEDIA_TYPE_APPLICATION_JSON = MediaType.parse("application/json; charset=utf-8"); + private static String requestId(Response response) { + if (response == null) { + return "unknown"; + } + return DashScopeHeaders.requestIdOrUnknown( + DashScopeHeaders.findRequestId(response.headers().toMultimap())); + } + private Status parseStreamEventData(String data) { try { JsonObject jsonResponse = JsonUtils.parse(data); @@ -368,7 +377,13 @@ private void handleSSEEvent( Response response, HalfDuplexRequest req, AtomicBoolean terminated) { - log.debug(StringUtils.format("Event: id %s, type: %s, data: %s", id, eventType, data)); + log.debug( + StringUtils.format( + "Event: id %s, type: %s, data: %s, requestId=%s", + id, + eventType, + data, + requestId(response))); if (terminated.get()) { return; } @@ -393,7 +408,13 @@ private void handleSSEEvent( isFlattenResult, req)); } else if (SSEEventType.DONE.equals(eventType)) { // event done ignore message - log.debug(StringUtils.format("Ignore event id: %s, type: %s, data: %s", id, eventType, data)); + log.debug( + StringUtils.format( + "Ignore event id: %s, type: %s, data: %s, requestId=%s", + id, + eventType, + data, + requestId(response))); } else if (eventType != null) { // process assistant events. emitter.onNext( @@ -530,7 +551,13 @@ public void onEvent( java.lang.String id, java.lang.String type, java.lang.String data) { - log.debug(StringUtils.format("Event: id %s, type: %s, data: %s", id, type, data)); + log.debug( + StringUtils.format( + "Event: id %s, type: %s, data: %s, requestId=%s", + id, + type, + data, + requestId(response))); if (terminated.get()) { return; } diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java index cc0045b4..79a8ecd6 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java @@ -63,6 +63,7 @@ public class OkHttpWebSocketClient extends WebSocketListener private static final Pattern CLIENT_ERROR_STATUS_LINE = Pattern.compile("was '4\\d\\d "); private OkHttpClient client; private WebSocket webSocketClient; + private volatile String requestId; // indicate the websocket connection is established. private AtomicBoolean isOpen = new AtomicBoolean(false); protected AtomicBoolean isClosed = new AtomicBoolean(false); @@ -87,6 +88,37 @@ public OkHttpWebSocketClient(OkHttpClient client, boolean passTaskStarted) { this.passTaskStarted.set(passTaskStarted); } + protected String getRequestIdOrUnknown() { + return DashScopeHeaders.requestIdOrUnknown(requestId); + } + + private void updateRequestId(String requestId) { + if (requestId != null && !requestId.isEmpty()) { + this.requestId = requestId; + } + } + + private void setRequestIdFromStartMessage(JsonObject startMessage) { + this.requestId = null; + try { + if (startMessage == null || !startMessage.has("header")) { + return; + } + JsonObject header = startMessage.getAsJsonObject("header"); + if (header != null && header.has("task_id") && !header.get("task_id").isJsonNull()) { + this.requestId = header.get("task_id").getAsString(); + } + } catch (RuntimeException ignored) { + // Request processing keeps its original validation and error handling. + } + } + + private void updateRequestIdFromResponse(Response response) { + if (response != null && (requestId == null || requestId.isEmpty())) { + updateRequestId(DashScopeHeaders.findRequestId(response.headers().toMultimap())); + } + } + private Request buildConnectionRequest( String apiKey, boolean isSecurityCheck, @@ -169,7 +201,8 @@ private void establishWebSocketClient( while (true) { // Bail out immediately if cancel() has been called if (isClosed.get()) { - log.debug("Connection cancelled, stop reconnecting."); + log.debug( + "Connection cancelled, stop reconnecting. requestId={}", getRequestIdOrUnknown()); return; } try { @@ -202,7 +235,7 @@ private void establishWebSocketClient( } catch (Throwable ex) { attempts += 1; errorMessage = ex.getMessage() != null ? ex.getMessage() : ex.toString(); - log.error(errorMessage); + log.error("{}, requestId={}", errorMessage, getRequestIdOrUnknown()); if (errorMessage.contains(Constants.NO_API_KEY_ERROR)) { throw ex; } @@ -212,9 +245,10 @@ private void establishWebSocketClient( // so give up immediately. if (isClientError(httpStatusCode, errorMessage)) { log.warn( - "Websocket handshake refused with http status {}, will not retry: {}", + "Websocket handshake refused with http status {}, will not retry: {}, requestId={}", httpStatusCode, - errorMessage); + errorMessage, + getRequestIdOrUnknown()); break; } if (attempts >= MAX_CONNECTION_TIMES) { @@ -223,7 +257,9 @@ private void establishWebSocketClient( } // Check again before sleeping if (isClosed.get()) { - log.debug("Connection cancelled during retry, stop reconnecting."); + log.debug( + "Connection cancelled during retry, stop reconnecting. requestId={}", + getRequestIdOrUnknown()); return; } if (!sleepBeforeRetry(attempts)) { @@ -335,7 +371,9 @@ public void onClosed(WebSocket webSocket, int code, String reason) { // calls to this // listener will be made. log.debug( - StringUtils.format("WebSocket %s closed: %d, %s", webSocket.toString(), code, reason)); + StringUtils.format( + "WebSocket %s closed: %d, %s, requestId=%s", + webSocket.toString(), code, reason, getRequestIdOrUnknown())); isOpen.set(false); } @@ -359,7 +397,10 @@ public void onClosing(WebSocket webSocket, int code, String reason) { // endpoint that understands only text data MAY send this if it receives a // binary message) webSocket.close(code, null); - log.debug(StringUtils.format("Websocket is closing, code: %s, reasion: %s", code, reason)); + log.debug( + StringUtils.format( + "Websocket is closing, code: %s, reasion: %s, requestId=%s", + code, reason, getRequestIdOrUnknown())); if (responseEmitter != null && !responseEmitter.isCancelled()) { responseEmitter.onComplete(); } else { // close on idle, such as server close the connection. @@ -369,13 +410,16 @@ public void onClosing(WebSocket webSocket, int code, String reason) { @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { + updateRequestIdFromResponse(response); // Invoked when a web socket has been closed due to an error reading from or // writing to the network. // Both outgoing and incoming messages may have been lost. No further calls to // this listener will be made. if (isClosed.get()) { - log.debug("called close before but not working, close again in onFailure."); + log.debug( + "called close before but not working, close again in onFailure. requestId={}", + getRequestIdOrUnknown()); close(1001, "call closed before"); // Do not leave establishWebSocketClient() waiting for the 60s timeout. releaseConnectionWaiter(); @@ -392,7 +436,7 @@ public void onFailure(WebSocket webSocket, Throwable t, Response response) { try { responseBody = body.string(); } catch (IOException ex) { - log.error(ex.getMessage()); + log.error("{}, requestId={}", ex.getMessage(), getRequestIdOrUnknown()); } } } @@ -404,7 +448,7 @@ public void onFailure(WebSocket webSocket, Throwable t, Response response) { // Appended, not inlined, to keep the message prefix stable for log based diagnostics. failureMessage = failureMessage + ", http status: " + httpStatusCode; } - log.error(failureMessage); + log.error("{}, requestId={}", failureMessage, getRequestIdOrUnknown()); isOpen.set(false); if (connectionEmitter != null && !connectionEmitter.isCancelled()) { connectionEmitter.onError(new WebSocketConnectException(failureMessage, httpStatusCode, t)); @@ -412,26 +456,37 @@ public void onFailure(WebSocket webSocket, Throwable t, Response response) { // error on request responseEmitter.onError(new Exception(failureMessage, t)); } else { - log.error(failureMessage); + log.error("{}, requestId={}", failureMessage, getRequestIdOrUnknown()); } } @Override public void onMessage(WebSocket webSocket, String text) { if (isClosed.get()) { - log.debug("called close before but not working, close again in onMessage."); + log.debug( + "called close before but not working, close again in onMessage. requestId={}", + getRequestIdOrUnknown()); close(1001, "call closed before"); return; } - log.debug(text); - // Invoked when a text (type 0x1) message has been received. - if (!isFirstMessage.get()) { - log.debug("Receive first package."); + boolean firstMessage = !isFirstMessage.get(); + if (firstMessage) { isFirstMessage.set(true); } + boolean messageLogged = false; try { // Check different message. WebSocketResponse response = JsonUtils.fromJson(text, WebSocketResponse.class); + if (response.header != null) { + updateRequestId(response.header.taskId); + } + log.debug("{}, requestId={}", text, getRequestIdOrUnknown()); + messageLogged = true; + // Invoked when a text (type 0x1) message has been received. + if (firstMessage) { + log.debug("Receive first package. requestId={}", getRequestIdOrUnknown()); + firstMessage = false; + } switch (response.header.event) { case TASK_STARTED: // if has payload, call onNext. @@ -454,7 +509,10 @@ public void onMessage(WebSocket webSocket, String text) { } break; case TASK_FAILED: - log.error(StringUtils.format("Receive task_failed message: %s", text)); + log.error( + StringUtils.format( + "Receive task_failed message: %s, requestId=%s", + text, getRequestIdOrUnknown())); Status st = Status.builder() .code(response.header.code) @@ -467,7 +525,10 @@ public void onMessage(WebSocket webSocket, String text) { if (!responseEmitter.isCancelled()) { responseEmitter.onError(new ApiException(st)); } else { - log.error(StringUtils.format("Something wrong, receive task failed message: %s", text)); + log.error( + StringUtils.format( + "Something wrong, receive task failed message: %s, requestId=%s", + text, getRequestIdOrUnknown())); } case TASK_FINISHED: // check the payload and usage is null. @@ -503,6 +564,12 @@ public void onMessage(WebSocket webSocket, String text) { .build())); } } catch (Throwable ex) { + if (!messageLogged) { + log.debug("{}, requestId={}", text, getRequestIdOrUnknown()); + } + if (firstMessage) { + log.debug("Receive first package. requestId={}", getRequestIdOrUnknown()); + } responseEmitter.onError( new ApiException( Status.builder() @@ -518,12 +585,14 @@ public void onMessage(WebSocket webSocket, String text) { public void onMessage(WebSocket webSocket, ByteString bytes) { // Invoked when a binary (type 0x2) message has been received. if (isClosed.get()) { - log.debug("called close before but not working, close again in onMessage."); + log.debug( + "called close before but not working, close again in onMessage. requestId={}", + getRequestIdOrUnknown()); close(1001, "call closed before"); return; } if (!isFirstMessage.get()) { - log.debug("Receive first binary package."); + log.debug("Receive first binary package. requestId={}", getRequestIdOrUnknown()); isFirstMessage.set(true); } responseEmitter.onNext( @@ -536,13 +605,16 @@ public void onMessage(WebSocket webSocket, ByteString bytes) { @Override public void onOpen(WebSocket webSocket, Response response) { + updateRequestIdFromResponse(response); // the connection has been accepted by the remote peer and may begin // transmitting messages // Invoked when a web socket has been accepted by the remote peer and may begin // transmitting // messages.. if (isClosed.get()) { - log.debug("called close before but not working, close again in onOpen."); + log.debug( + "called close before but not working, close again in onOpen. requestId={}", + getRequestIdOrUnknown()); close(1001, "call closed before"); // Do not leave establishWebSocketClient() waiting for the 60s timeout. releaseConnectionWaiter(); @@ -564,7 +636,9 @@ protected void sendTextWithRetry( String module) { // Guard: skip if already cancelled if (isClosed.get()) { - log.debug("sendTextWithRetry skipped: connection already closed."); + log.debug( + "sendTextWithRetry skipped: connection already closed. requestId={}", + getRequestIdOrUnknown()); return; } // simple retry with fixed delay, no strategy @@ -579,13 +653,16 @@ protected void sendTextWithRetry( if (passTaskStarted.get()) { // when pass througn task started, no need to retry. if (webSocketClient == null) { - log.warn("webSocketClient is null, cannot send message."); + log.warn( + "webSocketClient is null, cannot send message. requestId={}", + getRequestIdOrUnknown()); return; } - log.info("Sending message: " + message); + log.info("Sending message: {}, requestId={}", message, getRequestIdOrUnknown()); Boolean isOk = webSocketClient.send(message); if (!isOk) { - log.warn("Send request failed, return without retry."); + log.warn( + "Send request failed, return without retry. requestId={}", getRequestIdOrUnknown()); } return; } @@ -595,10 +672,12 @@ protected void sendTextWithRetry( return; } if (webSocketClient == null) { - log.warn("webSocketClient is null, cannot send message."); + log.warn( + "webSocketClient is null, cannot send message. requestId={}", + getRequestIdOrUnknown()); return; } - log.debug("Sending message: " + message); + log.debug("Sending message: {}, requestId={}", message, getRequestIdOrUnknown()); Boolean isOk = webSocketClient.send(message); if (isOk) { break; @@ -607,7 +686,8 @@ protected void sendTextWithRetry( apiKey, isSecurityCheck, workspace, customHeaders, baseWebSocketUrl, module); log.warn( StringUtils.format( - "Send request failed, the connection may closed, will reconnect and send again")); + "Send request failed, the connection may closed, will reconnect and send again, requestId=%s", + getRequestIdOrUnknown())); } Observable.timer(5000, TimeUnit.MILLISECONDS).blockingSingle(); ++retryCount; @@ -640,7 +720,9 @@ protected void sendBinaryWithRetry( return; } if (webSocketClient == null) { - log.warn("webSocketClient is null, cannot send binary message."); + log.warn( + "webSocketClient is null, cannot send binary message. requestId={}", + getRequestIdOrUnknown()); return; } Boolean isOk = webSocketClient.send(message); @@ -651,7 +733,8 @@ protected void sendBinaryWithRetry( apiKey, isSecurityCheck, workspace, customHeaders, baseWebSocketUrl, module); log.warn( StringUtils.format( - "Send request failed, the connection may closed, will reconnect and send again")); + "Send request failed, the connection may closed, will reconnect and send again, requestId=%s", + getRequestIdOrUnknown())); } Observable.timer(5000, TimeUnit.MILLISECONDS).blockingSingle(); ++retryCount; @@ -659,12 +742,14 @@ protected void sendBinaryWithRetry( } private void sendBatchRequest(HalfDuplexRequest req) { + JsonObject startMessage = req.getStartTaskMessage(); + setRequestIdFromStartMessage(startMessage); if (req.getWebsocketBinaryData() != null) { // send start-task. sendTextWithRetry( req.getApiKey(), req.isSecurityCheck(), - JsonUtils.toJson(req.getStartTaskMessage()), + JsonUtils.toJson(startMessage), req.getWorkspace(), req.getHeaders(), req.getBaseWebSocketUrl(), @@ -683,7 +768,7 @@ private void sendBatchRequest(HalfDuplexRequest req) { sendTextWithRetry( req.getApiKey(), req.isSecurityCheck(), - JsonUtils.toJson(req.getStartTaskMessage()), + JsonUtils.toJson(startMessage), req.getWorkspace(), req.getHeaders(), req.getBaseWebSocketUrl(), @@ -831,6 +916,7 @@ protected void executeStreamRequest(FullDuplexRequest req) { pendingResponseError.set(null); JsonObject startMessage = req.getStartTaskMessage(); + setRequestIdFromStartMessage(startMessage); onBeforeSendStartMessage(startMessage); String taskId = startMessage.get("header").getAsJsonObject().get("task_id").getAsString(); // send start message out. @@ -888,18 +974,25 @@ protected void executeStreamRequest(FullDuplexRequest req) { req.getModule()); } } catch (Throwable ex) { - log.error(StringUtils.format("sendStreamData exception: %s", ex.getMessage())); + log.error( + StringUtils.format( + "sendStreamData exception: %s, requestId=%s", + ex.getMessage(), getRequestIdOrUnknown())); emitResponseError(ex); } }, err -> { - log.error(StringUtils.format("Get stream data error!")); + log.error( + StringUtils.format( + "Get stream data error! requestId=%s", getRequestIdOrUnknown())); emitResponseError(err); }, new Action() { @Override public void run() throws Exception { - log.debug(StringUtils.format("Stream data send completed!")); + log.debug( + StringUtils.format( + "Stream data send completed! requestId=%s", getRequestIdOrUnknown())); sendTextWithRetry( req.getApiKey(), req.isSecurityCheck(), @@ -918,7 +1011,10 @@ public void run() throws Exception { d.dispose(); } } catch (Throwable ex) { - log.error(StringUtils.format("sendStreamData exception: %s", ex.getMessage())); + log.error( + StringUtils.format( + "sendStreamData exception: %s, requestId=%s", + ex.getMessage(), getRequestIdOrUnknown())); emitResponseError(ex); } } @@ -937,9 +1033,15 @@ private void joinSendFuture(CompletableFuture future) { future.join(); } } catch (CancellationException ex) { - log.error("Sending streaming data cancelled", ex.getMessage()); + log.error( + "Sending streaming data cancelled: {}, requestId={}", + ex.getMessage(), + getRequestIdOrUnknown()); } catch (CompletionException ex) { - log.error("Sending streaming data exception", ex.getMessage()); + log.error( + "Sending streaming data exception: {}, requestId={}", + ex.getMessage(), + getRequestIdOrUnknown()); emitResponseError(ex.getCause() != null ? ex.getCause() : ex); } } diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClientForAudio.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClientForAudio.java index 7917cb3e..3d2614ba 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClientForAudio.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClientForAudio.java @@ -89,7 +89,10 @@ public OkHttpWebSocketClientForAudio(OkHttpClient client, boolean passTaskStarte @Override protected void onBeforeSendStartMessage(JsonObject startMessage) { - log.info("send run-task request {}", JsonUtils.toJson(startMessage)); + log.info( + "send run-task request {}, requestId={}", + JsonUtils.toJson(startMessage), + getRequestIdOrUnknown()); } @Override diff --git a/src/main/java/com/alibaba/dashscope/rerank/TextReRankResult.java b/src/main/java/com/alibaba/dashscope/rerank/TextReRankResult.java index 734f8014..d7c3119a 100644 --- a/src/main/java/com/alibaba/dashscope/rerank/TextReRankResult.java +++ b/src/main/java/com/alibaba/dashscope/rerank/TextReRankResult.java @@ -43,7 +43,10 @@ public static TextReRankResult fromDashScopeResult(DashScopeResult dashScopeResu JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), TextReRankOutput.class)); } else { - log.error("Result no output: {}", dashScopeResult); + log.error( + "Result no output: {}, requestId={}", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown()); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java b/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java index 5087111a..5e03144a 100644 --- a/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java +++ b/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java @@ -46,7 +46,11 @@ public static AsyncTaskListResult fromDashScopeResult(DashScopeResult dashScopeR rs.message = dashScopeResult.getMessage(); return rs; } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return null; } diff --git a/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java b/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java index 828995f0..d88f2cdb 100644 --- a/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java +++ b/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java @@ -29,7 +29,11 @@ public static TokenizationResult fromDashScopeResult(DashScopeResult dashScopeRe JsonUtils.fromJsonObject( (JsonObject) dashScopeResult.getOutput(), TokenizationOutput.class); } else { - log.error(StringUtils.format("Result no output: %s", dashScopeResult)); + log.error( + StringUtils.format( + "Result no output: %s, requestId=%s", + dashScopeResult, + dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/test/java/com/alibaba/dashscope/TestDashScopeResultEmptyBody.java b/src/test/java/com/alibaba/dashscope/TestDashScopeResultEmptyBody.java index f69392da..81071461 100644 --- a/src/test/java/com/alibaba/dashscope/TestDashScopeResultEmptyBody.java +++ b/src/test/java/com/alibaba/dashscope/TestDashScopeResultEmptyBody.java @@ -14,6 +14,9 @@ import com.alibaba.dashscope.protocol.NetworkResponse; import com.alibaba.dashscope.protocol.Protocol; import com.google.gson.JsonObject; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -136,4 +139,43 @@ public void testMalformedBodyIsStillAnInternalError() throws Exception { assertEquals(PublicErrorDef.INTERNAL_ERROR.getStatusCode(), result.getStatusCode()); assertEquals(PublicErrorDef.INTERNAL_ERROR.getErrorCode(), result.getCode()); } + + @Test + public void testBodyRequestIdOverridesResponseHeader() throws Exception { + NetworkResponse response = + NetworkResponse.builder() + .headers( + Collections.singletonMap( + "x-request-id", Collections.singletonList("request-from-header"))) + .message("{\"request_id\":\"request-from-body\",\"output\":{}}") + .httpStatusCode(200) + .build(); + DashScopeResult result = new DashScopeResult().fromResponse(Protocol.HTTP, response, false); + assertEquals("request-from-body", result.getRequestId()); + } + + @Test + public void testMalformedBodyLogsHeaderRequestId() throws Exception { + NetworkResponse response = + NetworkResponse.builder() + .headers( + Collections.singletonMap( + "x-request-id", Collections.singletonList("request-from-header"))) + .message("not json at all") + .httpStatusCode(200) + .build(); + PrintStream originalErr = System.err; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + DashScopeResult result; + try { + System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8.name())); + result = new DashScopeResult().fromResponse(Protocol.HTTP, response, false); + } finally { + System.setErr(originalErr); + } + assertEquals("request-from-header", result.getRequestId()); + assertTrue( + new String(output.toByteArray(), StandardCharsets.UTF_8) + .contains("requestId=request-from-header")); + } } diff --git a/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java b/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java index 3f7de517..63134227 100644 --- a/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java +++ b/src/test/java/com/alibaba/dashscope/TestMultiModalConversation.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationMessage; @@ -11,6 +12,7 @@ import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalMessageItemImage; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalMessageItemText; +import com.alibaba.dashscope.common.DashScopeResult; import com.alibaba.dashscope.common.MultiModalMessage; import com.alibaba.dashscope.common.Role; import com.alibaba.dashscope.exception.ApiException; @@ -18,7 +20,11 @@ import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.exception.UploadFileException; import com.alibaba.dashscope.utils.Constants; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import lombok.extern.slf4j.Slf4j; @@ -32,6 +38,8 @@ import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.junitpioneer.jupiter.SetEnvironmentVariable; +import org.slf4j.LoggerFactory; +import org.slf4j.simple.SimpleLogger; @Execution(ExecutionMode.SAME_THREAD) @Slf4j @@ -41,6 +49,35 @@ public class TestMultiModalConversation { MediaType.parse("application/json; charset=utf-8"); MockWebServer server; + private static class SdkLogCapture implements AutoCloseable { + private final PrintStream originalErr = System.err; + private final ByteArrayOutputStream output = new ByteArrayOutputStream(); + private final SimpleLogger logger; + private final Field levelField; + private final int originalLevel; + + SdkLogCapture(Class loggerClass, boolean debug) throws Exception { + logger = (SimpleLogger) LoggerFactory.getLogger(loggerClass); + levelField = SimpleLogger.class.getDeclaredField("currentLogLevel"); + levelField.setAccessible(true); + originalLevel = levelField.getInt(logger); + if (debug) { + levelField.setInt(logger, 10); + } + System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8.name())); + } + + String output() { + return new String(output.toByteArray(), StandardCharsets.UTF_8); + } + + @Override + public void close() throws Exception { + System.setErr(originalErr); + levelField.setInt(logger, originalLevel); + } + } + @BeforeEach public void before() { this.server = new MockWebServer(); @@ -101,8 +138,7 @@ public void testSendAndReceive() } @Test - public void testStreamIgnoresUsageOnlyFrameAndUsesHeaderRequestId() - throws ApiException, NoApiKeyException, UploadFileException { + public void testStreamIgnoresUsageOnlyFrameAndUsesHeaderRequestId() throws Exception { server.enqueue( new MockResponse() .setHeader("content-type", "text/event-stream") @@ -125,8 +161,11 @@ public void testStreamIgnoresUsageOnlyFrameAndUsesHeaderRequestId() .build()) .build(); - List results = - new MultiModalConversation().streamCall(param).toList().blockingGet(); + List results; + try (SdkLogCapture capture = new SdkLogCapture(MultiModalConversation.class, true)) { + results = new MultiModalConversation().streamCall(param).toList().blockingGet(); + assertTrue(capture.output().contains("requestId=request-from-header")); + } assertEquals(1, results.size()); MultiModalConversationResult result = results.get(0); @@ -136,4 +175,19 @@ public void testStreamIgnoresUsageOnlyFrameAndUsesHeaderRequestId() "正常结果", result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text")); } + + @Test + public void testResultNoOutputLogsRequestId() throws Exception { + DashScopeResult withRequestId = new DashScopeResult(); + withRequestId.setRequestId("request-from-body"); + try (SdkLogCapture capture = new SdkLogCapture(MultiModalConversationResult.class, false)) { + MultiModalConversationResult.fromDashScopeResult(withRequestId); + assertTrue(capture.output().contains("requestId=request-from-body")); + } + + try (SdkLogCapture capture = new SdkLogCapture(MultiModalConversationResult.class, false)) { + MultiModalConversationResult.fromDashScopeResult(new DashScopeResult()); + assertTrue(capture.output().contains("requestId=unknown")); + } + } } diff --git a/src/test/java/com/alibaba/dashscope/protocol/TestDashScopeHeaders.java b/src/test/java/com/alibaba/dashscope/protocol/TestDashScopeHeaders.java index 7018c5b4..a6b4e674 100644 --- a/src/test/java/com/alibaba/dashscope/protocol/TestDashScopeHeaders.java +++ b/src/test/java/com/alibaba/dashscope/protocol/TestDashScopeHeaders.java @@ -14,6 +14,7 @@ import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.task.AsyncTaskParam; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -212,4 +213,24 @@ public void testAsyncTaskPollRequestCarriesTasksModule() throws NoApiKeyExceptio assertEquals("tasks", request.getModule()); assertEquals(CLIENT_PREFIX + "/tasks", request.getHttpRequest().getHeaders().get(SDK_CLIENT)); } + + @Test + public void testFindRequestIdSupportsResponseHeaderVariants() { + assertEquals( + "request-1", + DashScopeHeaders.findRequestId( + Collections.singletonMap("X-Request-Id", Collections.singletonList("request-1")))); + assertEquals( + "request-2", + DashScopeHeaders.findRequestId( + Collections.singletonMap("x-dashscope-requestid", "request-2"))); + assertEquals( + "request-3", + DashScopeHeaders.findRequestId( + Collections.singletonMap("X-DashScope-Request-Id", "request-3"))); + assertNull(DashScopeHeaders.findRequestId(null)); + assertEquals("unknown", DashScopeHeaders.requestIdOrUnknown(null)); + assertEquals("unknown", DashScopeHeaders.requestIdOrUnknown("")); + assertEquals("request-4", DashScopeHeaders.requestIdOrUnknown("request-4")); + } } diff --git a/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java b/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java new file mode 100644 index 00000000..cca16f58 --- /dev/null +++ b/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java @@ -0,0 +1,154 @@ +// Copyright (c) Alibaba, Inc. and its affiliates. + +package com.alibaba.dashscope.protocol.okhttp; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.alibaba.dashscope.audio.protocol.AudioWebsocketCallback; +import com.alibaba.dashscope.audio.protocol.AudioWebsocketRequest; +import com.alibaba.dashscope.common.DashScopeResult; +import io.reactivex.BackpressureStrategy; +import io.reactivex.Flowable; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.slf4j.LoggerFactory; +import org.slf4j.simple.SimpleLogger; + +@Execution(ExecutionMode.SAME_THREAD) +public class TestWebSocketRequestIdLogging { + private static class SdkLogCapture implements AutoCloseable { + private final PrintStream originalErr = System.err; + private final ByteArrayOutputStream output = new ByteArrayOutputStream(); + private final SimpleLogger logger; + private final Field levelField; + private final int originalLevel; + + SdkLogCapture(Class loggerClass) throws Exception { + logger = (SimpleLogger) LoggerFactory.getLogger(loggerClass); + levelField = SimpleLogger.class.getDeclaredField("currentLogLevel"); + levelField.setAccessible(true); + originalLevel = levelField.getInt(logger); + levelField.setInt(logger, 10); + System.setErr(new PrintStream(output, true, StandardCharsets.UTF_8.name())); + } + + String output() { + return new String(output.toByteArray(), StandardCharsets.UTF_8); + } + + @Override + public void close() throws Exception { + System.setErr(originalErr); + levelField.setInt(logger, originalLevel); + } + } + + private static OkHttpWebSocketClient newClient() { + OkHttpWebSocketClient client = new OkHttpWebSocketClient(new OkHttpClient(), false); + Flowable.create( + emitter -> client.responseEmitter = emitter, BackpressureStrategy.BUFFER) + .subscribe(); + return client; + } + + private static Response failureResponse(String requestId) { + return new Response.Builder() + .request(new Request.Builder().url("http://localhost/").build()) + .protocol(okhttp3.Protocol.HTTP_1_1) + .code(500) + .message("failed") + .header("x-request-id", requestId) + .build(); + } + + private static AudioWebsocketRequest newAudioRequest() throws Exception { + AudioWebsocketRequest request = new AudioWebsocketRequest(); + Field callbackField = AudioWebsocketRequest.class.getDeclaredField("callback"); + callbackField.setAccessible(true); + callbackField.set( + request, + new AudioWebsocketCallback() { + @Override + public void onOpen() {} + + @Override + public void onMessage(WebSocket webSocket, String text) {} + + @Override + public void onMessage(WebSocket webSocket, ByteBuffer buffer) {} + + @Override + public void onError(WebSocket webSocket, Throwable t) {} + + @Override + public void onClose(int code, String reason) {} + }); + return request; + } + + @Test + public void testOkHttpLogsUnknownBeforeRequestIdIsAvailable() throws Exception { + OkHttpWebSocketClient client = new OkHttpWebSocketClient(new OkHttpClient(), false); + try (SdkLogCapture capture = new SdkLogCapture(OkHttpWebSocketClient.class)) { + client.onFailure(null, new IOException("failed"), null); + assertTrue(capture.output().contains("requestId=unknown")); + } + } + + @Test + public void testOkHttpLogsTaskIdFromMessage() throws Exception { + try (SdkLogCapture capture = new SdkLogCapture(OkHttpWebSocketClient.class)) { + newClient() + .onMessage( + null, + "{\"header\":{\"task_id\":\"websocket-task\",\"event\":\"task-started\"}," + + "\"payload\":{}}"); + String output = capture.output(); + assertTrue(output.contains("requestId=websocket-task")); + assertTrue(output.contains("Receive first package. requestId=websocket-task")); + } + } + + @Test + public void testOkHttpHandshakeFailureLogsResponseHeaderRequestId() throws Exception { + OkHttpWebSocketClient client = new OkHttpWebSocketClient(new OkHttpClient(), false); + try (SdkLogCapture capture = new SdkLogCapture(OkHttpWebSocketClient.class)) { + client.onFailure( + null, new IOException("handshake failed"), failureResponse("handshake-id")); + assertTrue(capture.output().contains("requestId=handshake-id")); + } + } + + @Test + public void testAudioLogsUnknownBeforeRequestIdIsAvailable() throws Exception { + AudioWebsocketRequest request = newAudioRequest(); + try (SdkLogCapture capture = new SdkLogCapture(AudioWebsocketRequest.class)) { + request.onClosed(null, 1000, "bye"); + assertTrue(capture.output().contains("requestId=unknown")); + } + } + + @Test + public void testAudioTaskIdIsNotOverwrittenByFailureResponseHeader() throws Exception { + AudioWebsocketRequest request = newAudioRequest(); + try (SdkLogCapture capture = new SdkLogCapture(AudioWebsocketRequest.class)) { + request.onMessage(null, "{\"header\":{\"task_id\":\"audio-task\"}}"); + request.onFailure(null, new IOException("failed"), failureResponse("handshake-id")); + String output = capture.output(); + assertTrue(output.contains("requestId=audio-task")); + assertFalse(output.contains("requestId=handshake-id")); + } + } +} From 9692731711be83b23802201dedfc3275089ebf36 Mon Sep 17 00:00:00 2001 From: "zhansheng.lzs" Date: Tue, 3 Nov 2026 16:21:00 +0800 Subject: [PATCH 3/3] style: align request ID logging with CI formatter --- .../codegeneration/CodeGenerationResult.java | 3 +-- .../aigc/generation/GenerationResult.java | 3 +-- .../ImageSynthesisListResult.java | 3 +-- .../imagesynthesis/ImageSynthesisResult.java | 3 +-- .../dashscope/app/ApplicationResult.java | 3 +-- .../audio/asr/recognition/Recognition.java | 3 +-- .../TranslationRecognizerChat.java | 3 +-- .../TranslationRecognizerRealtime.java | 15 +++++++------ .../audio/http_tts/HttpSpeechSynthesizer.java | 3 +-- .../audio/tts/SpeechSynthesizer.java | 3 +-- .../audio/ttsv2/SpeechSynthesizer.java | 9 +++----- .../audio/ttsv2/SpeechSynthesizerV2.java | 21 +++++++------------ .../multimodal/tingwu/TingWuRealtime.java | 3 +-- .../understanding/UnderstandingResult.java | 3 +-- .../protocol/okhttp/OkHttpHttpClient.java | 15 +++---------- .../okhttp/OkHttpWebSocketClient.java | 12 ++++------- .../dashscope/task/AsyncTaskListResult.java | 3 +-- .../tokenizers/TokenizationResult.java | 3 +-- .../okhttp/TestWebSocketRequestIdLogging.java | 3 +-- 19 files changed, 38 insertions(+), 76 deletions(-) diff --git a/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java b/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java index cc37e06d..68dfdae0 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/codegeneration/CodeGenerationResult.java @@ -36,8 +36,7 @@ public static CodeGenerationResult fromDashScopeResult(DashScopeResult dashScope log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java b/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java index 30818219..c732c0cd 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/generation/GenerationResult.java @@ -46,8 +46,7 @@ public static GenerationResult fromDashScopeResult(DashScopeResult dashScopeResu log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java index e7caf33b..e3520320 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisListResult.java @@ -49,8 +49,7 @@ public static ImageSynthesisListResult fromDashScopeResult(DashScopeResult dashS log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return null; } diff --git a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java index f8b868b3..fc589657 100644 --- a/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java +++ b/src/main/java/com/alibaba/dashscope/aigc/imagesynthesis/ImageSynthesisResult.java @@ -49,8 +49,7 @@ public static ImageSynthesisResult fromDashScopeResult(DashScopeResult dashScope log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java b/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java index cb69eb9e..0602e0aa 100644 --- a/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java +++ b/src/main/java/com/alibaba/dashscope/app/ApplicationResult.java @@ -64,8 +64,7 @@ public static ApplicationResult fromDashScopeResult(DashScopeResult dashScopeRes log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return result; diff --git a/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java b/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java index 435cf179..41c3b004 100644 --- a/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java +++ b/src/main/java/com/alibaba/dashscope/audio/asr/recognition/Recognition.java @@ -442,8 +442,7 @@ public void sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug( - "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); + log.debug("send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (state != RecognitionState.RECOGNITION_STARTED) { throw new ApiException( diff --git a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java index e548156a..46939453 100644 --- a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java +++ b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerChat.java @@ -292,8 +292,7 @@ public boolean sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug( - "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); + log.debug("send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (state != TranslationRecognizerState.SPEECH_TRANSLATION_STARTED) { throw new ApiException( diff --git a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java index f06f7fba..9ccb8449 100644 --- a/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java +++ b/src/main/java/com/alibaba/dashscope/audio/asr/translation/TranslationRecognizerRealtime.java @@ -282,9 +282,9 @@ public void onEvent(DashScopeResult message) { if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); log.debug( - "first package delay: {}, requestId={}", - getFirstPackageDelay(), - getRequestIdForLog()); + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( "[Recv Result] transcription: {}, translation: {}, requestId={}", @@ -408,9 +408,9 @@ public TranslationRecognizerResultPack call(TranslationRecognizerParam param, Fi if (firstPackageTimeStamp < 0) { firstPackageTimeStamp = System.currentTimeMillis(); log.debug( - "first package delay: {}, requestId={}", - getFirstPackageDelay(), - getRequestIdForLog()); + "first package delay: {}, requestId={}", + getFirstPackageDelay(), + getRequestIdForLog()); } log.debug( "[Recv SentenceEnd]: transcription {}, translation: {}, requestId={}", @@ -456,8 +456,7 @@ public void sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug( - "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); + log.debug("send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (state != TranslationRecognizerState.SPEECH_TRANSLATION_STARTED) { throw new ApiException( diff --git a/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java b/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java index 2f67974a..1f47ee03 100644 --- a/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java +++ b/src/main/java/com/alibaba/dashscope/audio/http_tts/HttpSpeechSynthesizer.java @@ -172,8 +172,7 @@ public void onError(Exception e) { } }); } catch (Exception e) { - log.error( - "Streaming call failed, requestId={}", getRequestIdForLog(requestId.get(), e), e); + log.error("Streaming call failed, requestId={}", getRequestIdForLog(requestId.get(), e), e); throw new ApiException(e); } } diff --git a/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java b/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java index 4b484635..21bec24d 100644 --- a/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java +++ b/src/main/java/com/alibaba/dashscope/audio/tts/SpeechSynthesizer.java @@ -152,8 +152,7 @@ public void onComplete() { channel.close(); outputStream.close(); } catch (IOException e) { - log.error( - "Failed to close channel: {}, requestId={}", channel, getRequestIdForLog(), e); + log.error("Failed to close channel: {}, requestId={}", channel, getRequestIdForLog(), e); } callback.onComplete(); } diff --git a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java index b1e5af04..a650f50a 100644 --- a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java +++ b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizer.java @@ -648,8 +648,7 @@ public void streamingComplete(long completeTimeoutMillis) { log.debug("stopLatch is done, requestId={}", getRequestIdForLog()); } catch (InterruptedException ignored) { log.error( - "Interrupted while waiting for streaming complete, requestId={}", - getRequestIdForLog()); + "Interrupted while waiting for streaming complete, requestId={}", getRequestIdForLog()); } } } @@ -752,8 +751,7 @@ public void streamingCall(String text) { } } catch (InterruptedException ignored) { log.error( - "Interrupted while waiting for streaming complete, requestId={}", - getRequestIdForLog()); + "Interrupted while waiting for streaming complete, requestId={}", getRequestIdForLog()); } } else { this.submitText(text); @@ -845,8 +843,7 @@ public void onError(Exception e) {} } } catch (InterruptedException ignored) { log.error( - "Interrupted while waiting for streaming complete, requestId={}", - getRequestIdForLog()); + "Interrupted while waiting for streaming complete, requestId={}", getRequestIdForLog()); } catch (RuntimeException e) { // The real cause may already have been recorded by the error callback, in which case the // exception raised here only masks it. diff --git a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java index bc6fb73d..8bf4cd67 100644 --- a/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java +++ b/src/main/java/com/alibaba/dashscope/audio/ttsv2/SpeechSynthesizerV2.java @@ -298,8 +298,7 @@ public void onMessage(WebSocket webSocket, String text) { handleResultGenerated(messageObj); break; default: - log.warn( - "Unknown event: {}, requestId={}", event, getRequestIdForLog(messageObj)); + log.warn("Unknown event: {}, requestId={}", event, getRequestIdForLog(messageObj)); break; } } @@ -316,9 +315,7 @@ public void onMessage(WebSocket webSocket, String text) { @Override public void onMessage(WebSocket webSocket, ByteBuffer bytes) { log.debug( - "Received binary message, size: {}, requestId={}", - bytes.remaining(), - getRequestIdForLog()); + "Received binary message, size: {}, requestId={}", bytes.remaining(), getRequestIdForLog()); try { ByteBuffer audioFrame = ByteBuffer.allocate(bytes.remaining()); audioFrame.put(bytes); @@ -373,10 +370,7 @@ public void onError(WebSocket webSocket, Throwable t) { @Override public void onClose(int code, String reason) { log.warn( - "WebSocket connection closed: {} ({}), requestId={}", - reason, - code, - getRequestIdForLog()); + "WebSocket connection closed: {} ({}), requestId={}", reason, code, getRequestIdForLog()); releaseLatches(); } @@ -532,8 +526,7 @@ public void streamingComplete(long completeTimeoutMillis) { log.debug("stopLatch is done, requestId={}", getRequestIdForLog()); } catch (InterruptedException ignored) { log.error( - "Interrupted while waiting for streaming complete, requestId={}", - getRequestIdForLog()); + "Interrupted while waiting for streaming complete, requestId={}", getRequestIdForLog()); Thread.currentThread().interrupt(); } } @@ -572,9 +565,9 @@ public void streamingCall(String text) { } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 log.error( - "Interrupted while waiting for streaming complete, requestId={}", - getRequestIdForLog(), - e); + "Interrupted while waiting for streaming complete, requestId={}", + getRequestIdForLog(), + e); throw new ApiException(e); } catch (NoApiKeyException e) { throw new ApiException(e); diff --git a/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java b/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java index 421a5efe..3d60f3ca 100644 --- a/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java +++ b/src/main/java/com/alibaba/dashscope/multimodal/tingwu/TingWuRealtime.java @@ -274,8 +274,7 @@ public void sendAudioFrame(ByteBuffer audioFrame) { if (this.startStreamTimeStamp < 0) { this.startStreamTimeStamp = System.currentTimeMillis(); } - log.debug( - "send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); + log.debug("send audio frame: {}, requestId={}", audioFrame.remaining(), getRequestIdForLog()); synchronized (this) { if (audioEmitter == null || !isListenState) { cmdBuffer.add(AsyncCmdBuffer.builder().audioFrame(audioFrame).build()); diff --git a/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java b/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java index 3f44b849..50949bee 100644 --- a/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java +++ b/src/main/java/com/alibaba/dashscope/nlp/understanding/UnderstandingResult.java @@ -33,8 +33,7 @@ public static UnderstandingResult fromDashScopeResult(DashScopeResult dashScopeR log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java index 9c62736b..f8749825 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpHttpClient.java @@ -380,10 +380,7 @@ private void handleSSEEvent( log.debug( StringUtils.format( "Event: id %s, type: %s, data: %s, requestId=%s", - id, - eventType, - data, - requestId(response))); + id, eventType, data, requestId(response))); if (terminated.get()) { return; } @@ -411,10 +408,7 @@ private void handleSSEEvent( log.debug( StringUtils.format( "Ignore event id: %s, type: %s, data: %s, requestId=%s", - id, - eventType, - data, - requestId(response))); + id, eventType, data, requestId(response))); } else if (eventType != null) { // process assistant events. emitter.onNext( @@ -554,10 +548,7 @@ public void onEvent( log.debug( StringUtils.format( "Event: id %s, type: %s, data: %s, requestId=%s", - id, - type, - data, - requestId(response))); + id, type, data, requestId(response))); if (terminated.get()) { return; } diff --git a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java index 79a8ecd6..d909f429 100644 --- a/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java +++ b/src/main/java/com/alibaba/dashscope/protocol/okhttp/OkHttpWebSocketClient.java @@ -201,8 +201,7 @@ private void establishWebSocketClient( while (true) { // Bail out immediately if cancel() has been called if (isClosed.get()) { - log.debug( - "Connection cancelled, stop reconnecting. requestId={}", getRequestIdOrUnknown()); + log.debug("Connection cancelled, stop reconnecting. requestId={}", getRequestIdOrUnknown()); return; } try { @@ -511,8 +510,7 @@ public void onMessage(WebSocket webSocket, String text) { case TASK_FAILED: log.error( StringUtils.format( - "Receive task_failed message: %s, requestId=%s", - text, getRequestIdOrUnknown())); + "Receive task_failed message: %s, requestId=%s", text, getRequestIdOrUnknown())); Status st = Status.builder() .code(response.header.code) @@ -654,8 +652,7 @@ protected void sendTextWithRetry( // when pass througn task started, no need to retry. if (webSocketClient == null) { log.warn( - "webSocketClient is null, cannot send message. requestId={}", - getRequestIdOrUnknown()); + "webSocketClient is null, cannot send message. requestId={}", getRequestIdOrUnknown()); return; } log.info("Sending message: {}, requestId={}", message, getRequestIdOrUnknown()); @@ -673,8 +670,7 @@ protected void sendTextWithRetry( } if (webSocketClient == null) { log.warn( - "webSocketClient is null, cannot send message. requestId={}", - getRequestIdOrUnknown()); + "webSocketClient is null, cannot send message. requestId={}", getRequestIdOrUnknown()); return; } log.debug("Sending message: {}, requestId={}", message, getRequestIdOrUnknown()); diff --git a/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java b/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java index 5e03144a..da40fb5b 100644 --- a/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java +++ b/src/main/java/com/alibaba/dashscope/task/AsyncTaskListResult.java @@ -49,8 +49,7 @@ public static AsyncTaskListResult fromDashScopeResult(DashScopeResult dashScopeR log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return null; } diff --git a/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java b/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java index d88f2cdb..2347442b 100644 --- a/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java +++ b/src/main/java/com/alibaba/dashscope/tokenizers/TokenizationResult.java @@ -32,8 +32,7 @@ public static TokenizationResult fromDashScopeResult(DashScopeResult dashScopeRe log.error( StringUtils.format( "Result no output: %s, requestId=%s", - dashScopeResult, - dashScopeResult.getRequestIdOrUnknown())); + dashScopeResult, dashScopeResult.getRequestIdOrUnknown())); } return result; } diff --git a/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java b/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java index cca16f58..98e00266 100644 --- a/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java +++ b/src/test/java/com/alibaba/dashscope/protocol/okhttp/TestWebSocketRequestIdLogging.java @@ -125,8 +125,7 @@ public void testOkHttpLogsTaskIdFromMessage() throws Exception { public void testOkHttpHandshakeFailureLogsResponseHeaderRequestId() throws Exception { OkHttpWebSocketClient client = new OkHttpWebSocketClient(new OkHttpClient(), false); try (SdkLogCapture capture = new SdkLogCapture(OkHttpWebSocketClient.class)) { - client.onFailure( - null, new IOException("handshake failed"), failureResponse("handshake-id")); + client.onFailure(null, new IOException("handshake failed"), failureResponse("handshake-id")); assertTrue(capture.output().contains("requestId=handshake-id")); } }