2017-06-19 2 views
0

J'utilise la configuration groovy avec le logback. De temps en temps, je vais enregistrer un répertoire ou un emplacement de fichier, et je voudrais qu'il apparaisse dans mon journal HTML en tant que lien. Voici à quoi ressemble ma configuration actuellement.Les liens de format dans le logback

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

Quelqu'un at-il une idée de comment je pourrais obtenir cela?

Répondre

1

Il existe deux obstacles à la génération de balises d'ancrage ou de tout autre code HTML dans la table. Je travaille contre le logback 1.2.3

D'abord vous avez besoin d'un moyen de convertir votre message, en cherchant des chemins et en les remplaçant par des ancres. Créer des convertisseurs personnalisés que vous pouvez utiliser à partir du modèle est simple et documented here. Ma mise en œuvre brute ressemble à ceci, vous aurez probablement envie de modifier la détection de chemin qui vous convient:

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

Cette tente d'échapper à des suspects avant de remplacer des chaînes comme /path/to/thing avec une balise d'ancrage.

Deuxièmement, le HTMLLayout escapes everything, c'est ainsi qu'il ne génère pas une table malformée et améliore la sécurité (les scripts ne peuvent pas être injectés, etc.). Donc, même avec votre nouveau convertisseur câblé et référencé correctement HTMLLayout va échapper à l'ancre. Pour contourner ce HTMLLayout étendu, malheureusement, vous devez remplacer les entrailles de la classe et le mettre dans le même paquet pour accéder aux champs privés du paquet.

Tout ce que vous voulez changer est la ligne d'échappement, je l'ai changé à String s = c.getClass().equals(LinkConverter.class) ? c.convert(event): Transform.escapeTags(c.convert(event)); pour essayer de minimiser l'impact.

Voici la pleine mise en œuvre:

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

Ma configuration finale de logback ressemble à ceci:

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

est ici my repo with this code.

+0

C'est intense, beau travail! Avez-vous déjà eu ceci ou avez-vous tout construit juste pour cette question? – Steve

+0

Ai-je raison de dire que% linkEscaper prend la place de% m dans le motif? mon problème est, log.info ("blahblah {}", var) ne fait pas la substitution pour mise en page ("ch.qos.logback.classic.html.CustomHTMLLayout") {pattern = "% d {aaaa/MM/dd HH: mm: ss}% - 5p% logger {0}% linkEscaper "} – Steve

+0

@Steve Oui, il remplace'% m'. Je l'enregistre près du sommet de la configuration du logback avec 'conversionRule (" linkEscaper ", LinkConverter.class)'. Construit pour cette question. – roby