简单的springboot log4j2日志配置

news2024/9/20 22:39:57

简单的springboot log4j2日志配置

在这里插入图片描述

1.简介

Log4j2 是 Apache Software Foundation 开发的一个日志记录工具,它是 Log4j 的后续版本,并且在多个方面进行了改进。以下是 Log4j2 的一些关键特性:

  • 性能提升:Log4j2 在设计上做了很多优化来提高日志记录的效率。例如,它使用了更高效的查找表来减少日志记录时的开销。

  • 可靠性增强:Log4j2 支持异步日志记录,这有助于提高应用程序的整体性能。异步处理可以避免日志记录阻塞应用程序线程。

  • 灵活性增加:Log4j2 提供了一个可插拔的架构,允许用户根据需要选择不同的布局、appender 和其他组件。这种模块化的设计使得配置更加灵活。

  • 简化配置:Log4j2 使用 XML、JSON 或 YAML 文件进行配置,相较于 Log4j 的 XML 配置,提供了更多的灵活性和易用性。
    丰富的功能集:Log4j2 包含了许多高级功能,如支持多种日志级别、过滤器、布局以及多种输出目的地(比如文件、控制台、数据库等)。

  • 安全性改进:鉴于之前在 Log4j 中发现的安全问题,Log4j2 在设计时考虑到了安全性,尤其是在处理外部输入数据时更为谨慎。

Log4j2 是一个广泛使用的日志框架,在 Java 应用程序中非常受欢迎。然而,值得注意的是,Log4j2 也曾经历过一些严重的安全漏洞,比如著名的 Log4Shell 漏洞(CVE-2021-44228),这是一个远程代码执行漏洞,影响了大量的系统和服务。因此,在使用 Log4j2 时,确保使用最新版本并及时应用安全更新是非常重要的。

在 Java 日志领域还有其他的日志框架,Log4j2、Log4j、Logback 和 SLF4J 这几个框架扮演着不同的角色,相互之间还有些许关联,此处整理一下它们之间的关系如下:

  • Log4j
    Log4j 是 Apache 软件基金会开发的第一个日志框架,它为 Java 应用程序提供了强大的日志功能。由于其稳定性和广泛的使用,Log4j 成为了早期 Java 应用的标准日志解决方案之一。
  • Log4j2
    Log4j2 是 Log4j 的继任者,它在 Log4j 的基础上进行了大量的改进,包括性能优化、新的配置方式(XML、JSON 或 YAML)、异步日志处理等功能。虽然两者名称相似,但是 Log4j2 并不向后兼容 Log4j。
  • Logback
    Logback 是 Log4j 的另一个替代品,由 Log4j 的原始作者 Ceki Gülcü 创建。它旨在作为 Log4j 的一个改进版本,并且与 Log4j 具有较高的兼容性。Logback 同样支持异步日志记录,并且具有更好的性能。
  • SLF4J (Simple Logging Facade for Java)
    SLF4J 不是一个实际的日志实现,而是一个抽象层或门面(Facade)。它的目的是提供一个简单的 API,以便于开发者编写日志代码,同时允许在运行时动态地绑定到不同的日志框架(如 Logback、Log4j、java.util.logging 等)。这样可以在不影响应用代码的情况下更换底层的日志实现。

这些日志框架之间的关系可以总结为:

  • SLF4J 是一个日志门面,它提供了一套统一的日志 API。
  • Logback 默认实现了 SLF4J 接口,可以直接与 SLF4J 一起工作。
  • Log4j 和 Log4j2 可以通过适配器(如 slf4j-log4j12 或 log4j-slf4j-impl)与 SLF4J 一起使用。
  • Log4j 和 Log4j2 是独立的日志框架,直接提供日志功能,不需要通过 SLF4J。

在实际应用中,通常会选择一个具体的日志框架(如 Logback 或 Log4j2),并通过 SLF4J 来编写日志代码,以提高代码的可移植性和灵活性。我们项目使用的是log4j2日志框架进行配置,下面主要对log4j2日志框架配置进行梳理方便日后复习使用。

2. 配置简介

2.1 日志级别

log4j2有8个级别 从低到高为 ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF,我们作为web服务器,主要配置level为 INFO 级别

等级描述
ALL最低等级,用于打印所有日志记录信息
TRACE追踪程序运行到哪里
DEBUG消息颗粒度强调调试层面日志信息,展示详细执行信息
INFO消息颗粒度突出强调应用正常的执行逻辑日志信息
WARN输出警告
ERROR输出错误日志信息
FATAL输出每个严重错误时间,会导致应用程序退出日志
OFF最高等级,关闭所有日志记录

2.2 Appenders种类

常用的文件追加器 appenders 信息如下

Appenders名称具体作用
FlumeAppender将几个不同源的日志汇集、集中到一处
RewriteAppender对日志事件进行掩码或注入信息
RollingFileAppender对日志文件进行封存
RoutingAppender在输出地之间进行筛选路由
SMTPAppender将LogEvent发送到指定邮件列表
SocketAppender将LogEvent以普通格式发送到远程主机
SyslogAppender将LogEvent以RFC 5424格式发送到远程主机
AsynchAppender将一个LogEvent异步地写入多个不同输出地
ConsoleAppender将LogEvent输出到控制台
FailoverAppender维护一个队列,系统将尝试向队列中的Appender依次输出LogEvent,直到有一个成功为止

2.3 PatternLayout格式详解

PatternLayout 是最重要也是最常用的控制输出内容的节点,包括类名、时间、行号、日志级别、序号等都可以控制,同时还可以指定日志格式,可以使用正则表达式处理输出结果。

