日志输出filter

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 日志输出filter

人类经常把一个生涯发生的事,撰写成历史,在从那里看人生;其实,那不过是衣服,人生是内在的——罗曼。罗兰

日记记录过滤器

package com.kuang.config.log;
import com.alibaba.fastjson.JSON;
import com.kuang.common.util.Opt;
import com.kuang.common.util.ResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * 日志记录过滤器
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/29 9:58
 */
@Slf4j
//@Component
//@WebFilter(filterName = "LogFilter", urlPatterns = "/**")
public class LogFilter implements Filter {
    /**
     * The <code>doFilter</code> method of the Filter is called by the container
     * each time a request/response pair is passed through the chain due to a
     * client request for a resource at the end of the chain. The FilterChain
     * passed in to this method allows the Filter to pass on the request and
     * response to the next entity in the chain.
     * <p>
     * A typical implementation of this method would follow the following
     * pattern:- <br>
     * 1. Examine the request<br>
     * 2. Optionally wrap the request object with a custom implementation to
     * filter content or headers for input filtering <br>
     * 3. Optionally wrap the response object with a custom implementation to
     * filter content or headers for output filtering <br>
     * 4. a) <strong>Either</strong> invoke the next entity in the chain using
     * the FilterChain object (<code>chain.doFilter()</code>), <br>
     * 4. b) <strong>or</strong> not pass on the request/response pair to the
     * next entity in the filter chain to block the request processing<br>
     * 5. Directly set headers on the response after invocation of the next
     * entity in the filter chain.
     *
     * @param request  The request to process
     * @param response The response associated with the request
     * @param chain    Provides access to the next filter in the chain for this
     *                 filter to pass the request and response to for further
     *                 processing
     * @throws IOException      if an I/O error occurs during this filter's
     *                          processing of the request
     * @throws ServletException if the processing fails for any other reason
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ResponseWrapper wrapper = new ResponseWrapper((HttpServletResponse) response);
        HttpServletRequest req = (HttpServletRequest) request;
        String uri = req.getRequestURI();
        long startTime = System.nanoTime();
        chain.doFilter(request, wrapper);
        // 获取response返回的内容并重新写入response
        String result = wrapper.getResponseData(response.getCharacterEncoding());
        response.getOutputStream().write(result.getBytes());
        Opt.of(log).filter(Logger::isInfoEnabled).ifPresent(l -> {
            log.info("method:{}", req.getMethod());
            log.info("uri:{}", uri);
            log.info("parameterMap:{}", JSON.toJSONString(req.getParameterMap()));
            log.info("responseCode:{}", wrapper.getStatus());
            log.info("result:{}", result);
            log.info("timeCost:{}", (System.nanoTime() - startTime) / (1000.0 * 1000.0) + "ms");
        });
    }
}


因为默认的response获取了响应结果就没了,因此我们需要封装一个ResponseWrapper

package com.kuang.common.util;
import lombok.SneakyThrows;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
/**
 * 过滤器获取响应结果
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/29 10:13
 */
public class ResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream buffer = null;
    private ServletOutputStream outputStream = null;
    private PrintWriter writer = null;
    /**
     * Constructs a response adaptor wrapping the given response.
     *
     * @param response The response to be wrapped
     * @throws IllegalArgumentException if the response is null
     */
    @SneakyThrows
    public ResponseWrapper(HttpServletResponse response) {
        super(response);
        buffer = new ByteArrayOutputStream();
        outputStream = new WrapperOutputStream(buffer);
        writer = new PrintWriter(new OutputStreamWriter(buffer, StandardCharsets.UTF_8));
    }
    /**
     * The default behavior of this method is to return getOutputStream() on the
     * wrapped response object.
     */
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return outputStream;
    }
    /**
     * The default behavior of this method is to return getWriter() on the
     * wrapped response object.
     */
    @Override
    public PrintWriter getWriter() throws IOException {
        return writer;
    }
    /**
     * The default behavior of this method is to call flushBuffer() on the
     * wrapped response object.
     */
    @Override
    @SneakyThrows
    public void flushBuffer() {
        if (outputStream != null) {
            outputStream.flush();
        }
        if (writer != null) {
            writer.flush();
        }
    }
    /**
     * The default behavior of this method is to call reset() on the wrapped
     * response object.
     */
    @Override
    public void reset() {
        buffer.reset();
    }
    /**
     * Get response content
     *
     * @param charset HttpServletResponse#getCharacterEncoding()
     * @return response content
     */
    @SneakyThrows
    public String getResponseData(String charset) {
        // 将out、writer中的数据强制输出到WrapperResponse的buffer里面,否则取不到数据
        flushBuffer();
        return buffer.toString(StandardCharsets.UTF_8.displayName());
    }
    /**
     * 内部类,对ServletOutputStream进行包装,指定输出流的输出端
     */
    private static class WrapperOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bos = null;
        public WrapperOutputStream(ByteArrayOutputStream stream) throws IOException {
            bos = stream;
        }
        /**
         * Writes the specified byte to this output stream. The general
         * contract for <code>write</code> is that one byte is written
         * to the output stream. The byte to be written is the eight
         * low-order bits of the argument <code>b</code>. The 24
         * high-order bits of <code>b</code> are ignored.
         * <p>
         * Subclasses of <code>OutputStream</code> must provide an
         * implementation for this method.
         *
         * @param b the <code>byte</code>.
         * @throws IOException if an I/O error occurs. In particular,
         *                     an <code>IOException</code> may be thrown if the
         *                     output stream has been closed.
         */
        @Override
        public void write(int b) throws IOException {
            bos.write(b);
        }
        /**
         * Checks if a non-blocking write will succeed. If this returns
         * <code>false</code>, it will cause a callback to
         * {@link WriteListener#onWritePossible()} when the buffer has emptied. If
         * this method returns <code>false</code> no further data must be written
         * until the contain calls {@link WriteListener#onWritePossible()}.
         *
         * @return <code>true</code> if data can be written, else <code>false</code>
         * @since Servlet 3.1
         */
        @Override
        public boolean isReady() {
            return false;
        }
        /**
         * Sets the {@link WriteListener} for this {@link ServletOutputStream} and
         * thereby switches to non-blocking IO. It is only valid to switch to
         * non-blocking IO within async processing or HTTP upgrade processing.
         *
         * @param listener The non-blocking IO write listener
         * @throws IllegalStateException If this method is called if neither
         *                               async nor HTTP upgrade is in progress or
         *                               if the {@link WriteListener} has already
         *                               been set
         * @throws NullPointerException  If listener is null
         * @since Servlet 3.1
         */
        @Override
        public void setWriteListener(WriteListener listener) {
        }
    }
}
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
Linux 网络安全
【Linux】INFO: attempting to log in with the new key(s), to filter out any that are already...
【Linux】INFO: attempting to log in with the new key(s), to filter out any that are already...
588 0
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
345 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
14天前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
333 3
|
4月前
|
Kubernetes Ubuntu Windows
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
146 3
|
24天前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1710 14
|
1月前
|
存储 监控 安全
什么是日志管理,如何进行日志管理?
日志管理是对IT系统生成的日志数据进行收集、存储、分析和处理的实践,对维护系统健康、确保安全及获取运营智能至关重要。本文介绍了日志管理的基本概念、常见挑战、工具的主要功能及选择解决方案的方法,强调了定义管理目标、日志收集与分析、警报和报告、持续改进等关键步骤,以及如何应对数据量大、安全问题、警报疲劳等挑战,最终实现日志数据的有效管理和利用。
108 0
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
43 0
|
2月前
|
数据可视化
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
279 0

热门文章

最新文章