2013-12-12 28 views
7

我有球衣制定了REST服務,我有一個ContainerRequestFilters打印請求,如下所示:新澤西LoggingFilter的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> 

和我在使用log4j的帖子方法記錄。但LoggingFilter在日誌中打印不同的log4j。有沒有什麼辦法可以讓LogginFilter使用log4j的配置?

我在的log4j.xml文件試過這樣:

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

,但它不工作:(

+0

澤西使用JDK記錄器,如果你工作了這一點,讓我知道!在此期間,您可以使用客戶端完成此操作:client.register(new LoggingFilter(Logger.getAnonymousLogger(),true));.不知道如何做這個服務器端 – stringy05

回答

3

新澤西確實使用JDK記錄器可以使用SLF4JBridgeHandler轉移JDK日誌。郵件到您的日誌記錄基礎。(見Claus Nielsen's Blogpost

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

因此,要獲得這種回升在Spring應用程序,我用了@PostConstruct註釋。處理這種

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

一種方法是寫在Java記錄器,你只需登錄到消息log4j的記錄,或任何你喜歡一個過濾器,你總是返回假下沉Java記錄。

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

這將允許您使用任何你想要的記錄器。

實施

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

摘要記錄器類

這是直接從澤西記錄過濾器類,但使日誌方法抽象。

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

註冊它與ususal一樣。

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

由於log4j2的,你可以簡單地交出所有JDK的日誌記錄到log4j的(除非你明確要求JDK日誌來處理記錄的其餘部分),使用log4j-jul庫和-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager VM參數。

來源https://logging.apache.org/log4j/2.0/log4j-jul/