繁体   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