PatternLayout中包含的特殊字符包括\t,\n,\r,\f,用\输出单斜线,用%%输出%,下面是PatternLayout的参数

参数名称类型描述
charsetString输出的字符集。如果没有指定,则使用系统默认的字符集输出
patternString详见后面的pattern的表格
replaceRegexReplacement替换部分输出中的String。这将会调用一个与RegexReplacement转换器相同的函数,不同的是这是针对整个消息的
alwaysWriteExceptionsboolean默认为true。总是输出异常,即使没有定义异常对应的pattern,也会被附在所有pattern的最后。设为false则不会输出异常
headerString可选项。包含在每个日志文件的顶部
footerString可选项。包含在每个日志文件的尾部
noConsoleNoAnsiboolean默认为false。如果为true,且System.console()是null,则不会输出ANSI转义码

RegexReplacement参数

参数名称类型具体作用描述
regexString将几个不同源的日志汇集、集中到一处
replacementString任何匹配正则规则,被正则替换的后值

下面是pattern属性具体描述(这个表格仅包括了我能看懂的部分,还有很多看不懂并且试验也不成功的部分我都没写。另外用于控制输出结果颜色的highlight和style我也没有写,实在是感觉平时意义不大):

参数名参数意义详细描述
%c{参数}或%logger{参数}输出logger的名称,即语句private static final Logger logger = LogManager.getLogger(App.class.getName())中App.class.getName()的值。也可以使用其他字符串如果不带参数,则输出完整的logger名称;如果参数是整数n(只支持正整数),则先将logger名称依照小数点(.)分割成n段,然后取右侧的n段;如果参数不是整数,则除了最右侧的一段,其他整段字符都用这个字符代替,保留小数点;不管怎么写,最右侧的一段都保持不变。默认不带参数,并输出logger的完整名称。注意:上面的说明写得很烂,但是官方文档写得就这么烂,而且还不完整,看不懂是必然的,还请看官自己多试验,才能有所领会。如果看官自己懒得试验又看不懂,只能建议不要加参数,直接%c输出完整值。
%C{参数}或%class{参数}输出类名。注意,这个是大写C,上面是小写c参数规则与%c完全一样,请参见上面的说明。
%d{参数}{时区te{参数}{时区}输出时间。第一个大括号数可以是保留关键字,也可以是text.SimpleDateFormat字符拼接而成。保留关键字有:DEFAULT,ABSOLUTE, COMPACT, DATE, ISO8601, ISO8601_BASIC。第二个大括号中的参数是java.util.TimeZone.getTimeZone的值,可以设定时区
输出特殊字符&, <, >, ”, ’全都要使用实体名称或实体编号替代,即官方文档说pattern删除了\r和\n,但是经我测试可以使用,明显是官方文档的错误
%F%file输出文件名
highlight{pattern}{style}高亮显示结果
%l输出完整的错误位置,如com.future.ourfuture.test.test.App.tt(App.java:13)注意1:这个是小写的L。注意2:使用该参数会影影响日志输出的性能
%L输出错误行号,如“13”注意:使用该参数会影响日志输出的性能
%m或%msg或%message输出错误信息,即logger.error(String msg)中的msg
%M或%method输出方法名,如“main”,“getMsg”等字符串
%n换行符根据系统自行决定,如Windows是”\r\n”,Linux是”\n”
%level{参数1}{参数2}{参数3}参数1用来替换日志信息的级别,格式为:{level=label, level=label, …},即使用label代替的字符串替换level。其中level为日志的级别,如WARN/DEBUG/ERROR/TRACE/INFO参数2表示只保留前n个字符。格式为length=n,n为整型。但参数1中指定了label的字符串不受此参数限制参数3表示结果是大写还是小写。参数1指定了label的字符串不受此参数限制
%r或%relative输出自JVM启动以来到log事件开始时的毫秒数
replace{pattern}{regex}{substitution}将pattern的输出结果,按照正则表达式regex匹配后,使用substitution字符串替换例如:"%replace{%logger }{.}{/}就是将所有%logger中的小数点(.)全部替换为斜杠,如果%logger是com.future.ourfuture.test.test.App则输出为com/future/ourfuture/test/test/App。pattern中可以写多个表达式,如%replace{%logger%msg%C}{.}{/}%n
%sn或%sequenceNumber自增序号,每执行一次log事件,序号+1,是一个static变量。
%t或%thread创建logging事件的线程名
%u{RANDOMTIME}或%uuid{RANDOMTIME}

patten表达式

pattern表达式logger名称响应结果
%c{1}org.apache.com.te.FooFoo
%c{2}org.apache.com.te.Foote.Foo
%c{1.}org.apache.com.te.Fooo.a.c.t.Foo
%c{1.1.!}org.apache.com.te.Fooo.a.!.!.Foo
%c{.}org.apache.com.te.Foo….Foo

pattern的对齐修饰
对齐修饰,可以指定信息的输出格式,如是否左对齐,是否留空格等。

编写格式为在任何pattern和%之间加入一个小数,可以是正数,也可以是负数。如%10.20c表示对logger的信息进行处理。%-10.20m表示对message进行处理。

整数表示右对齐,负数表示左对齐;整数位表示输出信息的最小10个字符,如果输出信息不够10个字符,将用空格补齐;小数位表示输出信息的最大字符数,如果超过20个字符,则只保留最后20个字符的信息(注意:保留的是后20个字符,而不是前20个字符)。下面是一些示例。

格式是否左对齐最小宽度最大宽度说明
%20右对齐20右对齐,不足20个字符则在信息前面用空格补足,超过20个字符则保留原信息
%-20左对齐20左对齐,不足20个字符则在信息后面用空格补足,超过20个字符则保留原信息
%.30不对齐30如果信息超过30个字符,则只保留最后30个字符
%20.30右对齐2030右对齐,不足20个字符则在信息前面用空格补足,超过30个字符则只保留最后30个字符
%-20.30左对齐2030左对齐,不足20个字符则在信息后面用空格补足,超过30个字符则只保留最后30个字符

我们项目中的log4j2.xml日志格式具体配置日志格式附带格式注释信息如下:

<!-- elk日志格式 -->
<property name="patternLayout">[%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}] [%level{length=5}] [%traceId] [%logger] [${sys:hostName}] [${sys:ip}] [${sys:applicationName}] [%F,%L,%C,%M] [%m] ## '%ex'%n</property>
  • [%d{yyyy-MM-dd’T’HH:mm:ss.SSSZZ}] 日期 美国时间
  • [%level{length=5}] 日志级别
  • [%traceId] 链路追踪id,skyWalking使用
  • [%logger] 记录日志的类或包的全限定名。这有助于在日志输出中明确标识日志来源
  • [${sys:hostName}] 自定义主机名称,System.setProperty(“hostName”, NetUtil.getLocalHostName());
  • [${sys:ip}] 自定义系统ip信息 ,System.setProperty(“ip”, NetUtil.getLocalIp());
  • [${sys:applicationName}] 应用名称
  • [%F,%L,%C,%M] / [当前执行类, 行号, 全类名, 方法名称]
  • [%m] 日志输出内容
  • ##自己特殊约定
  • '%ex'%n 两个引号将异常包裹,打出异常时候方便解析 如何抛异常 和 换行

