本文主要讲述在spring boot中使用logback时出现的一些中文乱码问题,在springMVC中基本也是适用的。
logback常用配置可参考 http://blog.csdn.net/yingxiake/article/details/51274426
输出到文件中,配置如下:
<appender name="STDOUT" class="ch.qos.logback.core.FileAppender">
<file>D:\firstLog.log</file>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{HH:mm:ss.SSS} [%thread] %-2level %logger{36} [%method][%line] - %msg%n</Pattern>
</layout>
</appender>
<root level="ERROR">
<appender-ref ref="STDOUT"/>
</root>
这个配置可以成功输出日志到指定的文件,但当输出中文时,出现了乱码,有些同学可能没有发现乱码的情况,是因为打开文本的工具默认编码有区别,直接用windows记事本打开可能没有乱码,但用Nodepad++等其他文本工具打开可能就是乱码。重要的是我们得明白logback输出的是什么编码。
新增的appender,如果没有指定编码,那默认编码是什么呢,默认就是Null,最后在输出的地方会取当前调用当前运行环境的默认编码。
private byte[] convertToBytes(String s) {
if(this.charset == null) {
return s.getBytes();
} else {
try {
return s.getBytes(this.charset.name());
} catch (UnsupportedEncodingException var3) {
throw new IllegalStateException("An existing charset cannot possibly be unsupported.");
}
}
}
由于charset==null
//String.getBytes()
public byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}
//StringCoding.encode(char[] ca, int off, int len)
static byte[] encode(char[] ca, int off, int len) {
String csn = Charset.defaultCharset().name();
try {
// use charset name encode() variant which provides caching.
return encode(csn, ca, off, len);
} catch (UnsupportedEncodingException x) {
warnUnsupportedCharset(csn);
}
try {
return encode("ISO-8859-1", ca, off, len);
} catch (UnsupportedEncodingException x) {
// If this code is hit during VM initialization, MessageUtils is
// the only way we will be able to get any kind of error message.
MessageUtils.err("ISO-8859-1 charset not available: "
+ x.toString());
// If we can not find ISO-8859-1 (a required encoding) then things
// are seriously wrong with the installation.
System.exit(1);
return null;
}
}
这个默认编码是哪里的默认编码呢?是tomcat的默认编码,那我们可以去修改tomcat的默认编码:
有人提供了简便的设置tomcat charset的方式:
在tomcat/bin目录下建一个文件,文件名为 setenv.bat ,并将下面代码写入文件,重启tomcat,默认编码就变为UTF-8了,用Logback输出就没有中文乱码情况了。
set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF8"
这是一种处理方式,但个人不太支持这种做法,因为很多默认输出用的是GBK的,将tomcat编码设置为UTF-8只是方便了自己输出日志,但有可能导致其他编码的输出会变成乱码,所以最好不要去动tomcat的默认编码。
解决方法当然是设置logback本身的输出编码,我们可以参见spring boot提供的console-appender.xml
<included>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
</included>
设置编码一定要在encoder节点下设置,有些人说可以直接在appender节点下添加charset,略翻源码发现最后的输出是在类ch.qos.logback.core.encoder.LayoutWrappingEncoder下完成的,这个类有个Charset成员变量,最终输出编码获取的就是这个变量,如果没有则取当前运行环境的默认编码。
设置编码可以如下:
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date{HH:mm:ss.SSS} [%thread] %-5level %logger{10} [%file:%line] - %msg%n</pattern>
</layout>
<charset>UTF-8</charset>
</encoder>
如果没有特殊要求可以引用spring boot写好的base.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Base logback configuration provided for compatibility with Spring Boot 1.1
-->
<included>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</included>
我们可以看到base.xml引入了两个appender,他的默认输出编码都是UTF-8的,但是运行环境不默认编码为GBK,编码有冲突,所以在console中输出的又是乱码,我们可以把他的默认配置copy到我们自定义的logback-spring.xml下,修改下默认的名称为CONSOLE的appender默认编码为GBK。
总结下来logback输出中文的乱码情况我们要考虑两个因素:
- 字节流的编码 byte[],通常为 s.getBytes(this.charset.name());
- 当前运行环境的默认编码,这个基本上可以确定是服务器的编码,这个我们可以通过Charset.defaultCharset().name()查看。值得注意的是通过spring boot内置的tomcat运行时,他的默认编码是UTF-8,所以无需任何设置,但当打包成war包时就会出现乱码情况了,所以最好在logback中明确设置好编码,以免受到惊吓。。
欢迎关注我的个人公众号:逍遥的心。主推程序员写的生活类文章,有兴趣的朋友可以共同探讨下: