一、项目初衷

Java 应用开发的同学都知道,项目上线后,日志的可视化查询与 JVM 的可视化监控是一件非常重要的事。
市面上成熟方案一般是采用 ELK/EFK 实现日志可视化,采用 Actuator + Prometheus + Grafana 实现 JVM 监控。
这两套都是非常优秀的解决方案,不过对于很多开发者来说,这中间存在大量的繁琐的配置过程。
而对于大多数中小型企业来说,很多都是一个简单的单体项目,并不想要多余的运维和部署成本!
为此我们希望通过一些低门槛的方式,实现日志的自动采集与日志可视化查询。

二、软件介绍

我们的目标:zero-observer + zero-log = actuator + prometheus + granfana + elk / efk

1. 主要功能

  • 应用日志查询:

     提供控制台面板与列表两种方式查询应用日志;

  • 慢接口监控:

     监控 Java 服务中请求超过阈值的接口,支持通用配置与自定义配置;

  • JVM 监控:

     监控 JVM 进程中的各种指标,包括堆内存、非堆内存、Eden、Survivor、OldGen、Metaspace、线程、GC、物理内存、CPU 等。

2. 系统架构

图片

本项目主要分为客户端和服务端两个部分。

3. Java 日志采集客户端【zero-log】

采集客户端旨在提供低门槛、少配置、轻量级、无侵入的方式实现日志、JVM 指标的自动采集与发送。

zero-log 基于 logback 实现将代码中通过 log.error、log.warn、log.info、log.trace 等方式输出的日志与 JVM 运行时的各项指标自动采集并发送到远程服务器上
原系统代码无需任何改动,只需要引入 zero-log 的依赖,同时在 logback-spring.xml 中添加 HttpBatchAppender,配置采集数据接收的接口即可实现自动采集与传输。

4. 服务端【zero-observer】

收集客户端采集插件采集的客户端数据,包括应用日志、JVM 指标等,并提供开箱即用的可视化检索功能,极大降低了 Java 应用日志与 JVM 指标监控可视化检索的门槛。

5. 功能介绍

仪表盘

图片

应用日志

图片

控制台日志

图片

慢接口日志

图片

日志查询

图片

日志详情

图片

JVM 监控

图片

图片

图片

三、服务端安装

zero-observer 数据存储使用的是 mysql 与 elasticsearch,mysql 存储的是系统数据,elasticsearch 存储的是日志数据。 所以需要自行安装 mysql 与 elasticsearch。

1. Mysql 初始化脚本

创建数据库:zero_observer

