2013-12-12 15 views
7

ich einen Rest-Service mit Jersey entwickelt haben, habe ich ein ContainerRequestFilters für den Druck der Antrag wie folgt:Jersey LoggingFilter mit log4j

<init-param> 
    <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name> 
    <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value> 
</init-param> 

und ich habe Logger in den post Methoden log4j. Der LoggingFilter druckt jedoch im Log log4j. Gibt es irgendeine Möglichkeit, dass LogginFilter die Konfiguration von log4j verwendet?

Ich habe versucht, dies in der Datei log4j.xml:

<logger name="com.sun.jersey.api.container.filter.LoggingFilter"> 
    <level value="info" /> 
    <appender-ref ref="ROOT" /> 
    <appender-ref ref="CONSOLE" /> 
</logger> 

aber es funktioniert nicht :(

+0

Jersey verwendet einen jdk Logger, wenn Sie dies aus arbeiten lassen Sie mich wissen! In der Zwischenzeit können Sie dies mit einem Client tun: client.register (new LoggingFilter (Logger.getAnonymousLogger(), true)). Ich bin mir nicht sicher, wie ich diese Server-Seite trotzdem machen soll – stringy05

Antwort

3

Jersey nutzt in der Tat das JDK Logger Sie können die SLF4JBridgeHandler verwenden Sie das JDK Protokoll zu übertragen. Nachrichten an Ihre Logging-Infrastruktur. (siehe Claus Nielsen's Blogpost)

SLF4JBridgeHandler.removeHandlersForRootLogger(); 
SLF4JBridgeHandler.install(); 

So dies in Ihrem Frühling Anwendung abgeholt zu bekommen, habe ich die @PostConstruct Anmerkung.

@Component 
public class JerseyLoggingBridge {  
    @PostConstruct 
    private void init() { 
     SLF4JBridgeHandler.removeHandlersForRootLogger(); 
     SLF4JBridgeHandler.install(); 
    }  
} 
2

Eine Möglichkeit, dies zu handhaben ist ein Filter für den Java-Logger zu schreiben, wo man einfach mit dem log4j Logger Nachricht einzuloggen, oder welche auch immer Sie bevorzugen, und man sinkt die Protokollierung Java durch immer falsch zurück.

Logger javaLogger = Logger.getLogger(YourClass.class.getName()); 
      javaLogger.setFilter(new Filter() { 
       @Override 
       public boolean isLoggable(LogRecord record) { 
        log4jLogger.info(new Date(record.getMillis()) + " " + record.getLevel() + " " + record.getMessage()); 
        return false; 
       } 
      }); 
      this.jerseyClient.register(new LoggingFilter(javaLogger, true)); 
3

Damit können Sie jeden gewünschten Logger verwenden.

Implementierung

import javax.annotation.Priority; 
import javax.ws.rs.container.PreMatching; 

import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 

@PreMatching 
@Priority(Integer.MIN_VALUE) 
public final class Log4j2JerseyLoggingFilter extends AbstractJerseyLoggingFilter { 

    private final Logger logger; 

    public Log4j2JerseyLoggingFilter() { 
     this(LogManager.getLogger(Log4j2JerseyLoggingFilter.class)); 
    } 

    public Log4j2JerseyLoggingFilter(final Logger logger) { 
     this(logger, false); 
    } 

    public Log4j2JerseyLoggingFilter(final Logger logger, boolean printEntity) { 
     super(printEntity); 
     this.logger = logger; 
    } 

    public Log4j2JerseyLoggingFilter(final Logger logger, int maxEntitySize) { 
     super(maxEntitySize); 
     this.logger = logger; 
    } 

    @Override 
    protected void log(StringBuilder b) { 
     if (logger != null) { 
      logger.info(b.toString()); 
     } 
    } 
} 

Abstrakt Logging Filterklasse

Dies ist direkt aus der Logging Filterklasse Jersey, aber die Log-Methode abstrakt zu machen.

import java.io.BufferedInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.FilterOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.URI; 
import java.nio.charset.Charset; 
import java.util.Comparator; 
import java.util.List; 
import java.util.Map; 
import java.util.Set; 
import java.util.TreeSet; 
import java.util.concurrent.atomic.AtomicLong; 

import javax.annotation.Priority; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.client.ClientRequestContext; 
import javax.ws.rs.client.ClientRequestFilter; 
import javax.ws.rs.client.ClientResponseContext; 
import javax.ws.rs.client.ClientResponseFilter; 
import javax.ws.rs.container.ContainerRequestContext; 
import javax.ws.rs.container.ContainerRequestFilter; 
import javax.ws.rs.container.ContainerResponseContext; 
import javax.ws.rs.container.ContainerResponseFilter; 
import javax.ws.rs.container.PreMatching; 
import javax.ws.rs.core.MultivaluedMap; 
import javax.ws.rs.ext.WriterInterceptor; 
import javax.ws.rs.ext.WriterInterceptorContext; 

import org.glassfish.jersey.filter.LoggingFilter; 
import org.glassfish.jersey.message.MessageUtils; 

/** 
* Universal logging filter. 
* <p/> 
* Can be used on client or server side. Has the highest priority. 
* 
* @author Pavel Bucek (pavel.bucek at oracle.com) 
* @author Martin Matula 
*/ 
@PreMatching 
@Priority(Integer.MIN_VALUE) 
public abstract class AbstractJerseyLoggingFilter implements ContainerRequestFilter, ClientRequestFilter, 
     ContainerResponseFilter, ClientResponseFilter, WriterInterceptor { 

    private static final String NOTIFICATION_PREFIX = "* "; 
    private static final String REQUEST_PREFIX = "> "; 
    private static final String RESPONSE_PREFIX = "< "; 
    private static final String ENTITY_LOGGER_PROPERTY = LoggingFilter.class.getName() + ".entityLogger"; 
    private static final String LOGGING_ID_PROPERTY = LoggingFilter.class.getName() + ".id"; 

    private static final Comparator<Map.Entry<String, List<String>>> COMPARATOR = new Comparator<Map.Entry<String, List<String>>>() { 

     @Override 
     public int compare(final Map.Entry<String, List<String>> o1, final Map.Entry<String, List<String>> o2) { 
      return o1.getKey().compareToIgnoreCase(o2.getKey()); 
     } 
    }; 

    private static final int DEFAULT_MAX_ENTITY_SIZE = 8 * 1024; 

    private final AtomicLong _id = new AtomicLong(0); 
    private final boolean printEntity; 
    private final int maxEntitySize; 

    /** 
    * Create a logging filter logging the request and response to a default JDK 
    * logger, named as the fully qualified class name of this class. Entity 
    * logging is turned off by default. 
    */ 
    public AbstractJerseyLoggingFilter() { 
     this(false); 
    } 

    /** 
    * Create a logging filter with custom logger and custom settings of entity 
    * logging. 
    * 
    * @param logger 
    *   the logger to log requests and responses. 
    * @param printEntity 
    *   if true, entity will be logged as well up to the default 
    *   maxEntitySize, which is 8KB 
    */ 
    public AbstractJerseyLoggingFilter(final boolean printEntity) { 
     this.printEntity = printEntity; 
     this.maxEntitySize = DEFAULT_MAX_ENTITY_SIZE; 
    } 

    /** 
    * Creates a logging filter with custom logger and entity logging turned on, 
    * but potentially limiting the size of entity to be buffered and logged. 
    * 
    * @param logger 
    *   the logger to log requests and responses. 
    * @param maxEntitySize 
    *   maximum number of entity bytes to be logged (and buffered) - 
    *   if the entity is larger, logging filter will print (and buffer 
    *   in memory) only the specified number of bytes and print 
    *   "...more..." string at the end. Negative values are 
    *   interpreted as zero. 
    */ 
    public AbstractJerseyLoggingFilter(final int maxEntitySize) { 
     this.printEntity = true; 
     this.maxEntitySize = Math.max(0, maxEntitySize); 
    } 

    protected abstract void log(final StringBuilder b); 

    private StringBuilder prefixId(final StringBuilder b, final long id) { 
     b.append(Long.toString(id)).append(" "); 
     return b; 
    } 

    private void printRequestLine(final StringBuilder b, final String note, final long id, final String method, 
      final URI uri) { 
     prefixId(b, id).append(NOTIFICATION_PREFIX).append(note).append(" on thread ") 
       .append(Thread.currentThread().getName()).append("\n"); 
     prefixId(b, id).append(REQUEST_PREFIX).append(method).append(" ").append(uri.toASCIIString()).append("\n"); 
    } 

    private void printResponseLine(final StringBuilder b, final String note, final long id, final int status) { 
     prefixId(b, id).append(NOTIFICATION_PREFIX).append(note).append(" on thread ") 
       .append(Thread.currentThread().getName()).append("\n"); 
     prefixId(b, id).append(RESPONSE_PREFIX).append(Integer.toString(status)).append("\n"); 
    } 

    private void printPrefixedHeaders(final StringBuilder b, final long id, final String prefix, 
      final MultivaluedMap<String, String> headers) { 
     for (final Map.Entry<String, List<String>> headerEntry : getSortedHeaders(headers.entrySet())) { 
      final List<?> val = headerEntry.getValue(); 
      final String header = headerEntry.getKey(); 

      if (val.size() == 1) { 
       prefixId(b, id).append(prefix).append(header).append(": ").append(val.get(0)).append("\n"); 
      } else { 
       final StringBuilder sb = new StringBuilder(); 
       boolean add = false; 
       for (final Object s : val) { 
        if (add) { 
         sb.append(','); 
        } 
        add = true; 
        sb.append(s); 
       } 
       prefixId(b, id).append(prefix).append(header).append(": ").append(sb.toString()).append("\n"); 
      } 
     } 
    } 

    private Set<Map.Entry<String, List<String>>> getSortedHeaders(final Set<Map.Entry<String, List<String>>> headers) { 
     final TreeSet<Map.Entry<String, List<String>>> sortedHeaders = new TreeSet<Map.Entry<String, List<String>>>(
       COMPARATOR); 
     sortedHeaders.addAll(headers); 
     return sortedHeaders; 
    } 

    private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) 
      throws IOException { 
     if (!stream.markSupported()) { 
      stream = new BufferedInputStream(stream); 
     } 
     stream.mark(maxEntitySize + 1); 
     final byte[] entity = new byte[maxEntitySize + 1]; 
     final int entitySize = stream.read(entity); 
     b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset)); 
     if (entitySize > maxEntitySize) { 
      b.append("...more..."); 
     } 
     b.append('\n'); 
     stream.reset(); 
     return stream; 
    } 

    @Override 
    public void filter(final ClientRequestContext context) throws IOException { 
     final long id = _id.incrementAndGet(); 
     context.setProperty(LOGGING_ID_PROPERTY, id); 

     final StringBuilder b = new StringBuilder(); 

     printRequestLine(b, "Sending client request", id, context.getMethod(), context.getUri()); 
     printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getStringHeaders()); 

     if (printEntity && context.hasEntity()) { 
      final OutputStream stream = new LoggingStream(b, context.getEntityStream()); 
      context.setEntityStream(stream); 
      context.setProperty(ENTITY_LOGGER_PROPERTY, stream); 
      // not calling log(b) here - it will be called by the interceptor 
     } else { 
      log(b); 
     } 
    } 

    @Override 
    public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext) 
      throws IOException { 
     final Object requestId = requestContext.getProperty(LOGGING_ID_PROPERTY); 
     final long id = requestId != null ? (Long) requestId : _id.incrementAndGet(); 

     final StringBuilder b = new StringBuilder(); 

     printResponseLine(b, "Client response received", id, responseContext.getStatus()); 
     printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getHeaders()); 

     if (printEntity && responseContext.hasEntity()) { 
      responseContext.setEntityStream(logInboundEntity(b, responseContext.getEntityStream(), 
        MessageUtils.getCharset(responseContext.getMediaType()))); 
     } 

     log(b); 
    } 

    @Override 
    public void filter(final ContainerRequestContext context) throws IOException { 
     final long id = _id.incrementAndGet(); 
     context.setProperty(LOGGING_ID_PROPERTY, id); 

     final StringBuilder b = new StringBuilder(); 

     printRequestLine(b, "Server has received a request", id, context.getMethod(), 
       context.getUriInfo().getRequestUri()); 
     printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getHeaders()); 

     if (printEntity && context.hasEntity()) { 
      context.setEntityStream(
        logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType()))); 
     } 

     log(b); 
    } 

    @Override 
    public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) 
      throws IOException { 
     final Object requestId = requestContext.getProperty(LOGGING_ID_PROPERTY); 
     final long id = requestId != null ? (Long) requestId : _id.incrementAndGet(); 

     final StringBuilder b = new StringBuilder(); 

     printResponseLine(b, "Server responded with a response", id, responseContext.getStatus()); 
     printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getStringHeaders()); 

     if (printEntity && responseContext.hasEntity()) { 
      final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream()); 
      responseContext.setEntityStream(stream); 
      requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream); 
      // not calling log(b) here - it will be called by the interceptor 
     } else { 
      log(b); 
     } 
    } 

    @Override 
    public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext) 
      throws IOException, WebApplicationException { 
     final LoggingStream stream = (LoggingStream) writerInterceptorContext.getProperty(ENTITY_LOGGER_PROPERTY); 
     writerInterceptorContext.proceed(); 
     if (stream != null) { 
      log(stream.getStringBuilder(MessageUtils.getCharset(writerInterceptorContext.getMediaType()))); 
     } 
    } 

    private class LoggingStream extends FilterOutputStream { 

     private final StringBuilder b; 
     private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

     LoggingStream(final StringBuilder b, final OutputStream inner) { 
      super(inner); 

      this.b = b; 
     } 

     StringBuilder getStringBuilder(final Charset charset) { 
      // write entity to the builder 
      final byte[] entity = baos.toByteArray(); 

      b.append(new String(entity, 0, Math.min(entity.length, maxEntitySize), charset)); 
      if (entity.length > maxEntitySize) { 
       b.append("...more..."); 
      } 
      b.append('\n'); 

      return b; 
     } 

     @Override 
     public void write(final int i) throws IOException { 
      if (baos.size() <= maxEntitySize) { 
       baos.write(i); 
      } 
      out.write(i); 
     } 
    } 
} 

es die gleiche Art und Weise wie ususal registrieren.

public class RestApplication extends ResourceConfig { 

     /** 
     * Registers this package as a list of resources that should be scanned for 
     * other resources. 
     */ 
     public RestApplication() { 
      packages(RestApplication.class.getPackage().getName()); 
      register(Log4j2JerseyLoggingFilter.class); 
     } 
    } 
0

Ab log4j2, können Sie einfach all Logging-JDK auszuhändigen log4j (sofern Sie nicht ausdrücklich JDK-Protokollierung erfordern Teil des Restes der Protokollierung zu handhaben), mit der log4j-jul Bibliothek und das -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager VM Argumente .

Quelle: https://logging.apache.org/log4j/2.0/log4j-jul/