语句参数的休眠跟踪值(blob除外)

时间:2019-01-09 23:45:54

标签: java hibernate logging

要跟踪休眠SQL语句的参数值,常见的log4j参数化如下所示:

<logger name="org.hibernate.SQL">
  <level value="debug" />
</logger>
<logger name="org.hibernate.type.descriptor.sql.BasicBinder">
  <level value="trace" />
</logger>

这将产生如下日志输出:

2019-01-10 00:10:29,349 [main] DEBUG  SqlStatementLogger.logStatement(SqlStatementLogger.java:92) - select land0_.fk_land as fk_land1_24_0_ from land land0_ where land0_.fk_land=?
2019-01-10 00:10:29,349 [main] TRACE  BasicBinder.bind(BasicBinder.java:65) - binding parameter [1] as [BIGINT] - [27]

这对于分析运行时如何执行应用程序路径非常有用。

问题在于,BasicBinder还记录了LOB参数值的整个字符串表示形式(例如byte[]),这非常无用:

2019-01-07 13:28:45,466 [wwsservices-catalina-exec-10] TRACE   org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [2] as [BLOB] - [[37, 80, 68, 70, 45, 49, 46, 52, ...

整个blob的字符串表示形式被打印到日志文件中,这对我来说很烦人。

有没有办法在仍然显示其他语句参数值的同时抑制/缩短Hibernate或log4j中LOB值的日志输出?

是否可以在log4j中设置最大日志语句大小?

2 个答案:

答案 0 :(得分:2)

Hibernate 5.2.3中已解决HHH-11097个问题,该问题也可以解决您的问题:

this commit中,BlobTypeDescriptor(及其他)将覆盖extractLoggableRepresentation

@Override
public String extractLoggableRepresentation(Blob value) {
    return value == null ? "null" : "BLOB{...}";
}

现在覆盖的默认实现(导致您的问题)如下所示:

@Override
public String extractLoggableRepresentation(T value) {
    return (value == null) ? "null" : value.toString();
}

这应该从您的日志中删除那些巨行。

如果您使用的是最新版本的休眠模式,则很可能使用实例化blob /原始字节数组(byte[])。负责此操作的类型描述符是PrimitiveByteArrayTypeDescriptor,它疯狂地实现了extractLoggableRepresentation方法,如下所示:

@Override
public String extractLoggableRepresentation(byte[] value) {
    return (value == null) ? super.extractLoggableRepresentation( null ) : Arrays.toString( value );
}

在这种情况下,我看到的唯一解决方案是

自定义UserType必须实现nullSafeSet并将自定义JavaTypeDescriptor传递给进行绑定和记录的绑定器:

@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
        final SharedSessionContractImplementor session) throws HibernateException, SQLException {

    // Simply do what 
    // org.hibernate.type.AbstractStandardBasicType.nullSafeSet(PreparedStatement, Object, int, WrapperOptions)
    // does, but using a custom descriptor.

    session.remapSqlTypeDescriptor(MaterializedBlobType.INSTANCE.getSqlTypeDescriptor())
            .getBinder(CustomPrimitiveByteArrayTypeDescriptor.INSTANCE)
            .bind(st, (byte[]) value, index, session);
}

自定义JavaTypeDescriptor只是扩展了PrimitiveByteArrayTypeDescriptor并覆盖了有问题的extractLoggableRepresentation方法:

public class CustomPrimitiveByteArrayTypeDescriptor extends PrimitiveByteArrayTypeDescriptor {
    public static final CustomPrimitiveByteArrayTypeDescriptor INSTANCE = new CustomPrimitiveByteArrayTypeDescriptor();

    @Override
    public String extractLoggableRepresentation(byte[] value) {
        if (null == value) {
            return super.extractLoggableRepresentation(value);
        } else {
            return "byte[" + value.length + "]";
        }
    }
}

答案 1 :(得分:1)

我知道这是一个老问题,但我今天遇到了这个问题,并找到了一种方法来正常记录所有类型,同时使用 log4j2 过滤器(特别是 RegexFilter)避免 blob 类型

Rc::clone(view.state_mut())

也许这对某人有用。