java 如何实现在线日志

如何采集springboot日志至web页面查看

实现方案

基于Filter方式,在日志输出至控制台前,LoggerFitler 拦截日志通过websocket推送至前台页面

实现逻辑:
LoggerFilter采集日志添加至LoggerQueue队列,
LoggerConsumer 从LoggerQueue中采集推送至前台页面

push
pull
socket
LoggerFilter
LoggerQueue
LoggerConsumer
wsLog.html

1. 配置拦截器

  • logback 在appender中指定filter 拦截
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%magenta(%d{yyyy-MM-dd HH:mm:ss.SSS}) %highlight(%-5level) %green([%thread]) %logger{40}: %m %n
            </pattern>
            <charset>utf8</charset>
        </encoder>
        <filter class="com.weblog.logger.LoggerFilter"></filter>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

2. 代码逻辑

2.1 LoggerFilter 拦截日志来源

从ILoggingEvent 获取日志信息,封装为LoggerMessage ,添加至日志队列

public class LoggerFilter extends Filter<ILoggingEvent> {


    private String formatTime(long timestamp) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        return simpleDateFormat.format(new Date(timestamp));
    }

    /**
     * 解析日志事件信息内容 加入队列
     *
     * @param event 日志事件
     */
    @Override
    public FilterReply decide(ILoggingEvent event) {
        LoggerMessage log = new LoggerMessage();
        log.setClassInfo(event.getLoggerName());
        log.setLogTime(formatTime(event.getTimeStamp()));
        log.setLogInfo(event.getFormattedMessage());
        log.setLogLevel(event.getLevel().levelStr);
        String exception = "";
        IThrowableProxy throwableProxy = event.getThrowableProxy();
        if (throwableProxy != null) {
            exception = ThrowableProxyUtil.asString(throwableProxy);
        }
        log.setErrorInfo(exception);
        LoggerQueue.getInstance().push(log);
        return FilterReply.ACCEPT;
    }
}
2.2 LoggerQueue 提供日志的存放与获取

内置队列管理器, 提供pull 和push方法
代码未优化,队列应该选择先进先出

public class LoggerQueue {
    /**
     * 最大队列大小
     */
    public static final int QUEUE_MAX_SIZE = 10000;

    /**
     * 日志队列
     */
    private static LoggerQueue loggerQueue = new LoggerQueue();

    /**
     * 阻塞队列
     */
    private BlockingQueue<LoggerMessage> blockingQueue = new LinkedBlockingQueue<LoggerMessage>(QUEUE_MAX_SIZE);

    private LoggerQueue() {
    }

    public static LoggerQueue getInstance() {
        return loggerQueue;
    }

    /**
     * 推送最新日志消息
     *
     * @param loggerMessage 日志消息
     * @return 是否成功
     */
    public boolean push(LoggerMessage loggerMessage) {
        return this.blockingQueue.add(loggerMessage);//队列满了就抛出异常,不阻塞
    }

    /**
     * 拉取最新日志消息
     *
     * @return 日志消息
     */
    public LoggerMessage pull() {
        LoggerMessage loggerMessage = null;
        try {
            loggerMessage = this.blockingQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return loggerMessage;
    }
}
2.4 WebSocketLoggerConsumer 实现消息推送至websocket

开启固定线程,获取日志队列信息,推送至websocket

@Component
public class WebSocketLoggerConsumer implements LoggerConsumer {

    @Resource
    private SimpMessagingTemplate messagingTemplate;

    /**
     * 创建日志消费线程池
     */
    @PostConstruct
    public void createLogExecutor() {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    LoggerQueue loggerQueue = LoggerQueue.getInstance();
                    if (loggerQueue != null) {
                        consumer(loggerQueue.pull());
                    }
                }
            }
        };
        executorService.submit(runnable);
    }

    @Override
    public void consumer(LoggerMessage loggerMessage) {
        messagingTemplate.convertAndSend("/topic/log", loggerMessage.toString());
    }
}

3. 测试

3.1 测试示例

1s 写入1条info日志,2s 写入1条warn 日志

    @Scheduled(fixedDelay = 1000)
    private void mockLogInfoData() {
        logger.info("logger info data!");
    }

    @Scheduled(fixedDelay = 2000)
    private void mockLogWarnData() {
        logger.warn("logger warn data!");
    }
3.2 idea 控制台日志:

在这里插入图片描述

3.3 socket日志效果

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值