# zero-observer
**Repository Path**: yc-fork/zero-observer
## Basic Information
- **Project Name**: zero-observer
- **Description**: 一个开箱即用的一站式 Java 应用日志观测工具,无需各种复杂繁琐的配置,使用门槛低。
- **Primary Language**: Unknown
- **License**: GPL-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 6
- **Created**: 2025-07-21
- **Last Updated**: 2025-07-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# zero-observer
## 一、背景
Java 应用开发时,服务器上的日志往往是以日志文件的形式存在。在日常维护时,通常需要将日志信息实现可视化查询。
ELK、EFK 等是优秀的日志可视化查询解决方案。不过对于部分开发者来说,日志的采集配置与日志可视化配置是一个比较繁琐的过程。
为此我们希望通过一些低门槛的方式,实现日志的自动采集与日志可视化查询。
本项目主要分为客户端和服务端两个部分。
### Java 日志采集客户端
zero-log Java 日志采集客户端:https://gitee.com/kuafucv/zero-log
> 日志采集客户端旨在提供低门槛、少配置、轻量级、无侵入的方式实现日志的自动采集与发送。
zero-log 基于 logback 实现将代码中通过 log.error、log.warn、log.info、log.trace
等方式输出的日志**_自动采集并发送到远程服务器上_**。
原系统代码的日志输出方式无需任何改动,只需要引入 zero-log 的依赖,同时在 logback-spring.xml 中添加 HttpBatchAppender,配置日志数据接收的接口即可实现日志的自动采集与传输。
### 服务端:
zero-observer 猿观测服务端 https://gitee.com/kuafucv/zero-observer
依托于 客户端[zero-log](https://gitee.com/kuafucv/zero-log) 的自动化日志采集插件,实现接收 Java 应用上报的日志数据,并提供开箱即用的日志可视化检索功能,极大降低了 Java 应用日志可视化检索的门槛。
> 请注意:
>
> 服务端从 1.0.0 之后,访问路径变更为 http://ip:port/zero-observer/ ,所以 logback 配置文件中 endpointUrl 属性值也需要修改为 http://ip:port/zero-observer/appLog/report 。
## 二、软件介绍
### 1. 软件结构图

### 2. 版本升级指南
请异步至 >>> [版本升级记录](VERSIONS.md) <<<
### 3. 功能介绍
#### 仪表盘

#### 应用日志

##### 应用控制台日志

##### 应用慢接口日志

##### 应用日志查询

##### 应用日志详情

## 三、服务端安装
> zero-observer 数据存储使用的是 mysql 与 elasticsearch,mysql 存储的是系统数据,elasticsearch 存储的是日志数据。
> 所以需要自行安装 mysql 与 elasticsearch。
### 1. Mysql 初始化脚本
创建数据库:zero_observer,执行下面建表语句。
```mysql
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);
```
### 2 安装方式
#### Docker 部署
```shell
# 拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/kuafucv/zero-observer:1.0.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.0.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/
#### Jar 包部署
下载 zero-observer.jar 与 start 启动器
Linux 启动
```shell
./start java -jar zero-observer.jar
```
windows 启动
```
start.exe java -jar zero-observer.jar
```
启动成功后,浏览器访问:http://127.0.0.1:9999/zero-observer/
> 默认 server.port=9999,有需要请自行更改
>
> 本项目采用 jdk1.8 编译开发,如果使用的时候 jdk 11 以上的 版本,需要在启动参数中额外加两个参数
> - --add-opens java.base/java.net=ALL-UNNAMED
> - --add-exports java.base/jdk.internal.loader=ALL-UNNAMED
>
> ./start java --add-opens java.base/java.net=ALL-UNNAMED --add-exports java.base/jdk.internal.loader=ALL-UNNAMED -jar zero-observer.jar
#### 访问入口
0.0.3 版本以前,访问路径是 http://ip:port 直接访问的。
有小伙伴反馈自己公司的项目环境只能暴露一个端口出去,所以需要有 context-path 做代理配置。
故而从 0.0.4 版本及以后,访问路径统一改为 http://ip:port/zero-observer/,有需要的小伙伴通过 zero-observer 进行代理配置。
如果有同学还是想要通过 http://ip:port 或者域名直接访问,不想后面再跟上 context-path 的,也可以通过 Nginx 进行一层代理。
## 四、Java 应用日志快速接入
Java 应用引入 [zero-log](https://gitee.com/kuafucv/zero-log) 即可。
### 1. 引入 maven 依赖
#### SpringBoot 工程
```xml
io.github.kuafucv
zero-log-spring-boot-starter
1.0.0
```
#### 非 SpringBoot 工程
```xml
io.github.kuafucv
zero-log-core
1.0.0
```
### 2. 配置 logback-spring.xml
```xml
${FILE_LOG_PATTERN}
${FILE_LOG_CHARSET}
http://ip:port/zero-observer/appLog/report
true
${app_name}
${env}
${port}
3
1000
1000
8
1024
```
> 注意:
> 这里仅仅展示 springboot 下的 logback-spring-xml 的配置,非 springboot 项目自行配置。
> 主要是新增 io.github.kuafucv.zero.log.core.HttpBatchAppender 日志 Appender,该 Appender 中的 encoder 建议与原项目中输出到日志文件的 encoder 一致。
### 3. 日志观测
启动 Java 服务,等待日志自动上报至 zero-observer 即可。
## 五、Java 慢接口监控
### 1 快速接入
#### SpringBoot 工程
springboot 工程引入`zero-log-spring-boot-starter`包,则自动开启慢接口监控。可以通过配置`zero.log.slow-request.enabled=false`进行关闭。
```yaml
zero:
log:
slow-request:
# 是否开启慢接口健康
enabled: true
# 默认时间阈值(毫秒)
default-time-threshold: 1000
```
#### 非 SpringBoot 工程
非 springboot 工程引入的是`zero-log-core`包,无法使用 starter 的自动装配,所以需要手动配置 `SlowRequestFilter`。
```java
@Bean
public FilterRegistrationBean slowRequestFilterFilterRegistrationBean() {
FilterRegistrationBean bean = new FilterRegistrationBean<>();
bean.setFilter(new SlowRequestFilter());
bean.setOrder(Integer.MIN_VALUE);
bean.setUrlPatterns(Collections.singletonList("/*"));
return bean;
}
```
> 其他更古老的项目,如使用 servlet 的 web.xml 配置的方式,请自行配置。
### 2 高阶配置
同一系统不同的接口,慢的时间阈值可能存在一定差别,zero-log 支持高阶的自定义配置,实现不同接口的不同阈值配置能力。
#### SpringBoot 工程
```java
@Component
public class SlowRequestThresholdFactoryImpl implements SlowRequestThresholdFactory {
@Override
public List build() {
List 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 工程
```java
public class SlowRequestThresholdFactoryImpl implements SlowRequestThresholdFactory {
@Override
public List build() {
List 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;
}
}
@Bean
public SlowRequestThresholdFactory slowRequestThresholdFactory() {
return new SlowRequestThresholdFactoryImpl();
}
@Bean
public FilterRegistrationBean slowRequestFilterFilterRegistrationBean(SlowRequestThresholdFactory slowRequestThresholdFactory) {
FilterRegistrationBean bean = new FilterRegistrationBean<>();
bean.setFilter(new SlowRequestFilter(1000, slowRequestThresholdFactory));
bean.setOrder(Integer.MIN_VALUE);
bean.setUrlPatterns(Collections.singletonList("/*"));
return bean;
}
```
不论是否是 springboot 工程,本质都是通过实现 SlowRequestThresholdFactory 接口的 build 方法,返回 List 集合,实现自定义不同接口的不同阈值能力。
>注意事项:
>1. 接口匹配是通过 spring 的 AntPathMatcher 实现的,所以 SlowRequestThreshold.urlPattern 的值配置规则参考 spring AntPathMatcher 匹配规则。
>2. 接口匹配根据放回的 List 从上到下逐个匹配,匹配到了则不再继续匹配,所以 urlPattern 范围更大的配置需要发放在 List 集合的的后面。
>3. 如果匹配不到,则使用默认阈值。
>4. 默认阈值与 SlowRequestThreshold 里设置的阈值,如果 小于等于 0,则默认该接口不做慢接口监控,不会进行日志输出。
## 联系我们
#### 微信

#### QQ群

如有使用问题或者建议,欢迎联系我,备注[猿观测]。
## 赞助支持


你的赞助是我坚持的最佳动力❤️❤️❤️