tomcat:@overrided log filter将输出与其非重写变量混合

smtd7mpg  于 2021-07-09  发布在  Java
关注(0)|答案(1)|浏览(357)

FullRequestDumperFilter 作为的java类扩展创建 RequestDumperFilter -tomcat的一部分。 FullRequestDumperFilter 是我的自定义tomcat日志过滤器,用于记录完整的http请求和响应,包括正文,而 RequestDumperFilter 只记录邮件头。
logging.properties 定义了2个日志文件,所需输出: request-dumper.log -标题( RequestDumperFilter ) custom-dumper.log -标题和正文( FullRequestDumperFilter )
问题:部分输出写入错误的日志文件,实际输出: request-dumper.log -两次写入的标题( RequestDumperFilter ) custom-dumper.log -仅正文(目录) @OverrideFullRequestDumperFilter )
这可能是由于 FullRequestDumperFilter ,继承自 RequestDumperFilter ,配置为输出到 request-dumper.log 而不是 custom-dumper.log .
如何让日志过滤器输出到正确的日志文件中? ${CATALINA_HOME}/logging.properties :

handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler, 1request-dumper.org.apache.juli.FileHandler, 1custom-dumper.org.apache.juli.FileHandler

...

1request-dumper.org.apache.juli.FileHandler.level = FINEST
1request-dumper.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1request-dumper.org.apache.juli.FileHandler.prefix = request-dumper.
1request-dumper.org.apache.juli.FileHandler.formatter = org.apache.juli.VerbatimFormatter
org.apache.catalina.filters.RequestDumperFilter.level = FINEST
org.apache.catalina.filters.RequestDumperFilter.handlers = \
  1request-dumper.org.apache.juli.FileHandler

1custom-dumper.org.apache.juli.FileHandler.level = FINEST
1custom-dumper.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1custom-dumper.org.apache.juli.FileHandler.prefix = custom-dumper.
1custom-dumper.org.apache.juli.FileHandler.formatter = org.apache.juli.VerbatimFormatter
com.example.FullRequestDumperFilter.level = FINEST
com.example.FullRequestDumperFilter.handlers = \
  1custom-dumper.org.apache.juli.FileHandler
