Format links in logback

只愿长相守 提交于 2020-12-13 03:42:44

问题


I am using groovy configuration with logback. Occasionally, I will log a directory or file location, and I'd like it to come up in my HTML log as a link. Here is what my configuration looks like currently.

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" 
    }
  }
}

Anyone have a thought as to how I could get this?


回答1:


There are two obstacles to generating anchor tags or any other HTML within the table. I'm working against logback 1.2.3

First you need a way to convert your message, looking for paths and replacing them with anchors. Creating custom converters that you can use from the pattern is straightforward and documented here. My crude implementation looks like this, you'll probably want to modify the path detection to suit you:

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;
    }
}

This is attempting to escape any suspicious characters before replacing strings like /path/to/thing with an anchor tag.

Secondly, the HTMLLayout escapes everything, this is so it doesn't generate a malformed table and improves security (scripts can't be injected etc). So even with your new converter wired up and referenced correctly HTMLLayout will escape the anchor.

To get around this I extended HTMLLayout, unfortunately you have to override the guts of the class and put it in the same package to access package private fields.

All you want to change is the escaping line, I changed it to String s = c.getClass().equals(LinkConverter.class) ? c.convert(event): Transform.escapeTags(c.convert(event)); to try and minimise the impact.

Here is the full implementation:

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);
    }
}

My final logback configuration looks like this:

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"])

Here's my repo with this code.



来源:https://stackoverflow.com/questions/44637032/format-links-in-logback

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!