log4j2 patternLayOut参考此博文

3.项目中使用

我们整体的使用需要先引入pom文件,将服务ip信息存入到系统变量中,供log4j2配置文件使用, 再进行log4j2配置文件配置,最后在代码中可以使用slf4j日志门脸进行日志调用,添加日志后通过elk 我们可以快速定为到线上的问题,哪个服务在哪个机器上,具体发生了哪些问题,提高生产问题排错效率。

3.1 pom配置

在spring boot项目中,默认使用的日志框架是Logback,所以我们需要排除掉其自身引用的日志框架再引入log4j2日志jar包。引入pom内容如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.4</version>
</dependency>

3.2 ip信息初始化到系统变量中

通过代码获取ip信息,具体工具类NetUtil实现如下

package cn.git.elk.util;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketChannel;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @program: bank-credit-sy
 * @description: $NetUtil 获取ip地址hostname工具类
 * @author: lixuchun
 * @create: 2021-02-04 14:52
 */
public class NetUtil {   
    // 正则表达式模式,用于匹配 IP 地址
    private static Pattern pattern;
    // IP 地址分隔符限制长度
    private static Integer BLOCKS_LIMIT_LENGTH_2 = 2;
    // 默认主机名
    private static String HOST = "0.0.0.0";

    /**
     * 格式化输入的地址字符串,确保其包含主机名和端口号,并默认设置端口为 80。
     * @param address 地址字符串
     * @return 格式化后的地址字符串
     */
    public static String normalizeAddress(String address){
        // 将地址字符串按冒号分割成数组
        String[] blocks = address.split(":");
        // 检查地址是否有效
        if(blocks.length > BLOCKS_LIMIT_LENGTH_2){
            throw new IllegalArgumentException(address + " is invalid");
        }
        // 获取主机名
        String host = blocks[0];
        // 默认端口号为 80
        int port = 80;
        // 如果地址包含端口号,则提取端口号
        if(blocks.length > 1){
            port = Integer.valueOf(blocks[1]);
        } else {
            // 使用默认端口 80
            address += ":" + port;
        } 
        // 格式化并返回地址
        String serverAddr = String.format("%s:%d", host, port);
        return serverAddr;
    }
    
    /**
     * 如果输入地址中的主机名为“0.0.0.0”,则用本地 IP 地址替换后返回格式化的地址。
     * @param address 地址字符串
     * @return 格式化后的地址字符串
     */
    public static String getLocalAddress(String address){
        // 将地址字符串按冒号分割成数组
        String[] blocks = address.split(":");
        // 检查地址是否有效
        if(blocks.length != BLOCKS_LIMIT_LENGTH_2){
            throw new IllegalArgumentException(address + " is invalid address");
        } 
        // 获取主机名
        String host = blocks[0];
        // 获取端口号
        int port = Integer.valueOf(blocks[1]);
        
        // 如果主机名为“0.0.0.0”,则替换为本地 IP 地址
        if(HOST.equals(host)){
            return String.format("%s:%d", NetUtil.getLocalIp(), port);
        }
        // 否则直接返回原地址
        return address;
    }
    
    /**
     * 检查给定的 IP 是否匹配优先级列表中的前缀,并返回匹配的索引。
     * @param ip IP 地址
     * @param prefix 优先级列表
     * @return 匹配的索引
     */
    private static int matchedIndex(String ip, String[] prefix){
        // 遍历优先级列表
        for(int i=0; i<prefix.length; i++){
            String p = prefix[i];
            // 如果前缀为“*”,则检查 IP 是否为内网地址
            if("*".equals(p)){
                if(ip.startsWith("127.") ||
                   ip.startsWith("10.") ||	
                   ip.startsWith("172.") ||
                   ip.startsWith("192.")){
                    continue;
                }
                return i;
            } else {
                // 检查 IP 是否以指定前缀开头
                if(ip.startsWith(p)){
                    return i;
                }
            } 
        }
        
        // 如果没有匹配,则返回 -1
        return -1;
    }
    
