只显示有效的 SQL 字符串 P6Spy

Posted

技术标签:

【中文标题】只显示有效的 SQL 字符串 P6Spy【英文标题】:Only show effective SQL string P6Spy 【发布时间】:2013-07-21 06:50:45 【问题描述】:

我正在使用 p6spy 记录我的程序生成的 sql 语句。输出的 spy.log 文件格式如下:

current time|execution time|category|statement SQL String|effective SQL string

我只是想知道是否有人知道是否有办法改变 spy.properties 文件并且只有最后一列,即有效的 SQL 字符串,输出到 spy.log 文件?我查看了属性文件,但没有发现任何似乎支持这一点的内容。

谢谢!

【问题讨论】:

【参考方案1】:

目前还没有提供这样的选项来通过配置来实现它。我认为您有 2 个选项

填写新的错误/功能请求报告(这也可以为使用 p6spy 的其他人带来好处):https://github.com/p6spy/p6spy/issues?state=open 或 提供自定义实现

对于后面的选项,我相信您可以通过自己的类来实现它(取决于您使用的记录器,假设您使用 Log4jLogger)。

好吧,如果您检查 Log4jLogger github 和 sourceforge 版本的相关部分,您的实现应该相当简单:

spy.properties:

appender=com.EffectiveSQLLog4jLogger

实现本身可能如下所示:

package com;

import com.p6spy.engine.logging.appender.Log4jLogger;

public class EffectiveSQLLog4jLogger extends Log4jLogger 

  public void logText(String text) 
    super.logText(getEffectiveSQL(text));
  

  private String getEffectiveSQL(String text) 
    if (null == text) 
      return null;
    

    final int idx = text.lastIndexOf("|");

    // non-perfect detection of the exception logged case
    if (-1 == idx) 
      return text;
    

    return text.substring(idx + 1); // not sure about + 1, but check and see :)
  

请注意,实施应涵盖 github(新项目主页,尚未发布版本)以及 sourceforge(原始项目主页,已发布 1.3 版本)。

请注意:我自己并没有测试提案,但这可能是一个很好的起点,从代码审查本身来看,我认为它可以工作。

【讨论】:

【参考方案2】:

在 spy.properties 中有一个名为 logMessageFormat 的属性,您可以将其设置为 MessageFormattingStrategy 的自定义实现。这适用于任何类型的记录器(即文件、slf4j 等)。

例如

logMessageFormat=my.custom.PrettySqlFormat

使用 Hibernate 的漂亮打印 SQL 格式化程序的示例:

package my.custom;

import org.hibernate.jdbc.util.BasicFormatterImpl;
import org.hibernate.jdbc.util.Formatter;

import com.p6spy.engine.spy.appender.MessageFormattingStrategy;

public class PrettySqlFormat implements MessageFormattingStrategy 

    private final Formatter formatter = new BasicFormatterImpl();

    @Override
    public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql) 
        return formatter.format(sql); 
    


【讨论】:

更新:在 p6Spy 3.9 中,formatMessage 方法有一个额外的 String url 参数。由于 Hibernate 4.0 BasicFormatterImpl 现在是 org.hibernate.engine.jdbc.internal.BasicFormatterImpl【参考方案3】:

您可以修补com.p6spy.engine.spy.appender.SingleLineFormat.java 像这样删除准备好的元素和对 P6Util 的任何引用:

package com.p6spy.engine.spy.appender;
public class SingleLineFormat implements MessageFormattingStrategy 
  @Override
  public String formatMessage(final int connectionId, final String now, final long elapsed, final String category, final String prepared, final String sql) 
    return now + "|" + elapsed + "|" + category + "|connection " + connectionId + "|" + sql;
  

然后只编译文件 javac com.p6spy.engine.spy.appender.SingleLineFormat.java

并将 p6spy.jar 中现有的类文件替换为新的。

【讨论】:

这看起来像是一个矫枉过正的解决方案。 是的,我也不高兴。也许我应该提交一个拉取请求以使其成为一个选项。但目前,由于是硬编码,没有其他解决方案。 提出一种新格式,可以直接从 spy.log 中读取自己的格式【参考方案4】:

我同意@boberj,我们习惯于使用 Hibernate 格式化程序来记录日志,但不要忘记批处理,这就是我建议使用的原因:

import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
import org.hibernate.engine.jdbc.internal.BasicFormatterImpl;
import org.hibernate.engine.jdbc.internal.Formatter;

/**
 * Created by Igor Dmitriev on 1/3/16
 */
public class HibernateSqlFormatter implements MessageFormattingStrategy 

    private final Formatter formatter = new BasicFormatterImpl();

    @Override
    public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql) 
        if (sql.isEmpty()) 
            return "";
        
        String template = "Hibernate: %s %s elapsed: %sms";
        String batch = "batch".equals(category) ? ((elapsed == 0) ? "add batch" : "execute batch") : "";
        return String.format(template, batch, formatter.format(sql), elapsed);
    

【讨论】:

【参考方案5】:

在 p6Spy 3.9 中,这可以很简单地实现。在spy.properties设置

customLogMessageFormat=%(effectiveSql)

【讨论】:

以上是关于只显示有效的 SQL 字符串 P6Spy的主要内容,如果未能解决你的问题,请参考以下文章

P6Spy配置使用

P6SPY 3.0.0-rc-1 发布,SQL 语句拦截

P6Spy使用

使用 p6spy,拦截到持久层执行的sql及参数

使用 p6spy,拦截到持久层执行的sql及参数

使用 p6spy,拦截到持久层执行的sql及参数