这篇文章上次修改于 270 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
今天发现 log4qt 在非主线程中记录日志的时候中文会出现乱码,具体是 RollingFileAppender
和 ConsoleAppender
出现乱码,而 DatabaseAppender
不会出现乱码。使用的配置文件如下:
log4j.rootLogger=All,console,database,rollingFile
log4j.additivity.org.apache=true
log4j.appender.rollingFile=Log4Qt::RollingFileAppender
log4j.appender.rollingFile.Threshold=INFO
log4j.appender.rollingFile.ImmediateFlush=true
log4j.appender.rollingFile.AppendFile=true
log4j.appender.rollingFile.File=logs/app.log
log4j.appender.rollingFile.MaxFileSize=4096KB
log4j.appender.rollingFile.MaxBackupIndex=50
log4j.appender.rollingFile.layout=Log4Qt::PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=[%5p] %d -->[%c] %m %n
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.immediateFlush=true
log4j.appender.console.target=STDOUT_TARGET
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%5p] %d -->[%c] %m %n
log4j.appender.database=Log4Qt::DatabaseAppender
log4j.appender.database.Threshold=INFO
log4j.appender.database.connection=log4qt_connection
log4j.appender.database.table=t_log
log4j.appender.database.layout=org.apache.log4j.DatabaseLayout
log4j.appender.database.layout.timeStampColumn=timeStamp
log4j.appender.database.layout.loggenameColumn=loggename
log4j.appender.database.layout.threadNameColumn=threadName
log4j.appender.database.layout.levelColumn=level
log4j.appender.database.layout.messageColumn=message
初步怀疑应该是编码问题引起的,如果能设置 log4qt 使用的编码,问题应该能够得到解决。于是,在配置文件中增加如下编码配置:
log4j.appender.console.encoding=UTF-8
重新运行后,发现问题依旧。
跟踪 log4qt 源码后发现,编码是在 WriterAppender
中设置的:
Q_PROPERTY(QTextCodec *encoding READ encoding WRITE setEncoding)
而将配置文件中的属性设置到对象上是在 factory.cpp
中的 doSetObjectProperty
方法中完成的,如下所示:
void Factory::doSetObjectProperty(QObject *object,
const QString &property,
const QString &value)
{
// - Validate property
// - Get correct property name from meta object
// - Find specific property setter
// - If no specfifc propery setter can be found,
// find general property setter
// - Call property setter
QMetaProperty meta_property;
if (!validateObjectProperty(meta_property, property, object))
return;
QString propertyString = QLatin1String(meta_property.name());
QString type = QLatin1String(meta_property.typeName());
logger()->debug(QStringLiteral("Setting property '%1' on object of class '%2' to value '%3'"),
propertyString,
QLatin1String(object->metaObject()->className()),
value);
QVariant variant;
bool ok = true;
if (type == QStringLiteral("bool"))
variant = OptionConverter::toBoolean(value, &ok);
else if (type == QStringLiteral("int"))
variant = OptionConverter::toInt(value, &ok);
else if (type == QStringLiteral("Log4Qt::Level"))
variant = QVariant::fromValue(OptionConverter::toLevel(value, &ok));
else if (type == QStringLiteral("QString"))
variant = value;
else
{
LogError e = LOG4QT_ERROR(QT_TR_NOOP("Cannot convert to type '%1' for property '%2' on object of class '%3'"),
CONFIGURATOR_UNKNOWN_TYPE_ERROR,
"Log4Qt::Factory");
e << type
<< property
<< QString::fromLatin1(object->metaObject()->className());
logger()->error(e);
return;
}
if (!ok)
return;
// Everything is checked and the type is the one of the property.
// Write should never return false
if (!meta_property.write(object, variant))
logger()->warn(QStringLiteral("Unxpected error result from QMetaProperty.write()"));
}
仔细看这段代码,居然没有设置 encoding 对应类型 QTextCodec*
的相关代码,那就自己加上吧。
改完后的代码如下所示:
void Factory::doSetObjectProperty(QObject *object,
const QString &property,
const QString &value)
{
// - Validate property
// - Get correct property name from meta object
// - Find specific property setter
// - If no specfifc propery setter can be found,
// find general property setter
// - Call property setter
QMetaProperty meta_property;
if (!validateObjectProperty(meta_property, property, object))
return;
QString propertyString = QLatin1String(meta_property.name());
QString type = QLatin1String(meta_property.typeName());
logger()->debug(QStringLiteral("Setting property '%1' on object of class '%2' to value '%3'"),
propertyString,
QLatin1String(object->metaObject()->className()),
value);
QVariant variant;
bool ok = true;
if (type == QStringLiteral("bool"))
variant = OptionConverter::toBoolean(value, &ok);
else if (type == QStringLiteral("int"))
variant = OptionConverter::toInt(value, &ok);
else if (type == QStringLiteral("Log4Qt::Level"))
variant = QVariant::fromValue(OptionConverter::toLevel(value, &ok));
else if (type == QStringLiteral("QString"))
variant = value;
else if (type == QStringLiteral("QTextCodec*"))
variant = QVariant::fromValue(QTextCodec::codecForName(value.toUtf8()));
else
{
LogError e = LOG4QT_ERROR(QT_TR_NOOP("Cannot convert to type '%1' for property '%2' on object of class '%3'"),
CONFIGURATOR_UNKNOWN_TYPE_ERROR,
"Log4Qt::Factory");
e << type
<< property
<< QString::fromLatin1(object->metaObject()->className());
logger()->error(e);
return;
}
if (!ok)
return;
// Everything is checked and the type is the one of the property.
// Write should never return false
if (!meta_property.write(object, variant))
logger()->warn(QStringLiteral("Unxpected error result from QMetaProperty.write()"));
}
还要记着在全局范围声明元类型:Q_DECLARE_METATYPE(QTextCodec*)
。
再次重新运行,编码是设置成功了,可输出还是乱码!!!
不要慌,换个编码试试,然后换成 GB18030
,再次重新运行,终于没有乱码了!
下一步准备去 github 提个 PR,不知道能否被 merge。
没有评论