    /**
     * 获取本地 IP 地址,根据优先级选择最优 IP 地址;如果没有指定优先级,则使用默认优先级顺序。
     * @param ipPreference IP 优先级字符串
     * @return 本地 IP 地址
     */
    public static String getLocalIp(String ipPreference) {
        // 如果未指定优先级,则使用默认优先级
        if(ipPreference == null){
            ipPreference = "*>10>172>192>127";
        }
        // 分割优先级字符串
        String[] prefix = ipPreference.split("[> ]+");
        try {
            // 编译正则表达式模式
            pattern = Pattern.compile(PATTEN_COMPARE_RULES);
            // 获取所有网络接口
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            // 初始化最佳匹配 IP 和索引
            String matchedIp = null;
            int matchedIdx = -1;
            // 遍历所有网络接口
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                // 获取每个网络接口的所有 IP 地址
                Enumeration<InetAddress> en = ni.getInetAddresses(); 
                // 遍历所有 IP 地址
                while (en.hasMoreElements()) {
                    InetAddress addr = en.nextElement();
                    String ip = addr.getHostAddress();  
                    // 匹配 IP 地址
                    Matcher matcher = pattern.matcher(ip);
                    if (matcher.matches()) {  
                        // 获取匹配的索引
                        int idx = matchedIndex(ip, prefix);
                        if(idx == -1) {
                            continue;
                        }
                        // 更新最佳匹配 IP 和索引
                        if(matchedIdx == -1){
                            matchedIdx = idx;
                            matchedIp = ip;
                        } else {
                            if(matchedIdx > idx){
                                matchedIdx = idx;
                                matchedIp = ip;
                            }
                        }
                    } 
                } 
            } 
            // 如果找到最佳匹配 IP,则返回;否则返回“127.0.0.1”
            if(matchedIp != null) {
                return matchedIp;
            }
            return "127.0.0.1";
        } catch (Exception e) { 
            return "127.0.0.1";
        }
    }
    
    /**
     * 获取本地 IP 地址,默认使用优先级顺序。
     * @return 本地 IP 地址
     */
    public static String getLocalIp() {
        return getLocalIp("*>10>172>192>127");
    }
    
    /**
     * 返回给定 SocketChannel 对象的远程地址信息。
     * @param channel SocketChannel 对象
     * @return 远程地址信息
     */
    public static String remoteAddress(SocketChannel channel){
        // 获取远程地址
        SocketAddress addr = channel.socket().getRemoteSocketAddress();
        // 格式化并返回地址信息
        String res = String.format("%s", addr);
        return res;
    }
    
    /**
     * 返回给定 SocketChannel 对象的本地地址信息,去掉可能存在的冒号前缀。
     * @param channel SocketChannel 对象
     * @return 本地地址信息
     */
    public static String localAddress(SocketChannel channel){
        // 获取本地地址
        SocketAddress addr = channel.socket().getLocalSocketAddress();
        // 格式化并返回地址信息
        String res = String.format("%s", addr);
        // 如果地址不为空,则去掉第一个字符(通常是“/”)
        return addr == null ? res : res.substring(1);
    }
    
    /**
     * 获取当前 Java 进程 ID。
     * @return 进程 ID
     */
    public static String getPid(){
        // 获取运行时管理对象
        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        // 获取名称
        String name = runtime.getName();
        // 查找“@”符号的位置
        int index = name.indexOf("@");
        if (index != -1) {
            // 提取进程 ID
            return name.substring(0, index);
        }
        // 如果未找到,则返回 null
        return null;
    }
    
    /**
     * 获取本地主机名。
     * @return 本地主机名
     */
    public static String getLocalHostName() {
        try {
            // 获取本地 IP 地址并提取主机名
            return (InetAddress.getLocalHost()).getHostName();
        } catch (UnknownHostException uhe) {
            // 处理异常情况
            String host = uhe.getMessage();
            if (host != null) {
                int colon = host.indexOf(':');
                if (colon > 0) {
                    // 提取主机名部分
                    return host.substring(0, colon);
                }
            }
            // 如果无法获取主机名,则返回“UnknownHost”
            return "UnknownHost";
        }
    }
}

初始化ip信息到系统变量中代码部分如下

package cn.git.init;

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/** 
 * @description: 初始化设置ip hostname等信息通用类
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-01-03
 */
@Component
public class InitLogIpHost implements EnvironmentAware {

    private static Environment environment;


    @PostConstruct
    public void initIpHostEnvInfo() {
        // 设置 applicationName
        System.setProperty("applicationName", environment.getProperty("spring.application.name"));
        // 设置 ip
        System.setProperty("ip", NetUtil.getLocalIp());
        // 设置 hostname
        System.setProperty("hostName", NetUtil.getLocalHostName());
    }

