[英]Logback System.err output uses wrong encoding
我在 Windows 10 上使用帶有 Java 17 的 Logback 1.2.11。我正在使用以下logback.xml
:
<configuration>
<property scope="context" name="COLORIZER_COLORS" value="boldred@,boldyellow@,boldcyan@,@,@" />
<conversionRule conversionWord="colorize" converterClass="org.tuxdude.logback.extensions.LogColorizer" />
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<withJansi>true</withJansi>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%colorize(%level)] %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDERR" />
</root>
</configuration>
如果在我的代碼中使用System.out.println("é")
或System.err.println("é")
,我會按預期在控制台上看到一個é
(U+00E9,一個帶重音的小寫字母 e) . 但是,如果我通過 Logback(通過 SLF4J)登錄,它會在屏幕上顯示一個Θ
字符(U+0398,希臘大寫字母 theta)。 無論我在logback.xml
文件中使用<target>System.out</target>
還是<target>System.err</target>
都會發生這種情況。
默認情況下, ConsoleAppender
的PatternLoutEncoder
應該使用系統默認編碼。 (有關詳細討論,請參閱LayoutWrappingEncoder? 的 LogBack 默認字符集。)我的語言環境中的 Windows 10 控制台編碼應該是 Windows-1252(或 Powershell 中的 ISO-8859-1)。 Θ 字符甚至沒有出現在這些字符集中。
為什么 Logback 在應該打印é
字符時將Θ
字符打印到標准輸出? 更一般地說,為什么在打印到System.out
或System.err
時 Logback 不使用默認編碼?
看起來 Logback 使用了錯誤的“默認字符集”。 System.out
的 API Javadocs 說明了它的默認字符集(也適用於System.err
):
“標准”輸出流。 此流已經打開並准備好接受輸出數據。 通常,此流對應於主機環境或用戶指定的顯示輸出或另一個輸出目的地。 如果
Console
存在,則從字符到字節的轉換中使用的編碼等效於Console.charset()
,否則等效於Charset.defaultCharset()
。
在我的 Windows 10 命令提示符上, Charset.defaultCharset()
返回windows-1252
,而System.console().charset()
返回IBM437
。 如果創建一個new OutputStreamWriter(System.out, System.console().charset())
並寫入字符串"é"
,它將按預期生成é
。 但是如果我使用new OutputStreamWriter(System.out, Charset.defaultCharset())
並寫"é"
,它肯定會產生Θ
! 這就是 Θ 的來源——它是IBM437
字符集的一部分!
我不會在這里問為什么我的 Windows 10 命令提示符默認使用IBM437
作為其默認字符集; 在這個問題的背景下,這是無關緊要的。
根本問題似乎是 Logback 錯誤地檢索了默認字符集。 (說來話長,但基本上 Logback依賴於String.getBytes String.getBytes()
的默認字符集。) LayoutWrappingEncoder 中的LayoutWrappingEncoder
最終依賴於Charset.defaultCharset()
的值,這與控制台的值不匹配; 相反,它應該默認為System.console().charset()
如果它想要匹配控制台的默認字符集。
顯然LayoutWrappingEncoder
不知道它是在寫入控制台還是其他實際上使用Charset.defaultCharset()
的輸出流。 也許需要某種方式ch.qos.logback.core.OutputStreamAppender
可以將其字符集公開給LayoutWrappingEncoder
,而ch.qos.logback.core.ConsoleAppender
可以覆蓋基於System.console().charset()
的默認值的Charset.defaultCharset()
。
無論如何,這里的罪魁禍首似乎是 Logback 為System.out
和System.err
的控制台使用了錯誤的默認字符集。 (任何人都知道我如何告訴 Logback 使用System.console().charset()
而不是Charset.defaultCharset()
?我當然沒有辦法提前知道默認的控制台字符集,所以我不能將其硬編碼到logback.xml
中。)
我已經提交了 Logback 錯誤LOGBACK-1642 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.