我正在使用具有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"
}
}
}
任何人都想过如何才能得到这个?
答案 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"])