``` `FullRequestDumperFilter.java` :

package com.example;

import org.apache.catalina.filters.RequestDumperFilter;
import org.apache.commons.io.output.TeeOutputStream;

import javax.servlet.;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.
;
import java.util.*;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

public class FullRequestDumperFilter extends RequestDumperFilter {

/**
 * The logger for this class.
 */
private static final Log log = LogFactory.getLog(FullRequestDumperFilter.class);

/**
 * Log the interesting request parameters, invoke the next Filter in the
 * sequence, and log the interesting response parameters.
 *
 * @param request  The servlet request to be processed
 * @param response The servlet response to be created
 * @param chain    The filter chain being processed
 * @throws IOException      if an input/output error occurs
 * @throws ServletException if a servlet error occurs
 */
@Override
public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain) throws IOException, ServletException {
    super.doFilter(request, response, chain);

    try {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        BufferedRequestWrapper bufferedReqest = new BufferedRequestWrapper(httpServletRequest);
        BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(httpServletResponse);
        doLog("       requestBody\n", bufferedReqest.getRequestBody());
        chain.doFilter(bufferedReqest, bufferedResponse);
        doLog("      responseBody\n", bufferedResponse.getContent());
    } catch (Throwable a) {
        log.error(a);
    }
}

private void doLog(String attribute, String value) {
    StringBuilder sb = new StringBuilder(80);
    sb.append(Thread.currentThread().getName());
    sb.append(' ');
    sb.append(attribute);
    sb.append('=');
    sb.append(value);
    log.info(sb.toString());
}

private static final class BufferedRequestWrapper extends HttpServletRequestWrapper {

    private ByteArrayInputStream bais = null;
    private ByteArrayOutputStream baos = null;
    private BufferedServletInputStream bsis = null;
    private byte[] buffer = null;

    public BufferedRequestWrapper(HttpServletRequest req) throws IOException {
        super(req);
        // Read InputStream and store its content in a buffer.
        InputStream is = req.getInputStream();
        this.baos = new ByteArrayOutputStream();
        byte buf[] = new byte[1024];
        int letti;
        while ((letti = is.read(buf)) > 0) {
            this.baos.write(buf, 0, letti);
        }
        this.buffer = this.baos.toByteArray();
    }

    @Override
    public ServletInputStream getInputStream() {
        this.bais = new ByteArrayInputStream(this.buffer);
        this.bsis = new BufferedServletInputStream(this.bais);
        return this.bsis;
    }

    String getRequestBody() throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(this.getInputStream()));
        String line = null;
        StringBuilder inputBuffer = new StringBuilder();
        do {
            line = reader.readLine();
            if (null != line) {
                inputBuffer.append(line.trim());
            }
        } while (line != null);
        reader.close();
        return inputBuffer.toString().trim();
    }

}

private static final class BufferedServletInputStream extends ServletInputStream {

    private ByteArrayInputStream bais;

    public BufferedServletInputStream(ByteArrayInputStream bais) {
        this.bais = bais;
    }

    @Override
    public int available() {
        return this.bais.available();
    }

    @Override
    public int read() {
        return this.bais.read();
    }

    @Override
    public int read(byte[] buf, int off, int len) {
        return this.bais.read(buf, off, len);
    }

}

public class TeeServletOutputStream extends ServletOutputStream {

    private final TeeOutputStream targetStream;

    public TeeServletOutputStream(OutputStream one, OutputStream two) {
        targetStream = new TeeOutputStream(one, two);
    }

    @Override
    public void write(int arg0) throws IOException {
        this.targetStream.write(arg0);
    }

    public void flush() throws IOException {
        super.flush();
        this.targetStream.flush();
    }

    public void close() throws IOException {
        super.close();
        this.targetStream.close();
    }
}

public class BufferedResponseWrapper implements HttpServletResponse {

    HttpServletResponse original;
    TeeServletOutputStream tee;
    ByteArrayOutputStream bos;

    public BufferedResponseWrapper(HttpServletResponse response) {
        original = response;
    }

    public String getContent() {
        return bos.toString();
    }

    public PrintWriter getWriter() throws IOException {
        return original.getWriter();
    }

    public ServletOutputStream getOutputStream() throws IOException {
        if (tee == null) {
            bos = new ByteArrayOutputStream();
            tee = new TeeServletOutputStream(original.getOutputStream(), bos);
        }
        return tee;

    }

    @Override
    public String getCharacterEncoding() {
        return original.getCharacterEncoding();
    }

    @Override
    public String getContentType() {
        return original.getContentType();
    }

    @Override
    public void setCharacterEncoding(String charset) {
        original.setCharacterEncoding(charset);
    }

    @Override
    public void setContentLength(int len) {
        original.setContentLength(len);
    }

    @Override
    public void setContentType(String type) {
        original.setContentType(type);
    }

    @Override
    public void setBufferSize(int size) {
        original.setBufferSize(size);
    }

    @Override
    public int getBufferSize() {
        return original.getBufferSize();
    }

    @Override
    public void flushBuffer() throws IOException {
        tee.flush();
    }

    @Override
    public void resetBuffer() {
        original.resetBuffer();
    }

    @Override
    public boolean isCommitted() {
        return original.isCommitted();
    }

    @Override
    public void reset() {
        original.reset();
    }

    @Override
    public void setLocale(Locale loc) {
        original.setLocale(loc);
    }

    @Override
    public Locale getLocale() {
        return original.getLocale();
    }

    @Override
    public void addCookie(Cookie cookie) {
        original.addCookie(cookie);
    }

    @Override
    public boolean containsHeader(String name) {
        return original.containsHeader(name);
    }

    @Override
    public String encodeURL(String url) {
        return original.encodeURL(url);
    }

    @Override
    public String encodeRedirectURL(String url) {
        return original.encodeRedirectURL(url);
    }

    @SuppressWarnings("deprecation")
    @Override
    public String encodeUrl(String url) {
        return original.encodeUrl(url);
    }

    @SuppressWarnings("deprecation")
    @Override
    public String encodeRedirectUrl(String url) {
        return original.encodeRedirectUrl(url);
    }

    @Override
    public void sendError(int sc, String msg) throws IOException {
        original.sendError(sc, msg);
    }

    @Override
    public void sendError(int sc) throws IOException {
        original.sendError(sc);
    }

    @Override
    public void sendRedirect(String location) throws IOException {
        original.sendRedirect(location);
    }

    @Override
    public void setDateHeader(String name, long date) {
        original.setDateHeader(name, date);
    }

    @Override
    public void addDateHeader(String name, long date) {
        original.addDateHeader(name, date);
    }

    @Override
    public void setHeader(String name, String value) {
        original.setHeader(name, value);
    }

    @Override
    public void addHeader(String name, String value) {
        original.addHeader(name, value);
    }

    @Override
    public void setIntHeader(String name, int value) {
        original.setIntHeader(name, value);
    }

    @Override
    public void addIntHeader(String name, int value) {
        original.addIntHeader(name, value);
    }

    @Override
    public void setStatus(int sc) {
        original.setStatus(sc);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void setStatus(int sc, String sm) {
        original.setStatus(sc, sm);
    }

    @Override
    public int getStatus() {
        return original.getStatus();
    }

    @Override
    public String getHeader(String s) {
        return original.getHeader(s);
    }

    @Override
    public Collection<String> getHeaders(String s) {
        return original.getHeaders(s);
    }

    @Override
    public Collection<String> getHeaderNames() {
        return original.getHeaderNames();
    }

}

}

dfty9e19

dfty9e191#

这是一个可接受的解决方案,我删除了中的一个过滤器 logging.properties 并将两个过滤器的处理程序都设置为 1custom-dumper.org.apache.juli.FileHandler .
但是,该解决方案仍有缺点:
只能有一个日志文件
必须为同一筛选器配置两次处理程序属性
理想情况下,会有日志级别(例如info、finest),这将允许自定义过滤器的不同输出存储在不同的日志文件中(带或不带正文) ${CATALINA_HOME}/logging.properties :

1custom-dumper.org.apache.juli.FileHandler.level = FINEST
1custom-dumper.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1custom-dumper.org.apache.juli.FileHandler.prefix = custom-dumper.
1custom-dumper.org.apache.juli.FileHandler.formatter = org.apache.juli.VerbatimFormatter
com.example.FullRequestDumperFilter.level = FINEST
com.example.FullRequestDumperFilter.handlers = \
  1custom-dumper.org.apache.juli.FileHandler
org.apache.catalina.filters.RequestDumperFilter.level = FINEST
org.apache.catalina.filters.RequestDumperFilter.handlers = \
  1custom-dumper.org.apache.juli.FileHandler

相关问题