CREATE TABLE `app_log_growth_trend` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`app` varchar(255) NOT NULL,`env` varchar(50) NOT NULL,`level` varchar(10) NOT NULL,`statistic_time` datetime NOT NULL,`log_count` int(11) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `app_log_total_growth_trend` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`statistic_time` datetime NOT NULL,`log_count` bigint(20) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `app_log_level_statistic` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`app` varchar(255) NOT NULL,`env` varchar(50) NOT NULL,`level` varchar(10) NOT NULL,`statistic_time` datetime NOT NULL,`log_count` int(11) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `app_env_instance` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`app` varchar(255) NOT NULL,`env` varchar(50) NOT NULL,`ip` varchar(50) NOT NULL,`port` varchar(5) NOT NULL,`hostname` varchar(255) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `app_log_statistic` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`app_log_statistic_counter_id` bigint(20) NOT NULL,`app` varchar(255) NOT NULL,`env` varchar(50) NOT NULL,`statistic_time` datetime NOT NULL,`log_count` bigint(20) NOT NULL DEFAULT '0',`slow_request_count` bigint(20) NOT NULL DEFAULT '0',`error_count` bigint(20) NOT NULL DEFAULT '0',`warn_count` bigint(20) NOT NULL DEFAULT '0',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `app_log_statistic_counter` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`statistic_time` datetime NOT NULL,`statistic_status` int(11) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `system_config` (`id` bigint(20) NOT NULL COMMENT '主键',`create_time` datetime NOT NULL COMMENT '创建时间',`key_code` varchar(50) NOT NULL COMMENT 'key编码',`key_name` varchar(50) DEFAULT NULL COMMENT 'key 名称',`key_value` varchar(255) NOT NULL COMMENT 'key值',`enabled` int(11) NOT NULL DEFAULT '1' COMMENT '是否启用',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `system_config` (`id`, `create_time`, `key_code`, `key_name`, `key_value`, `enabled`)
VALUES (1, '2025-07-19 23:56:06', 'app_log_storage_days', '应用日志存储天数', '3', 1);CREATE TABLE `users` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`account` varchar(100) NOT NULL,`pwd` varchar(255) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `token_info` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`subject` varchar(100) NOT NULL,`token` varchar(255) NOT NULL,`expire_time` datetime NOT NULL,`expire_timestamp` bigint(20) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `license` (`id` bigint(20) NOT NULL,`create_time` datetime NOT NULL,`content` text NOT NULL,`remark` text DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2. Docker 部署

# 拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/kuafucv/zero-observer:1.1.0
# 启动容器
docker run -itd -p 8080:8080 --name zero-observer \-e TZ=Asia/Shanghai-e ES_IP=127.0.0.1 \-e ES_PORT=9200 \-e ES_USERNAME=es \-e ES_PASSWORD=es \-e MYSQL_IP=127.0.0.1 \-e MYSQL_PORT=3306 \-e MYSQL_USERNAME=root \-e MYSQL_PASSWORD=123456 \registry.cn-hangzhou.aliyuncs.com/kuafucv/zero-observer:1.1.0

参数解析:

  • TZ:时区,默认 Asia/Shanghai

  • ES_IP:elasticsearch 的 ip

  • ES_PORT:elasticsearch restapi 的端口

  • ES_USERNAME:elasticsearch 用户名,无则不填即可

  • ES_PASSWORD:elasticsearch 密码,无则不填即可

  • MYSQL_IP:mysql 的ip

  • MYSQL_PORT:mysql 端口

  • MYSQL_USERNAME 用户名

  • MYSQL_PASSWORD 密码

启动成功后,浏览器访问:http://127.0.0.1:8080/zero-observer/
默认用户密码:admin/123456

四、Java 应用日志快速接入

1. 引入 maven 依赖


<dependency><groupId>io.github.kuafucv</groupId><artifactId>zero-log-spring-boot-starter</artifactId><version>1.1.0</version>
</dependency>

2. 配置 logback-spring.xml

<configuration debug="false"><springProperty name="app_name" source="spring.application.name"/><springProperty name="env" source="spring.profiles.active"/><springProperty name="port" source="server.port"/><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /><conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /><conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /><property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-[%X{TRACE_ID}] %d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/><property name="FILE_LOG_CHARSET" value="${FILE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/><appender name="BATCH_HTTP" class="io.github.kuafucv.zero.log.core.HttpBatchAppender"><!-- 必需:参照 logback 的 encoder 配置 --><encoder><pattern>${FILE_LOG_PATTERN}</pattern><charset>${FILE_LOG_CHARSET}</charset></encoder><!--请求的地址--><!-- 废弃:日志接收接口URL,该配置已过时,后续版本将删除该配置,建议使用 serverUrl 进行配置 --><endpointUrl>http://ip:port/zero-observer/appLog/report</endpointUrl><!-- 必需:日志接收接口URL --><serverUrl>http://ip:port/zero-observer/</serverUrl><!-- 必填:应用名称 --><appName>${app_name}</appName><!-- 可选:环境,默认值:env --><env>${env}</env><!-- 可选:服务端口,默认值:0 --><appServerPort>${port}</appServerPort><!-- 可选:是否包含MDC上下文 --><includeMDC>true</includeMDC><!-- 可选:日志传输频率,单位秒,默认值:3 秒 --><flushIntervalInSeconds>3</flushIntervalInSeconds><!-- 可选:请求超时时间,默认值:1000 毫秒 --><httpReadTimeoutInMillis>1000</httpReadTimeoutInMillis><!-- 可选:请求超时时间,默认值:1000 毫秒 --><httpConnectionTimeoutInMillis>1000</httpConnectionTimeoutInMillis><!-- 可选:日志存储滚筒最大数量,默认值:8 --><maxNumberOfBuckets>8</maxNumberOfBuckets><!-- 可选:每个日志存储滚筒大小(KB),默认值:1024 --><maxBucketSizeInKilobytes>1024</maxBucketSizeInKilobytes></appender><!-- 日志输出级别 --><root level="INFO"><appender-ref ref="BATCH_HTTP" /></root>
</configuration>

注意:

  • 这里仅仅展示 springboot 下的 logback-spring-xml 的配置,非 springboot 项目自行配置。

  • 主要是新增 io.github.kuafucv.zero.log.core.HttpBatchAppender 日志 Appender,该 Appender 中的 encoder 建议与原项目中输出到日志文件的 encoder 一致。

  • endpointUrl(过时) 为日志接收的远程日志中心接口,zero-log 会自动调用该接口,并发送日志数据

  • 推荐使用 serverUrl,该属性值为 http://ip:port/zero-observer/

3. 全量配置列表

图片

4. 日志观测

启动 Java 服务,等待日志自动上报至 zero-observer 即可。

五、Java 慢接口监控

1. 快速接入

SpringBoot 工程

springboot 工程引入zero-log-spring-boot-starter包,则自动开启慢接口监控。可以通过配置zero.log.slow-request.enabled=false进行关闭。

zero:log:slow-request:# 是否开启慢接口健康enabled: true# 默认时间阈值(毫秒)default-time-threshold: 1000
非 SpringBoot 工程

非 springboot 工程引入的是zero-log-core包,无法使用 starter 的自动装配,所以需要手

@Bean
public FilterRegistrationBean<SlowRequestFilter> slowRequestFilterFilterRegistrationBean() {FilterRegistrationBean<SlowRequestFilter> bean = new FilterRegistrationBean<>();bean.setFilter(new SlowRequestFilter());bean.setOrder(Integer.MIN_VALUE);bean.setUrlPatterns(Collections.singletonList("/*"));return bean;
}

其他更古老的项目,如使用 servlet 的 web.xml 配置的方式,请自行配置。

2. 高阶配置

同一系统不同的接口,慢的时间阈值可能存在一定差别,zero-log 支持高阶的自定义配置,实现不同接口的不同阈值配置能力。

@Component
public class SlowRequestThresholdFactoryImpl implements SlowRequestThresholdFactory {@Overridepublic List<SlowRequestThreshold> build() {List<SlowRequestThreshold> list = new ArrayList<>();SlowRequestThreshold s0 = new SlowRequestThreshold();s0.setUrlPattern("/**/user/**");s0.setTimeThreshold(500);list.add(s1);SlowRequestThreshold s1 = new SlowRequestThreshold();s1.setUrlPattern("/**");s1.setTimeThreshold(2000);list.add(s1);return list;}
}

不论是否是 springboot 工程,本质都是通过实现 SlowRequestThresholdFactory 接口的 build 方法,返回 List 集合,实现自定义不同接口的不同阈值能力。

注意事项:

接口匹配是通过 spring 的 AntPathMatcher 实现的,所以 SlowRequestThreshold.urlPattern 的值配置规则参考 spring AntPathMatcher 匹配规则。接口匹配根据放回的 List 从上到下逐个匹配,匹配到了则不再继续匹配,所以 urlPattern 范围更大的配置需要发放在 List 集合的的后面。如果匹配不到,则使用默认阈值。默认阈值与 SlowRequestThreshold 里设置的阈值,如果 小于等于 0,则默认该接口不做慢接口监控,不会进行日志输出。

开源地址:

https://gitee.com/kuafucv/zero-observer

架构设计之道在于在不同的场景采用合适的架构设计,架构设计没有完美,只有合适。

在代码的路上,我们一起砥砺前行。用代码改变世界!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96748.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96748.shtml
英文地址,请注明出处:http://en.pswp.cn/web/96748.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode hot 100】101.对称二叉树

问题链接 101.对称二叉树 问题描述 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;…

Zynq开发实践(FPGA之选择开发板)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】我们之所以选用zynq开发板&#xff0c;就在于它支持arm软件开发&#xff0c;也支持fpga开发&#xff0c;甚至可以运行linux&#xff0c;这是之前没有…

Flutter Riverpod 3.0 发布,大规模重构下的全新状态管理框架

在之前的 《注解模式下的 Riverpod 有什么特别之处》我们聊过 Riverpod 2.x 的设计和使用原理&#xff0c;同时当时我们就聊到作者已经在开始探索 3.0 的重构方式&#xff0c;而现在随着 Riverpod 3.0 的发布&#xff0c;riverpod 带来了许多细节性的变化。 当然&#xff0c;这…

Xcode 上传 ipa 全流程详解 App Store 上架流程、uni-app 生成 ipa 文件上传与审核指南

对于 iOS 开发者而言&#xff0c;应用开发完成后最重要的一步就是将应用打包为 ipa 文件&#xff0c;并上传至 App Store Connect 进行分发或上架。 其中&#xff0c;Xcode 上传 ipa 是最常见的方法&#xff0c;但很多开发者在实际操作中常常遇到卡住、上传失败或签名错误等问题…

快速选中对象

图片要求 图片背景单纯&#xff0c;对象边缘比较清晰 对象选择工具 选择对象选择工具后&#xff0c;画出大致区域&#xff0c;系统将自动分析图片内容&#xff0c;从而实现快速选择图片中的一个惑多个对象他有两种模式&#xff0c;分别是举行与套索模式。使用时可以先选中对象的…

点到点链路上的OSPF动态路由(2025年9月10日)

一、前言前面我们已经分享过了静态路由、缺省路由、浮动静态路由这些静态路由的配置。接下来将会 陆陆续续开始分享动态路由以及其他路由配置。博主这里是一个新人&#xff0c;了解这些路由配置不是自上而下的&#xff0c;而是自下而上的&#xff0c;也就是说通过实验去理解原理…

技术视界 | 末端执行器:机器人的“手”,如何赋予机器以生命?

在现代自动化系统中&#xff0c;末端执行器&#xff08;End Effector&#xff09;作为机器人与物理世界交互的“手”&#xff0c;发挥着至关重要的作用。它直接安装在机械臂末端&#xff0c;不仅是机器人实现“抓取、感知和操作”三大核心功能的关键部件&#xff0c;更是整个自…

滑动窗口概述

滑动窗口算法简介滑动窗口是一种用于处理数组或字符串子区间问题的高效算法。它通过维护一个动态窗口&#xff08;通常由两个指针表示&#xff09;来避免重复计算&#xff0c;将时间复杂度从O(n)优化到O(n)。基本实现步骤初始化窗口指针&#xff1a;通常使用left和right指针表示…

AI 创建学生管理系统

使用腾讯元宝创建&#xff0c;整体效果不错。修正2个bug跑起来&#xff0c;达到了需要的功能先上效果图&#xff1a;按钮分类别配色&#xff0c;界面清爽。喜欢这布局创建过程&#xff1a;prompt: 使用最新稳定vue版&#xff0c;使用pinia存储&#xff0c;基于typescript, 样式…

ASP.NET Core 中的简单授权

ASP.NET Core 中的授权通过 [Authorize] 属性及其各种参数控制。 在其最基本的形式中&#xff0c;通过向控制器、操作或 [Authorize] Page 应用 Razor 属性&#xff0c;可限制为仅允许经过身份验证的用户访问该组件。 使用 [Authorize] 属性 以下代码限制为仅允许经过身份验证…

leetcode 493 翻转对

一、题目描述 二、解题思路 本题的思路与逆序数的思路相似&#xff0c;采用归并排序的思路来实现。leetcode LCR 170.交易逆序对的总数-CSDN博客 注意&#xff1a;但是逆序数的ret更新在左、右区间合并时更新&#xff0c;但本题ret更新在左、右区间合并前更新。 三、代码实现…

初识微服务-nacos配置中心

配置中心 概述 配置中心是微服务中不可或缺的组件&#xff0c;因为如果没有配置中心&#xff0c;那么各个微服务的的配置信息无法得到统一和管理&#xff0c;会变得冗余。 :::color4 配置中心是用于管理应用程序配置信息的工具 集中管理配置&#xff1a;解决微服务架构下配置分…

Android webview更新记录-aosp

一、下载 webview下载地址&#xff0c;感谢火哥分享&#xff0c;版本很全。 https://www.firepx.com/app/android-system-webview/ 二、更新 external/chromium-webview/prebuilt 具体更新那个目录&#xff0c;需要查看编译架构 这个看你的lunch就行&#xff0c;这里我的是a…

无感FOC(无传感器磁场定向控制)

我们来详细解析无感FOC&#xff08;无传感器磁场定向控制&#xff09;中的高频方波注入&#xff08;High-Frequency Square-Wave Injection, HFSWI&#xff09;​​ 的原理。这是一个用于零低速或极低速范围内估算转子位置的核心技术。核心思想与要解决的问题在电机静止或转速极…

MATLAB基于博弈论组合赋权-云模型的煤与瓦斯突出危险性评价

MATLAB基于博弈论组合赋权-云模型的煤与瓦斯突出危险性评价 1. 问题背景与核心目标 背景&#xff1a;煤与瓦斯突出是煤矿生产中的一种极其复杂的动力灾害&#xff0c;其发生机理复杂&#xff0c;影响因素众多&#xff08;如地应力、瓦斯压力、煤体物理属性等&#xff09;。对其…

JavaWeb-Servlet总结及JSP

目录 一、文件下载 二、ServletConfig对象 三、Web.xml文件使用总结 四、server.xml文件 五、JSP动态网页技术 1.概念&#xff1a; 2.动态网页&#xff1a; 3.特点&#xff1a; 4.JSP的访问原理&#xff1a; 5.JSP的文档说明&#xff1a; 6.jsp实际运行文件&#xff…

DDIM和DDPM之 间的区别与联系

核心关系概述 首先&#xff0c;要理解DDIM并不是一个全新的模型&#xff0c;而是DDPM的一个精巧的重新参数化和扩展。它们使用完全相同的训练目标和方法&#xff0c;因此你可以用一个训练好的DDPM模型直接来运行DDIM的采样算法&#xff0c;而无需重新训练。 DDIM的核心贡献是&a…

c++---map和set

这里再提二叉树&#xff08;二叉搜索树&#xff09;&#xff0c;是为了后面讲解map和set做准备。 一、二叉搜索树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树。 若它的左子树不为空&#xff0c;则左子树上所有节点的值都…

windows下,podman迁移镜像文件位置

docker-desktop有自带的镜像文件位置迁移功能&#xff0c;但podman-desktop还没有&#xff0c;所以只能自己操作wsl导入导出来实现# 1.一定要先停止当前machine podman machine stop# 2. 导出当前 machine&#xff08;会生成 tar 镜像&#xff09; wsl --export podman-machine…

Champ-基于3D的人物图像到动画视频生成框架

本文转载自&#xff1a;https://www.hello123.com/champ ** 一、&#x1f916; Champ 是什么&#xff1f; 阿里 南大 复旦联手打造的虚拟人动作黑科技&#xff01;Champ 可不是普通动画工具&#xff0c;它能把你随手拍的小视频变成专业级 3D 动画 —— 无论跳舞、打拳还是走…