    /**
     * Set the {@code Environment} that this component runs in.
     *
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {
        InitLogIpHost.environment = environment;
    }
}

3.3 log4j2.xml日志文件配置

<?xml version="1.0" encoding="UTF-8"?>
<Configuration schema="Log4J-V2.0.xsd" monitorInterval="600">
    <!-- 配置全局属性 -->
    <Properties>
        <!-- 日志文件保存的基本路径 -->
        <Property name="LOG_HOME">logs</Property>
        <!-- 日志文件的基础名称 -->
        <property name="FILE_NAME">docker-server</property>
        <!-- 日志输出格式 -->
        <property name="patternLayout">[%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}] [%level{length=5}] [%traceId] [%logger] [${sys:hostName}] [${sys:ip}] [${sys:applicationName}] [%F,%L,%C,%M] [%m] ## '%ex'%n</property>
    </Properties>

    <!-- 定义不同的日志输出目的地 -->
    <Appenders>
        <!-- 控制台输出 -->
        <Console name="CONSOLE" target="SYSTEM_OUT">
            <!-- 使用定义的日志格式 -->
            <PatternLayout pattern="${patternLayout}"/>
            <!-- 只允许 info 级别及以上的日志输出到控制台 -->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
        </Console>

        <!-- 应用程序日志滚动文件 -->
        <RollingRandomAccessFile name="appAppender" fileName="${LOG_HOME}/app-${FILE_NAME}.log" filePattern="${LOG_HOME}/app-${FILE_NAME}-%d{yyyy-MM-dd}-%i.log" >
            <!-- 使用定义的日志格式 -->
            <PatternLayout pattern="${patternLayout}" />
            <!-- 滚动策略 -->
            <Policies>
                <!--
					根据当前filePattern配置"%d{yyyy-MM-dd}",每interval天滚动一次
                    "%d{yyyy-MM-dd HH-mm}" 则为每interval分钟滚动一次
				-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!-- 文件大小超过 500MB 时滚动 -->
                <SizeBasedTriggeringPolicy size="500MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>

        <!-- Druid SQL 日志滚动文件 -->
        <RollingRandomAccessFile name="druidSqlRollingFile" fileName="${LOG_HOME}/druid/app-${FILE_NAME}-druid.log" filePattern="${LOG_HOME}/app-${FILE_NAME}-druid-%d{yyyy-MM-dd}-%i.log" >
            <!-- 使用定义的日志格式 -->
            <PatternLayout pattern="${patternLayout}" />
            <!-- 滚动策略 -->
            <Policies>
                <!-- 每天滚动一次 -->
                <TimeBasedTriggeringPolicy interval="1"/>
                <!-- 文件大小超过 500MB 时滚动 -->
                <SizeBasedTriggeringPolicy size="500MB"/>
            </Policies>
            <!-- 最多保留 20 个旧日志文件 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingRandomAccessFile>

        <!-- skywalking GRPC 日志客户端 Appender -->
        <GRPCLogClientAppender name="grpc-log">
            <!-- 使用简单的日志格式 -->
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </GRPCLogClientAppender>
    </Appenders>

    <!-- 定义不同日志记录器 -->
    <Loggers>
        <!-- 关闭 org.apache.kafka 包下的所有日志输出 -->
        <logger name="org.apache.kafka" level="off"/>

        <!-- 设置 druid 包的日志级别为 error,并关闭继承父 Logger 的行为 -->
        <logger name="druid" level="error" additivity="false">
            <appender-ref ref="druidSqlRollingFile"/>
        </logger>

        <!-- 设置 cn.git.* 包的日志级别为 info,并关闭继承父 Logger 的行为 -->
        <logger name="cn.git.*" level="info" additivity="false">
            <AppenderRef ref="grpc-log"/>
        </logger>

        <!-- 创建一个异步 Logger,用于处理 cn.git.* 包的日志,并指定日志输出到 appAppender -->
        <AsyncLogger name="cn.git.*" level="info" includeLocation="true">
            <AppenderRef ref="appAppender"/>
        </AsyncLogger>

        <!-- 设置根 Logger 的日志级别为 info,并指定日志输出到控制台、appAppender 和 grpc-log -->
        <root level="info">
            <AppenderRef ref="CONSOLE"/>
            <Appender-Ref ref="appAppender"/>
            <AppenderRef ref="grpc-log"/>
        </root>
    </Loggers>
</Configuration>

4. 测试

我们启动服务,然后在定时任务中打印一个简单的日志信息,并且运行时候可能会报错,task代码如下

package cn.git.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/** 
 * @description: 简单定时任务
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-07-10
 */
@Slf4j
@Component
@EnableScheduling
public class TimerTask {

