簡體   English   中英

Logback System.err 輸出使用錯誤的編碼

[英]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>都會發生這種情況。

默認情況下, ConsoleAppenderPatternLoutEncoder應該使用系統默認編碼。 (有關詳細討論,請參閱LayoutWrappingEncoder? 的 LogBack 默認字符集。)我的語言環境中的 Windows 10 控制台編碼應該是 Windows-1252(或 Powershell 中的 ISO-8859-1)。 Θ 字符甚至沒有出現在這些字符集中。

為什么 Logback 在應該打印é字符時將Θ字符打印到標准輸出? 更一般地說,為什么在打印到System.outSystem.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.outSystem.err的控制台使用了錯誤的默認字符集。 (任何人都知道我如何告訴 Logback 使用System.console().charset()而不是Charset.defaultCharset() ?我當然沒有辦法提前知道默認的控制台字符集,所以我不能將其硬編碼到logback.xml中。)

我已經提交了 Logback 錯誤LOGBACK-1642

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM