在logback

时间:2017-06-19 17:57:30

标签: logback

我正在使用具有logback的groovy配置。有时,我会记录一个目录或文件位置,我希望它作为链接出现在我的HTML日志中。这是我目前的配置。

appender("htmlLog", FileAppender) {
  file = "${logPath}/${logName}.html"
  append = false
  encoder(LayoutWrappingEncoder) {
    layout("ch.qos.logback.classic.html.HTMLLayout"){  
      pattern = "%d{yyyy/MM/dd HH:mm:ss}%-5p%logger{0}%m" 
    }
  }
}

任何人都想过如何才能得到这个?

1 个答案:

答案 0 :(得分:1)

在表格中生成锚标记或任何其他HTML有两个障碍。我正在反对logback 1.2.3

首先,您需要一种方法来转换您的消息,寻找路径并用锚点替换它们。创建可以从模式中使用的自定义转换器非常简单,documented here。我粗略的实现看起来像这样,你可能想要修改路径检测以适合你:

package ch.qos.logback.classic.html;

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.helpers.Transform;

public class LinkConverter extends ClassicConverter {
    public String convert(ILoggingEvent iLoggingEvent) {
        String message = iLoggingEvent.getMessage();
        message = Transform.escapeTags(message);
        message = message.replaceAll(" (/\\S+)", " <a href=\"$1\">file://$1</a>");
        return message;
    }
}

在使用锚标记替换/path/to/thing之类的字符串之前,这是试图逃避任何可疑字符。

其次,HTMLLayout escapes everything,这样就不会生成格式错误的表并提高安全性(脚本无法注入等)。因此,即使您的新转换器已正确连接并正确引用,HTMLLayout也会逃脱锚点。

为了解决这个问题,我扩展了HTMLLayout,遗憾的是你必须覆盖类的内容,并将它放在同一个包中以访问包私有字段。

您想要更改的是逃避行,我将其更改为String s = c.getClass().equals(LinkConverter.class) ? c.convert(event): Transform.escapeTags(c.convert(event));以尝试将影响降至最低。

以下是完整的实施:

package ch.qos.logback.classic.html;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.helpers.Transform;
import ch.qos.logback.core.pattern.Converter;

public class UnsafeHTMLLayout extends HTMLLayout{

    public String doLayout(ILoggingEvent event) {
        StringBuilder buf = new StringBuilder();
        this.startNewTableIfLimitReached(buf);
        boolean odd = true;
        if((this.counter++ & 1L) == 0L) {
            odd = false;
        }

        String level = event.getLevel().toString().toLowerCase();
        buf.append(CoreConstants.LINE_SEPARATOR);
        buf.append("<tr class=\"");
        buf.append(level);
        if(odd) {
            buf.append(" odd\">");
        } else {
            buf.append(" even\">");
        }

        buf.append(CoreConstants.LINE_SEPARATOR);

        for(Converter c = this.head; c != null; c = c.getNext()) {
            this.appendEventToBuffer(buf, c, event);
        }

        buf.append("</tr>");
        buf.append(CoreConstants.LINE_SEPARATOR);
        if(event.getThrowableProxy() != null) {
            this.throwableRenderer.render(buf, event);
        }

        return buf.toString();
    }

    private void appendEventToBuffer(StringBuilder buf, Converter<ILoggingEvent> c, ILoggingEvent event) {
        buf.append("<td class=\"");
        buf.append(this.computeConverterName(c));
        buf.append("\">");
        String s = c.getClass().equals(LinkConverter.class) ? c.convert(event): Transform.escapeTags(c.convert(event));
        buf.append(s);
        buf.append("</td>");
        buf.append(CoreConstants.LINE_SEPARATOR);
    }
}

我的最终logback配置如下所示:

import ch.qos.logback.classic.html.LinkConverter

conversionRule("linkEscaper", LinkConverter.class)

appender("htmlLog", FileAppender) {
    file = "/tmp/out.html"
    append = false
    encoder(LayoutWrappingEncoder) {
        layout("ch.qos.logback.classic.html.UnsafeHTMLLayout"){
            pattern = "%d{yyyy/MM/dd HH:mm:ss}%-5p%logger{0}%linkEscaper"
        }
    }
}

root(INFO, ["htmlLog"])

这是my repo with this code