    /**
     * 每5秒执行一次
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void timer() {
        log.info("定时任务执行 : " + System.currentTimeMillis());
        if (System.currentTimeMillis() % 2 == 0) {
            throw new RuntimeException("异常啦!");
        }
    }
}

我们观察运行结果日志信息如下

"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:61667,suspend=y,server=n -Dvisualvm.id=6066284867800 -javaagent:C:\Users\Administrator.DESKTOP-40G9I84\AppData\Local\JetBrains\IdeaIC2020.3\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;D:\idea_workspace_activiti_change\docker-hello\target\classes;D:\apache-maven-3.6.3\repos\org\projectlombok\lombok\1.18.6\lombok-1.18.6.jar;D:\apache-maven-3.6.3\repos\cn\hutool\hutool-all\5.5.7\hutool-all-5.5.7.jar;D:\apache-maven-3.6.3\repos\com\alibaba\fastjson\1.2.83\fastjson-1.2.83.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot-starter-web\2.3.8.RELEASE\spring-boot-starter-web-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot-starter\2.3.8.RELEASE\spring-boot-starter-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\apache-maven-3.6.3\repos\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot-starter-json\2.3.8.RELEASE\spring-boot-starter-json-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\com\fasterxml\jackson\core\jackson-databind\2.11.4\jackson-databind-2.11.4.jar;D:\apache-maven-3.6.3\repos\com\fasterxml\jackson\core\jackson-annotations\2.11.4\jackson-annotations-2.11.4.jar;D:\apache-maven-3.6.3\repos\com\fasterxml\jackson\core\jackson-core\2.11.4\jackson-core-2.11.4.jar;D:\apache-maven-3.6.3\repos\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.4\jackson-datatype-jdk8-2.11.4.jar;D:\apache-maven-3.6.3\repos\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.4\jackson-datatype-jsr310-2.11.4.jar;D:\apache-maven-3.6.3\repos\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.4\jackson-module-parameter-names-2.11.4.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot-starter-tomcat\2.3.8.RELEASE\spring-boot-starter-tomcat-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\apache\tomcat\embed\tomcat-embed-core\9.0.41\tomcat-embed-core-9.0.41.jar;D:\apache-maven-3.6.3\repos\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\apache-maven-3.6.3\repos\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.41\tomcat-embed-websocket-9.0.41.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-web\5.2.12.RELEASE\spring-web-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-beans\5.2.12.RELEASE\spring-beans-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-webmvc\5.2.12.RELEASE\spring-webmvc-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-aop\5.2.12.RELEASE\spring-aop-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-context\5.2.12.RELEASE\spring-context-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-expression\5.2.12.RELEASE\spring-expression-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot-starter-log4j2\2.3.8.RELEASE\spring-boot-starter-log4j2-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\apache\logging\log4j\log4j-slf4j-impl\2.13.3\log4j-slf4j-impl-2.13.3.jar;D:\apache-maven-3.6.3\repos\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\apache-maven-3.6.3\repos\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\apache-maven-3.6.3\repos\org\apache\logging\log4j\log4j-core\2.13.3\log4j-core-2.13.3.jar;D:\apache-maven-3.6.3\repos\org\apache\logging\log4j\log4j-jul\2.13.3\log4j-jul-2.13.3.jar;D:\apache-maven-3.6.3\repos\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\apache-maven-3.6.3\repos\com\lmax\disruptor\3.3.4\disruptor-3.3.4.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-core\5.2.12.RELEASE\spring-core-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\spring-jcl\5.2.12.RELEASE\spring-jcl-5.2.12.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot-autoconfigure\2.3.8.RELEASE\spring-boot-autoconfigure-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\org\springframework\boot\spring-boot\2.3.8.RELEASE\spring-boot-2.3.8.RELEASE.jar;D:\apache-maven-3.6.3\repos\com\huaban\jieba-analysis\1.0.2\jieba-analysis-1.0.2.jar;D:\apache-maven-3.6.3\repos\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar;D:\apache-maven-3.6.3\repos\com\github\whvcse\easy-captcha\1.6.2\easy-captcha-1.6.2.jar;D:\apache-maven-3.6.3\repos\com\jcraft\jsch\0.1.55\jsch-0.1.55.jar;D:\apache-maven-3.6.3\repos\commons-net\commons-net\3.7\commons-net-3.7.jar;D:\IntelliJ IDEA Community Edition 2020.3.1\lib\idea_rt.jar" cn.git.helloApplication
Connected to the target VM, address: '127.0.0.1:61667', transport: 'socket'

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.8.RELEASE)

[2024-09-09T09:41:36.395+08:00] [INFO] [mainraceId] [cn.git.helloApplication] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [StartupInfoLogger.java,55,org.springframework.boot.StartupInfoLogger,logStarting] [Starting helloApplication on smallBigPower with PID 18696 (D:\idea_workspace_activiti_change\docker-hello\target\classes started by Administrator in D:\idea_workspace_activiti_change\docker-hello)] ## ''
[2024-09-09T09:41:36.401+08:00] [INFO] [mainraceId] [cn.git.helloApplication] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [SpringApplication.java,651,org.springframework.boot.SpringApplication,logStartupProfileInfo] [No active profile set, falling back to default profiles: default] ## ''
[2024-09-09T09:41:37.169+08:00] [INFO] [mainraceId] [org.springframework.boot.web.embedded.tomcat.TomcatWebServer] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [TomcatWebServer.java,108,org.springframework.boot.web.embedded.tomcat.TomcatWebServer,initialize] [Tomcat initialized with port(s): 8088 (http)] ## ''
[2024-09-09T09:41:37.179+08:00] [INFO] [mainraceId] [org.apache.coyote.http11.Http11NioProtocol] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [DirectJDKLog.java,173,org.apache.juli.logging.DirectJDKLog,log] [Initializing ProtocolHandler ["http-nio-8088"]] ## ''
[2024-09-09T09:41:37.180+08:00] [INFO] [mainraceId] [org.apache.catalina.core.StandardService] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [DirectJDKLog.java,173,org.apache.juli.logging.DirectJDKLog,log] [Starting service [Tomcat]] ## ''
[2024-09-09T09:41:37.180+08:00] [INFO] [mainraceId] [org.apache.catalina.core.StandardEngine] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [DirectJDKLog.java,173,org.apache.juli.logging.DirectJDKLog,log] [Starting Servlet engine: [Apache Tomcat/9.0.41]] ## ''
[2024-09-09T09:41:37.229+08:00] [INFO] [mainraceId] [org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [DirectJDKLog.java,173,org.apache.juli.logging.DirectJDKLog,log] [Initializing Spring embedded WebApplicationContext] ## ''
[2024-09-09T09:41:37.229+08:00] [INFO] [mainraceId] [org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [ServletWebServerApplicationContext.java,285,org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext,prepareWebApplicationContext] [Root WebApplicationContext: initialization completed in 796 ms] ## ''
[2024-09-09T09:41:37.263+08:00] [INFO] [mainraceId] [cn.git.init.AnalyzerInit] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [AnalyzerInit.java,44,cn.git.init.AnalyzerInit,analyzerInit] [开始加载分词词典信息,获取自定义词典路径[/D:/idea_workspace_activiti_change/docker-hello/target/classes/dict/custom.dict]] ## ''
main dict load finished, time elapsed 373 ms
user dict D:\idea_workspace_activiti_change\docker-hello\target\classes\dict\custom.dict load finished, tot words:7839, time elapsed:9ms
[2024-09-09T09:41:37.647+08:00] [INFO] [mainraceId] [cn.git.init.AnalyzerInit] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [AnalyzerInit.java,48,cn.git.init.AnalyzerInit,analyzerInit] [加载自定义词典信息完毕] ## ''
[2024-09-09T09:41:37.785+08:00] [INFO] [mainraceId] [cn.git.init.AnalyzerInit] [smallBigPower] [${sys:ip}] [${sys:applicationName}] [AnalyzerInit.java,61,cn.git.init.AnalyzerInit,analyzerInit] [数据库中敏感分词加载完毕!] ## ''
[2024-09-09T09:41:38.093+08:00] [INFO] [mainraceId] [org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor] [smallBigPower] [192.168.220.1] [docker-hello] [ExecutorConfigurationSupport.java,181,org.springframework.scheduling.concurrent.ExecutorConfigurationSupport,initialize] [Initializing ExecutorService 'applicationTaskExecutor'] ## ''
[2024-09-09T09:41:38.770+08:00] [INFO] [mainraceId] [org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler] [smallBigPower] [192.168.220.1] [docker-hello] [ExecutorConfigurationSupport.java,181,org.springframework.scheduling.concurrent.ExecutorConfigurationSupport,initialize] [Initializing ExecutorService 'taskScheduler'] ## ''
[2024-09-09T09:41:38.778+08:00] [INFO] [mainraceId] [org.apache.coyote.http11.Http11NioProtocol] [smallBigPower] [192.168.220.1] [docker-hello] [DirectJDKLog.java,173,org.apache.juli.logging.DirectJDKLog,log] [Starting ProtocolHandler ["http-nio-8088"]] ## ''
[2024-09-09T09:41:38.795+08:00] [INFO] [mainraceId] [org.springframework.boot.web.embedded.tomcat.TomcatWebServer] [smallBigPower] [192.168.220.1] [docker-hello] [TomcatWebServer.java,220,org.springframework.boot.web.embedded.tomcat.TomcatWebServer,start] [Tomcat started on port(s): 8088 (http) with context path ''] ## ''
[2024-09-09T09:41:38.804+08:00] [INFO] [mainraceId] [cn.git.helloApplication] [smallBigPower] [192.168.220.1] [docker-hello] [StartupInfoLogger.java,61,org.springframework.boot.StartupInfoLogger,logStarted] [Started helloApplication in 2.72 seconds (JVM running for 3.189)] ## ''
[2024-09-09T09:41:40.008+08:00] [INFO] [scheduling-1raceId] [cn.git.task.TimerTask] [smallBigPower] [192.168.220.1] [docker-hello] [TimerTask.java,24,cn.git.task.TimerTask,timer] [定时任务执行 : 1725846100008] ## ''
[2024-09-09T09:41:40.009+08:00] [ERROR] [scheduling-1raceId] [org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler] [smallBigPower] [192.168.220.1] [docker-hello] [TaskUtils.java,95,org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler,handleError] [Unexpected error occurred in scheduled task] ## ' java.lang.RuntimeException: 异常啦!
	at cn.git.task.TimerTask.timer(TimerTask.java:26)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
	at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:748)
'
Disconnected from the target VM, address: '127.0.0.1:61667', transport: 'socket'

Process finished with exit code -1

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内裤洗衣机哪个牌子好又实惠?诚意盘点五款绝佳内衣洗衣机!

在当今繁忙的生活中&#xff0c;内衣洗衣机已成为我们日常生活中不可或缺的家电。但是&#xff0c;面对市场上众多品牌的内衣洗衣机&#xff0c;那么&#xff0c;到底内衣洗衣机哪个牌子好&#xff1f;本次我将在这篇文章中探讨内衣洗衣机的选购策略&#xff0c;以帮助大家找到…

Java并发编程实战 10 | 线程安全问题

什么是线程安全&#xff1f; 《Java并发实践》的作者 Brian Goetz 对线程安全的定义是&#xff1a;当多个线程访问同一个对象时&#xff0c;如果无需考虑这些线程在运行时的调度策略和交替执行顺序&#xff0c;也不需要进行额外的同步处理&#xff0c;仍然能够得到正确的结果&…

C语言--12字符串处理函数

函数strstr 函数strchr与strrchr 注意&#xff1a; 这两个函数的功能&#xff0c;都是在指定的字符串 s 中&#xff0c;试图找到字符 c。strchr() 从左往右找第一个&#xff0c;strrchr() 从左往右找最后一个。字符串结束标记 ‘\0’ 被认为是字符串的一部分。 函数strlen 示例…

一款免费开源功能丰富的看图软件NeeView

NeeView 是一款功能丰富的图像查看软件&#xff0c;它以其独特的浏览体验和广泛的支持格式受到用户的欢迎。NeeView 不仅可以浏览普通的图像文件&#xff0c;还能够查看压缩包内的图片、预览PDF文档甚至播放视频文件。 NeeView 的主要特点&#xff1a; 多格式支持&#xff1a…

《人工智能安全治理框架》1.0版

人工智能是人类发展新领域&#xff0c;给世界带来巨大机遇&#xff0c;也带来各类风险挑战落实《全球人工智能治理倡议》&#xff0c;遵循“以人为本、智能向善”的发展方向&#xff0c;为推动政府、国际组织、企业、科研院所、民间机构和社会公众等各方&#xff0c;就人工智能…

无人机之穿越机的类型

穿越机&#xff0c;即FPV Drone或Racing Drone&#xff0c;是一种主要通过第一人称视角&#xff08;FPV&#xff09;进行操作的无人机。这种无人机通常配备有四个电机和相应的飞控系统&#xff0c;使其具有极高的飞行自由度和速度。穿越机的类型多样&#xff0c;可以从不同角度…

GD32E230程序烧录和开发环境使用介绍

GD32E230程序烧录和开发环境使用介绍 从GD32提供的资料来看&#xff0c;支持IAR、Keil、EmbeddedBuilder&#xff1b;目前该软件还是比较粗糙&#xff0c;个人上手体验不佳&#xff0c;面板菜单按键烧操作一下&#xff0c;动不动就卡死&#xff0c;仅支持gdlink调试器。 Embed…

第100+24步 ChatGPT学习:概率校准 Beta Calibration

基于Python 3.9版本演示 一、写在前面 最近看了一篇在Lancet子刊《eClinicalMedicine》上发表的机器学习分类的文章&#xff1a;《Development of a novel dementia risk prediction model in the general population: A large, longitudinal, population-based machine-learn…

元宇宙的崛起:重塑2024年游戏行业的新趋势

最早可以追溯到1994年&#xff0c;当时出现了世界上第一个轴测图界面的多人互动社交游戏《Web World》。‌这个游戏允许用户实时聊天、旅游、改造场景&#xff0c;开启了游戏中的UGC模式&#xff0c;可以视为元宇宙游戏的雏形。 2021年Roblox元宇宙的概念股上市&#xff0c;Fac…

学生护眼台灯哪个品牌比较好?分享五款效果好的学生护眼台灯

现在孩子的很多兴趣班和课后辅导班都是在线上举行&#xff0c;通常对着手机电脑长时间。电子产品有大量蓝光和辐射&#xff0c;会伤害到孩子的眼睛。但为了学习&#xff0c;也是没办法。护眼台灯的出现可以让孩子们的眼睛得到保护&#xff0c;防止蓝光对眼睛的伤害。学生护眼台…

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹&#xff0c;比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”&#xff0c;打开命令提示符&#xff0c;进入到发布代码目录 命令行启动.netcore项目的命令为: dotnet 项目启动文件.dll --urls"ht…

CSP-J基础之数学基础 计数原理与排列组合 一篇搞懂

文章目录 前言加法原理加法原理是什么使用场景 乘法原理举个例子总结 区别加法原理乘法原理总结 乘法原理的运用排列组合**排列****组合**总结 计算排列的可能种数举个例子数学定义数学公式应用公式例子应用 总结全排列举个例子数学定义数学公式作用 组合数学定义组合的公式举个…

系统安全设计规范(Word完整版)

1.1 总体设计 1.1.1 设计原则 1.2 物理层安全 1.2.1 机房建设安全 1.2.2 电气安全特性 1.2.3 设备安全 1.2.4 介质安全措施 1.3 网络层安全 1.3.1 网络结构安全 1.3.2 划分子网络 1.3.3 异常流量管理 1.3.4 网络安全审计 1.3.5 网络访问控制 1.3.6 完整性检查 1.…

天洑软件荣获国家级专精特新“小巨人”企业认定

近日&#xff0c;江苏省工业和信息化厅公布了第六批国家级专精特新"小巨人"企业名单&#xff0c;南京天洑软件有限公司&#xff08;以下简称“天洑软件”&#xff09;获得国家级专精特新“小巨人”企业认定。继2023年被评为江苏省“专精特新”中小企业后&#xff0c;…

【828华为云征文|华为云Flexus X实例:从选购到登录,一站式指南】

华为云Flexus X实例&#xff1a;从选购到登录&#xff0c;一站式指南 华为云Flexus X实例的优势大揭秘操作指南&#xff1a;一步步带你开通华为云Flexus X实例注册与登录华为云账号选择配置并购买选择Flexus X实例配置选择基础配置实例规格镜像存储网络弹性公网IP您可能需要&am…

佰朔资本:换手率是什么指标?换手率高股价为什么不涨呢?

换手率&#xff0c;也叫”周转率“&#xff0c;指的是在必定时间内商场中股票易手买卖的频率&#xff0c;是反映股票流通性强弱的指标之一。 换手率某段时期内成交量/发行总股数*100%。 通常而言&#xff0c;在股票商场上&#xff0c;换手次数多&#xff0c;筹码互动多&#…

Docker 部署 Kafka (图文并茂超详细)

部署 Kafka ( Docker ) Kafka对于zookeeper是强依赖&#xff0c;保存kafka相关的节点数据&#xff0c;所以安装Kafka之前必须先安装zookeeper [Step 1] : 部署 Zookeeper -> 拉取 Zookeeper 镜像 ➡️ 启动 Zookeeper 容器 docker pull zookeeper:3.4.14 docker run -d --…

Linux网络:网络协议栈协议

1.网络在体系结构的位置与网络协议栈的层状结构 2.协议栈各层的功能 协议栈分层设计达到了解耦目的&#xff0c;层与层之间只有接口之间的关系&#xff0c;提高了代码之间的可维护性与拓展性。同一层之间使用的协议相同&#xff0c;达到了跨设备的作用 3.协议 协议本质是一…

【详解】文件操作,Stream流

文件(File)操作——I/O流 Windows&#xff08;大多数&#xff09;进行文件操作的类File。 文件?文件夹?路径? 文件 能够使用工具打开操作的&#xff0c;文件是不能存储文件的。 一般文件具有后缀——.mp4 文件夹 存储文件的 路径问题——“/” 正右\ 反左/ ——统一朝左&am…

什么是点对点专线、SDH专线以及MSTP专线?

点对点专线&#xff08;Point-to-Point Circuit&#xff09;、SDH专线&#xff08;Synchronous Digital Hierarchy&#xff09;以及MSTP专线&#xff08;Multi-Service Transport Platform&#xff09;都是企业级通信服务中常见的网络连接类型&#xff0c;主要用于提供高带宽、…