Ruoyi框架之系统监控的编写
大体思路
1. 项目初始化
- 使用Spring Initializr来生成一个基本的Spring Boot项目,选择
Spring Web
、Spring Boot Actuator
和Spring Data
等依赖。
2. 定义模块结构
- 创建一个独立的监控模块,放置在
com.example.monitor
包下,包含以下部分:controller
:用于处理HTTP请求,返回监控数据。service
:用于封装监控逻辑。model
:用于定义监控数据的模型类。
3. 获取系统资源信息
- 使用Java的
ManagementFactory
和OperatingSystemMXBean
来获取CPU、内存等资源的信息。 - 创建
SystemMetricsService
类,获取并封装系统资源信息。
4. 暴露监控数据
- 创建一个RESTful API控制器
SystemMetricsController
,通过HTTP GET请求获取当前系统的CPU、内存和虚拟机相关信息。
5. 前端展示
- 编写简单的HTML或使用Vue.js来展示这些监控数据。
- 通过AJAX定时请求后台API,动态展示监控数据。
6. 优化与扩展
- 监控更多的系统指标,如磁盘使用、网络流量等。
- 使用Spring Boot Actuator来暴露更多的监控端点。
- 实现告警机制,当系统指标超过阈值时,发送通知或记录日志
具体实现
1. 项目初始化
首先,使用 Spring Initializr 初始化一个Spring Boot项目。选择以下依赖:
- Spring Web
- Spring Boot Actuator
生成项目后,下载并解压,然后导入到你的IDE中。
2. 定义模块结构
在src/main/java/com/example/monitor
包下,创建以下目录结构:
com/example/monitor/
├── controller
│ └── SystemMetricsController.java
├── service
│ └── SystemMetricsService.java
└── model
└── SystemMetrics.java
3. 获取系统资源信息
首先,创建一个SystemMetrics
模型类,用于封装系统资源信息:
package com.example.monitor.model;
public class SystemMetrics {
private double cpuLoad;
private long totalMemory;
private long freeMemory;
private long maxMemory;
// getters and setters
public double getCpuLoad() {
return cpuLoad;
}
public void setCpuLoad(double cpuLoad) {
this.cpuLoad = cpuLoad;
}
public long getTotalMemory() {
return totalMemory;
}
public void setTotalMemory(long totalMemory) {
this.totalMemory = totalMemory;
}
public long getFreeMemory() {
return freeMemory;
}
public void setFreeMemory(long freeMemory) {
this.freeMemory = freeMemory;
}
public long getMaxMemory() {
return maxMemory;
}
public void setMaxMemory(long maxMemory) {
this.maxMemory = maxMemory;
}
}
然后,创建SystemMetricsService
服务类,用于获取CPU和内存信息:
package com.example.monitor.service;
import com.example.monitor.model.SystemMetrics;
import org.springframework.stereotype.Service;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
@Service
public class SystemMetricsService {
public SystemMetrics getSystemMetrics() {
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
SystemMetrics metrics = new SystemMetrics();
// 获取CPU负载(系统负载平均值)
metrics.setCpuLoad(osBean.getSystemLoadAverage());
// 获取JVM内存使用情况
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
long maxMemory = Runtime.getRuntime().maxMemory();
metrics.setTotalMemory(totalMemory);
metrics.setFreeMemory(freeMemory);
metrics.setMaxMemory(maxMemory);
return metrics;
}
}
4. 暴露监控数据
接下来,创建一个控制器SystemMetricsController
,通过RESTful API来提供监控数据:
package com.example.monitor.controller;
import com.example.monitor.model.SystemMetrics;
import com.example.monitor.service.SystemMetricsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/metrics")
public class SystemMetricsController {
@Autowired
private SystemMetricsService systemMetricsService;
@GetMapping
public SystemMetrics getSystemMetrics() {
return systemMetricsService.getSystemMetrics();
}
}
启动应用后,你可以通过访问 http://localhost:8080/api/metrics
来查看监控数据。
5. 前端展示
如果你想简单展示这些数据,可以创建一个简单的HTML页面,使用JavaScript的fetch
API来获取数据:
在src/main/resources/static/
下创建一个index.html
文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>System Metrics</title>
</head>
<body>
<h1>System Metrics</h1>
<div>
<p>CPU Load: <span id="cpuLoad"></span></p>
<p>Total Memory: <span id="totalMemory"></span></p>
<p>Free Memory: <span id="freeMemory"></span></p>
<p>Max Memory: <span id="maxMemory"></span></p>
</div>
<script>
async function fetchMetrics() {
const response = await fetch('/api/metrics');
const data = await response.json();
document.getElementById('cpuLoad').textContent = data.cpuLoad;
document.getElementById('totalMemory').textContent = data.totalMemory;
document.getElementById('freeMemory').textContent = data.freeMemory;
document.getElementById('maxMemory').textContent = data.maxMemory;
}
setInterval(fetchMetrics, 5000); // 每5秒获取一次数据
fetchMetrics(); // 初始获取数据
</script>
</body>
</html>
启动Spring Boot应用后,访问 http://localhost:8080/
就可以看到系统的监控数据了。
6. 优化与扩展
你可以继续扩展和优化这个模块,以下是一些建议:
-
监控更多指标:通过扩展
SystemMetricsService
,添加磁盘使用情况、网络流量等监控信息。 -
告警机制:当某些指标超过预设的阈值时,可以通过邮件、短信或者其他通知方式进行告警。
-
集成Spring Boot Actuator:Actuator可以提供更多的内置监控端点,帮助你监控应用健康状况。你可以在
application.properties
中启用更多的Actuator端点。
通过这些步骤,你将能够从零开始构建一个自定义的服务监控模块。这个模块可以帮助你更好地了解和管理你的应用。
具体时间监控的逻辑和模块使用
要实现对系统资源的监控,具体来说就是获取并展示系统的CPU负载、内存使用情况等信息。我们会使用Java标准库中的ManagementFactory
和OperatingSystemMXBean
来获取这些系统资源数据。
1. CPU 负载监控
Java 提供了 OperatingSystemMXBean
接口,可以通过 ManagementFactory
获取系统的管理接口,用于监控CPU负载。
- CPU 负载:系统的平均负载(通常是最近1分钟的平均值),可以通过
getSystemLoadAverage()
方法获取。
2. 内存使用情况监控
Java 的 Runtime
类提供了用于获取JVM内存使用情况的方法:
- Total Memory:JVM的总内存,可以通过
Runtime.getRuntime().totalMemory()
获取。 - Free Memory:JVM当前的空闲内存,可以通过
Runtime.getRuntime().freeMemory()
获取。 - Max Memory:JVM可以使用的最大内存,可以通过
Runtime.getRuntime().maxMemory()
获取。
SystemMetricsService类的实现
我们将以上的监控逻辑封装到 SystemMetricsService
服务类中,该类负责从系统中提取这些信息,并返回给调用方。
package com.example.monitor.service;
import com.example.monitor.model.SystemMetrics;
import org.springframework.stereotype.Service;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
@Service
public class SystemMetricsService {
public SystemMetrics getSystemMetrics() {
// 获取操作系统管理接口
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
// 实例化我们的数据模型类
SystemMetrics metrics = new SystemMetrics();
// 获取并设置 CPU 负载
metrics.setCpuLoad(osBean.getSystemLoadAverage());
// 获取并设置内存使用情况
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
long maxMemory = Runtime.getRuntime().maxMemory();
metrics.setTotalMemory(totalMemory);
metrics.setFreeMemory(freeMemory);
metrics.setMaxMemory(maxMemory);
return metrics;
}
}
代码解释
-
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
:这个对象可以用来获取与操作系统相关的信息,如CPU负载。 -
osBean.getSystemLoadAverage();
:获取系统的平均负载,这个值通常表示最近一段时间(通常是1分钟)内的系统负载。 -
Runtime.getRuntime().totalMemory()
:返回当前JVM可以使用的内存总量。 -
Runtime.getRuntime().freeMemory()
:返回当前JVM中可用的空闲内存。 -
Runtime.getRuntime().maxMemory()
:返回JVM的最大可用内存。
总结
到目前为止,我们已经完成了SystemMetricsService
类的实现,这个类能够收集系统的CPU负载和内存使用情况。下一步,我们将创建一个控制器,将这些监控数据暴露为RESTful API,以便可以通过HTTP请求来访问这些信息。
扩展和优化
更新 SystemMetricsService
类
我们会在 SystemMetricsService
中增加对磁盘使用情况和线程信息的获取。
package com.example.monitor.service;
import com.example.monitor.model.SystemMetrics;
import org.springframework.stereotype.Service;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.ThreadMXBean;
@Service
public class SystemMetricsService {
public SystemMetrics getSystemMetrics() {
// 获取操作系统管理接口
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
// 实例化我们的数据模型类
SystemMetrics metrics = new SystemMetrics();
// 获取并设置 CPU 负载
metrics.setCpuLoad(osBean.getSystemLoadAverage());
// 获取并设置内存使用情况
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
long maxMemory = Runtime.getRuntime().maxMemory();
metrics.setTotalMemory(totalMemory);
metrics.setFreeMemory(freeMemory);
metrics.setMaxMemory(maxMemory);
// 获取并设置磁盘使用情况
File diskPartition = new File("/"); // "/" 表示根目录,可以改为指定分区
long totalDiskSpace = diskPartition.getTotalSpace();
long freeDiskSpace = diskPartition.getFreeSpace();
long usableDiskSpace = diskPartition.getUsableSpace();
metrics.setTotalDiskSpace(totalDiskSpace);
metrics.setFreeDiskSpace(freeDiskSpace);
metrics.setUsableDiskSpace(usableDiskSpace);
// 获取并设置线程信息
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
metrics.setThreadCount(threadBean.getThreadCount());
return metrics;
}
}
优化数据展示
为了使数据更易理解,我们将以下内容转换为人类可读的格式:
- 内存使用情况:将字节转换为MB或GB,并计算使用率。
- 磁盘使用情况:将字节转换为GB,并计算使用率。
我们已经在 SystemMetrics
类中实现了内存和磁盘使用的百分比计算方法。接下来,我们将展示如何将这些数据在前端以更易理解的方式显示出来。
前端展示改进
我们将增强前端展示,通过进度条来显示资源的使用率,数据格式转换成MB或GB等。
更新 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>System Metrics</title>
<style>
.progress-bar {
width: 100%;
background-color: #f3f3f3;
border-radius: 5px;
margin-bottom: 10px;
}
.progress-bar-fill {
display: block;
height: 20px;
background-color: #4caf50;
border-radius: 5px;
width: 0;
transition: width 0.5s ease-in-out;
}
.metric {
font-weight: bold;
}
</style>
</head>
<body>
<h1>System Metrics</h1>
<div>
<p class="metric">CPU Load: <span id="cpuLoad"></span></p>
<p class="metric">Memory Usage: <span id="usedMemory"></span> / <span id="maxMemory"></span> (MB)
<span id="memoryUsagePercentage"></span>%</p>
<div class="progress-bar">
<span id="memoryProgress" class="progress-bar-fill"></span>
</div>
<p class="metric">Disk Usage: <span id="usedDiskSpace"></span> / <span id="totalDiskSpace"></span> (GB)
<span id="diskUsagePercentage"></span>%</p>
<div class="progress-bar">
<span id="diskProgress" class="progress-bar-fill"></span>
</div>
<p class="metric">Thread Count: <span id="threadCount"></span></p>
</div>
<script>
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
async function fetchMetrics() {
const response = await fetch('/api/metrics');
const data = await response.json();
// 更新CPU负载
document.getElementById('cpuLoad').textContent = data.cpuLoad.toFixed(2);
// 更新内存使用情况
document.getElementById('usedMemory').textContent = formatBytes(data.totalMemory - data.freeMemory);
document.getElementById('maxMemory').textContent = formatBytes(data.maxMemory);
document.getElementById('memoryUsagePercentage').textContent = data.memoryUsagePercentage.toFixed(2);
document.getElementById('memoryProgress').style.width = data.memoryUsagePercentage + '%';
// 更新磁盘使用情况
document.getElementById('usedDiskSpace').textContent = formatBytes(data.totalDiskSpace - data.freeDiskSpace, 2);
document.getElementById('totalDiskSpace').textContent = formatBytes(data.totalDiskSpace, 2);
document.getElementById('diskUsagePercentage').textContent = data.diskUsagePercentage.toFixed(2);
document.getElementById('diskProgress').style.width = data.diskUsagePercentage + '%';
// 更新线程数
document.getElementById('threadCount').textContent = data.threadCount;
}
setInterval(fetchMetrics, 5000); // 每5秒获取一次数据
fetchMetrics(); // 初始获取数据
</script>
</body>
</html>
前端代码解释
-
格式化字节数据:
formatBytes()
函数将字节转换为更容易理解的MB、GB等。 -
进度条:
progress-bar-fill
用于展示资源使用率的进度条。通过调整其宽度展示内存和磁盘使用的百分比。 -
周期性数据获取:通过
setInterval
,每5秒从后端获取最新的系统资源数据,并动态更新页面内容。
总结
监控模块不仅能够监控更多的系统资源信息(如磁盘使用和线程数量),而且通过优化后的数据展示方式,用户可以更直观地理解这些信息。你可以根据需求进一步扩展这个模块,比如增加更多的监控指标、告警机制或更复杂的前端展示。
Spring Boot Actuator 是一个用于监控和管理 Spring Boot 应用程序的子项目,它提供了一组内置的端点,用于暴露应用程序的运行时信息,如健康状态、环境属性、日志配置、JVM 指标等。接下来,我们将 Spring Boot Actuator 集成到当前的监控模块中。
集成Spring Boot Actuator
1. 引入 Spring Boot Actuator 依赖
首先,确保在 pom.xml
文件中引入了 Spring Boot Actuator 的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
这个依赖会自动包含 Actuator 的所有核心功能。
2. 配置 Actuator 端点
接下来,我们可以在 application.properties
文件中配置 Actuator 的端点访问路径及其安全性。默认情况下,只有部分端点是启用的,我们可以通过配置启用其他端点。
在 src/main/resources/application.properties
文件中添加以下配置:
# 设置所有 Actuator 端点可用
management.endpoints.web.exposure.include=*
# 自定义 Actuator 端点路径(可选)
management.endpoints.web.base-path=/actuator
# 开启健康检查
management.endpoint.health.show-details=always
3. 访问 Actuator 端点
现在,Spring Boot Actuator 已经集成到应用中。你可以通过浏览器或其他 HTTP 客户端访问以下一些常用的端点:
- 健康检查:
http://localhost:8080/actuator/health
- 提供应用程序的健康状态信息。 - JVM 指标:
http://localhost:8080/actuator/metrics
- 提供 JVM 和系统的各种指标,如 CPU 使用、内存使用等。 - 环境信息:
http://localhost:8080/actuator/env
- 提供应用程序的环境属性。 - HTTP 路径映射:
http://localhost:8080/actuator/mappings
- 显示所有的 HTTP 请求映射。
4. 自定义监控信息
你可以通过创建自定义的 @Endpoint
来扩展 Actuator 的功能,例如将之前实现的 SystemMetrics
集成到 Actuator 中。
自定义 Endpoint
我们可以创建一个自定义的 Actuator 端点,通过它来暴露我们之前实现的 SystemMetrics
信息。
package com.example.monitor.actuator;
import com.example.monitor.model.SystemMetrics;
import com.example.monitor.service.SystemMetricsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;
@Component
@Endpoint(id = "systemMetrics")
public class SystemMetricsEndpoint {
private final SystemMetricsService systemMetricsService;
@Autowired
public SystemMetricsEndpoint(SystemMetricsService systemMetricsService) {
this.systemMetricsService = systemMetricsService;
}
@ReadOperation
public SystemMetrics systemMetrics() {
return systemMetricsService.getSystemMetrics();
}
}
访问自定义的 SystemMetrics
Endpoint
- 现在,你可以通过
http://localhost:8080/actuator/systemMetrics
访问自定义的系统监控信息。这将返回我们之前收集的 CPU、内存、磁盘等监控数据。
5. 安全配置(可选)
如果你希望限制 Actuator 端点的访问,可以使用 Spring Security 进行保护。你可以为敏感的端点配置用户名和密码,或根据需求进行权限控制。
总结
通过集成 Spring Boot Actuator,你不仅获得了开箱即用的应用监控能力,还可以自定义和扩展 Actuator 的功能,将特定的监控数据集成到应用程序的监控中。你现在可以访问各种内置的和自定义的端点,实时监控应用的健康状况和性能指标。
实现监控的逻辑代码为:
OperatingSystemMXBean operatingSystemMXBean =
ManagementFactory.getOperatingSystemMXBean();//获取当前操作系统的接口,检测CPU
log.info("CPU的消耗为:{}",operatingSystemMXBean.getSystemLoadAverage());
//监控JVM虚拟机
log.info("JVM的总内存为:{}GB",Runtime.getRuntime().totalMemory()/1024/1024);
log.info("JVM的空余内存为:{}GB",Runtime.getRuntime().freeMemory()/1024/1024);
log.info("JVM的最大内存为:{}GB",Runtime.getRuntime().maxMemory()/1024/1024);
//监控本地磁盘
File file = new File("D:\\"); // 磁盘路径,D盘,单位为B
log.info("磁盘总容量为:{}GB",file.getTotalSpace()/1024/1024/1024);
log.info("磁盘剩余容量为:{}GB",file.getFreeSpace()/1024/1024/1024);
log.info("磁盘最大容量为:{}GB",file.getUsableSpace()/1024/1024/1024);
//监控线程
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
log.info("当前线程数:{}",threadMXBean.getThreadCount());
}
还有就是前端的异步刷新,在前面已写!
日志编写之SLF4J
1. maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.6.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
2. slf4j配置结构
configuration:配置根目录
conversionRule:彩色日志,配置之后控制台输出的日志信息是彩色的,非常好看
appender:日志输出配置规则
file:日志文件输出路径
encoder:日志文件输出格式
pattern:日志文件输出模板格式
charset:日志文件输出编码方式
rollingPolicy:日志记录器的滚动策略;简单来说就是一天过后把前一天的日志文件名变成 "2021-xx-xx.log";每个日志文件最大尺寸多少,超过尺寸后多余部分生成一个新的日志文件等,一些动态的策略处理
fileNamePattern:滚动策略输出日志文件目录,及文件名模板;以尺寸策略来说,超过10m的文件,多余部分输出的文件名和路劲为appender的file值,已满10m的部分输出路径为此值
timeBasedFileNamingAndTriggeringPolicy:设置日志文件尺寸滚动策略
maxFilesSize:单个日志文件最大size
maxHistory:日志文件最大保存时间
filter:日志文件记录数据过滤器
level:只记录对应等级的记录
onMatch:常量:ACCEPT
onMismatch:常量:DENY
root:设置日志记录写入和控制器打印等级,低于这个等级的记录不写入日志文件,不在控制器打印
appender-ref:日志规则生效列表,值为appender对应的name属性,只有name存在appender-ref的appender配置才会生效;
logger:指定某个报下的日志输出规则,配置之后只要是这个包下产生的记录,都是遵循此规则,并且与root中配置的appender-ref重复的话,会叠加生效
appender-ref:使用的日志生成规则
springProfile:设置不同环境的配置,上诉标签除了configuration都可以放置在此标签内;会根据不同的环境,使用不同的规则
3. 案例详解
3.1 configuration
配置文件的根节点
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds" debug="false">
<conversionRule ....></conversionRule>
<root ....></root>
<appender ...></appender>
</configuration>
3.2 conversionRule
配置完彩色日志后,就可以在模板内使用彩色变量,使得输出的日志记录变成彩色的,稍后在pattern中举例使用彩色变量,现在先配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds" debug="false"> ......一些其他的配置
<!-- 彩色日志 --> <!-- conversionWord:指定在pattern中使用的别名 --> <!-- converterClass:指定使用彩色日志渲染类 -->
<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"/>
<!-- 彩色日志格式 -->
</configuration>
3.3 appender
日志输出规则
<!--输出到控制台-->
<!-- name 表示规则名称,提供与root -> appender-ref 的使用-->
<!-- class 表示使用的日志输出类 ConsoleAppender表示为控制台日志输出类,使用此类日志会输出的控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 配置日志输出过滤条件-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 只输出info等级及以上的日志-->
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<level>info</level>
</filter>
<!-- 配置日志输出格式-->
<encoder>
<!-- 日志输出格式模板,请注意一下格式是为了更好的描述,在打印的时候出现换行情况,实际使用要将其写成一行,换行符由%n代替-->
<Pattern>
${
CONSOLE_LOG_PATTERN:- //常量
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} //%clr表示使用conversionRule中conversionWord为clr的converterClass输出()中的变量文本;%d表示日期;{faint}表示颜色;颜色值有[faint:灰白,red,green,yellow,blue,magenta,cyan]
%clr(${LOG_LEVEL_PATTERN:-%5p})
%clr(${PID:- }){magenta}
%clr(---){faint}
%clr([%15.15t]){faint}
%clr(%-40.40logger{39}){cyan}
%clr(:){cyan}
%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
}
</Pattern>
<!-- 日志输出字符集,没错就是为了解决中文乱码-->
<charset>UTF-8</charset>
</encoder>
</appender>
3.4 Pattern中特殊符号含义
-X号: X信息输出时左对齐;
%p: //输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%d: //输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%r: //输出自应用启动到输出该log信息耗费的毫秒数
%c: //输出日志信息所属的类目,通常就是所在类的全名
%t: //输出产生该日志事件的线程名
%l: //输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main (TestLog4.java:10)
%x: //输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%: //输出一个”%”字符
%F: //输出日志消息产生时所在的文件名称
%L: //输出代码中的行号
%m://输出代码中指定的消息,产生的日志具体信息
%n: //输出一个回车换行符,Windows平台为”\r\n”,Unix平台为”\n”输出日志信息换行
3.5 appender
根据等级设置多个日志输出规则,把不同等级的日志分别存储,配置多个appender
<!-- 设置一个变量,以免Pattern重复复制模板表达式-->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 DEBUG 日志 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_debug.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>1KB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
3.6 root
appender必须要放置在root中,才能生效
<!-- 表明日志输出等级,只有info及info以上的日志才会在控制台和日志文件中输出-->
<root level="info">
<appender-ref ref="CONSOLE"/> <!--ref 表明使用一个name=CONSOLE的appender标签,的规则-->
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
3.7 logger
更精确的指定annender生效范围
<!-- name:指定日志输出规则生效范围,可以是包名和类型;-->
<!-- level表示只输出info等级及以上的日志记录-->
<!-- 下例会将com.example.mybitesstudy02.service包下的日志只输出info等级及以上的日志记录,并且使用CONSOLE的apender规则-->
<logger name="com.example.mybitesstudy02.service" level="info">
<appender-ref ref="CONSOLE"/>
</logger>
3.8 springProfile
指定不同环境下的日志配置,注意springProfile判断当前是处于什么环境,取决于spring boot配置文件(application.properties)的spring.profiles.active值,默认是default
<!-- 这里表示不管在所有环境都使用的配置-->
<root level="info">
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!--这里表示在dev环境使用的配置-->
<springProfile name="dev">
<root level="info">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<!--这里表示在pro环境使用的配置-->
<springProfile name="pro">
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</springProfile>
4. 超详细配置案例
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
<!-- 日志存放路径 -->
<springProperty scope="context" name="log.path" source="logging.file.path"/>
<springProperty scope="context" name="log.name" source="logging.file.name"/>
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<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="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--1. 输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--2. 输出到文档-->
<!-- 2.1 level为 DEBUG 日志,时间滚动输出 -->
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/${log.name}_debug.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志归档 -->
<fileNamePattern>${log.path}/${log.name}-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录debug级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.2 level为 INFO 日志,时间滚动输出 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/${log.name}_info.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/${log.name}-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.3 level为 WARN 日志,时间滚动输出 -->
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/${log.name}_warn.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/${log.name}-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 2.4 level为 ERROR 日志,时间滚动输出 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文档的路径及文档名 -->
<file>${log.path}/${log.name}_error.log</file>
<!--日志文档输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/${log.name}-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文档保留天数-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<!-- 此日志文档只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 4. 最终的策略 -->
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
<!-- 4.2 生产环境:输出到文档
<springProfile name="pro">
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG_FILE" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="WARN_FILE" />
</root>
</springProfile> -->
</configuration>
注意:
在resources目录下创建logback-spring.xml 并编写配置文件
在application.yaml里配置 xml的路径
在要输出日志的类上打上@Slf4j注解
用log.info/debug.....来输出自己想要的日志
支持用{}拼接字符串!!!
举例
OperatingSystemMXBean operatingSystemMXBean =
ManagementFactory.getOperatingSystemMXBean();//获取当前操作系统的接口,检测CPU
log.info("CPU的消耗为:{}",operatingSystemMXBean.getSystemLoadAverage());
//监控JVM虚拟机
log.info("JVM的总内存为:{}GB",Runtime.getRuntime().totalMemory()/1024/1024);
log.info("JVM的空余内存为:{}GB",Runtime.getRuntime().freeMemory()/1024/1024);
log.info("JVM的最大内存为:{}GB",Runtime.getRuntime().maxMemory()/1024/1024);
//监控本地磁盘
File file = new File("D:\\"); // 磁盘路径,D盘,单位为B
log.info("磁盘总容量为:{}GB",file.getTotalSpace()/1024/1024/1024);
log.info("磁盘剩余容量为:{}GB",file.getFreeSpace()/1024/1024/1024);
log.info("磁盘最大容量为:{}GB",file.getUsableSpace()/1024/1024/1024);
//监控线程
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
log.info("当前线程数:{}",threadMXBean.getThreadCount());
}
Leave a reply