log4j2的一些配置,为某个类某个方法单独文件打印日志,定时删除日志

本文详细介绍了Log4j2的日志配置方法,包括如何设置日志级别、日志输出格式、日志滚动策略等,并通过具体示例展示了如何针对特定类或方法配置单独的日志记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

log4j2.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<!-- status="OFF",可以去掉,它的含义为是否记录log4j2本身的event信息,默认是OFF -->
<configuration status="OFF">
    <!-- 定义下面的引用名 -->
    <Properties>
        <!--linux目录 /logs -->
        <!--<property name="basePath">/logs</property>-->
        <property name="basePath">${sys:catalina.home}/logs/webchat</property>
        <property name="rolling_pattern">%d{yyyy-MM-dd}-%i.gz</property>
        <property name="every_file_size">10MB</property><!-- 日志切割的最小单位 -->
        <property name="log_pattern">%d{yyyy-MM-dd HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n</property>
    </Properties>

    <!--先定义所有的appender -->
    <appenders>
        <!--这个输出控制台的配置 -->
        <Console name="Console" target="SYSTEM_OUT" >
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
            <ThresholdFilter level="trace" onMatch="ACCEPT"  onMismatch="DENY" />
            <!--这个都知道是输出日志的格式 -->
           <PatternLayout pattern="${log_pattern}"  charset="UTF-8"/>
        </Console>

        <!--这个会打印出所有的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
        <!-- 按月生成归档日志,可以使用 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz" -->
        <RollingFile name="RollingFile" fileName="${basePath}/sinter.log"
            filePattern="${basePath}/sinter.log${rolling_pattern}" >
            <PatternLayout pattern="${log_pattern}"  charset="UTF-8"/>
            <SizeBasedTriggeringPolicy size="${every_file_size}" />
        </RollingFile>

        <!--fileName com.sinter.interceptor.IndexInterceptor.java  方法日志 -->
        <RollingFile name="InterceptorRollingFile" fileName="${basePath}/interceptor.log"
                     filePattern="${basePath}/sinter.log${rolling_pattern}" >
            <PatternLayout pattern="${log_pattern}"  charset="UTF-8"/>
            <SizeBasedTriggeringPolicy size="${every_file_size}" />
        </RollingFile>

        <!--fileName com/sinter/controller/login/LoginController.java  sendCode方法日志 -->
<!--        <File name="sendCodeFile" fileName="${basePath}/sendCode.log" append="false">
            <PatternLayout pattern="${log_pattern}"/>
        </File>-->
        <RollingFile name="sendCodeRollingFile" fileName="${basePath}/sendCodeRollingFile.log" append="true"
                     filePattern="${basePath}/sendCodeRollingFile.log${rolling_pattern}">
            <PatternLayout pattern="${log_pattern}"  charset="UTF-8"/>

            <Policies>
                <SizeBasedTriggeringPolicy size="${every_file_size}"/>
                <!-- 每天凌晨0点  匹配的所有文件在10天或更长时间内将在翻滚时间删除。-->
                <CronTriggeringPolicy schedule="0 0 0 * * ?"/>
            </Policies>

            <DefaultRolloverStrategy>
                <Delete basePath="${basePath}" maxDepth="2">
                    <IfFileName glob="*.gz" />
                    <IfLastModified age="10d" />
                </Delete>
            </DefaultRolloverStrategy>

        </RollingFile>

    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
    <loggers>
        <!--建立一个默认的root的logger,需要在root的level中指定输出的级别, -->
        <root level="INFO" >
            <appender-ref ref="RollingFile" />
            <appender-ref ref="Console" />
        </root>
        <!--将logger中的 additivity 属性配置为 false,则这个logger不会将日志流反馈到root中。-->
        <Logger name="sendCodeLogger" additivity="false" level="INFO">
            <!--<appender-ref ref="sendCodeFile" level="INFO" />-->
            <appender-ref ref="sendCodeRollingFile" level="INFO" />
        </Logger>
        <Logger name="interceptorLogger" additivity="false" level="INFO">
            <appender-ref ref="InterceptorRollingFile" level="INFO" />
        </Logger>
    </loggers>

</configuration>

java类中代码片段如下:

@Controller
@RequestMapping("/login")
public class LoginController extends BaseController{

    static Logger sendCodeLogger = LogManager.getLogger("sendCodeLogger");


@RequestMapping(value = "/sendCode", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
@ResponseBody
public String sendCode(String phone,HttpServletRequest request) {

    String result = "error";

    try {
        String ip = CommonUtil.getRemoteIp(request);
        sendCodeLogger.info("###################ip为: "+ip);

        Enumeration em = request.getParameterNames();
        sendCodeLogger.info("###################开始记录手机验证码接口中的HttpServletRequest.getParameterNames");
        while (em.hasMoreElements()) {
            String name = (String) em.nextElement();
            String value = request.getParameter(name);
            sendCodeLogger.info("getParameter参数:"+name+" = "+value);
        }
        sendCodeLogger.info("###################结束记录getParameter参数");

<think>我们正在使用ELK Stack与Apollo集成实现日志全链路追踪,需要配置log4j2以支持提取traceId和spanId。 根据引用[1]和之前的知识,我们知道在分布式追踪中,通常会将TraceID和SpanID注入到日志中,以便在ELK中通过TraceID关联所有相关日志。 步骤: 1. 在log4j2配置文件中,配置PatternLayout,使用%X{traceId}和%X{spanId}来输出TraceID和SpanID。 2. 由于我们使用Apollo,可以考虑将日志格式(包括TraceID和SpanID的占位符)放在Apollo配置中心,实现动态更新。 3. 在ELK中,我们需要确保Logstash能够解析出TraceID和SpanID,以便在Kibana中根据TraceID进行过滤和查询。 具体配置如下: 在log4j2.xml中,我们可以这样配置: ```xml <Configuration status="info" monitorInterval="30"> <Properties> <!-- 从Apollo获取日志格式,如果Apollo中没有,则使用默认格式 --> <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%X{traceId}] [%X{spanId}] %-5level %logger{36} - %msg%n</Property> </Properties> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="${LOG_PATTERN}"/> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration> ``` 但是,我们还需要从Apollo动态更新这个日志格式。我们可以利用log4j2的Lookup功能,或者通过Apollo的配置监听器来更新。 这里,我们使用Apollo的配置监听器来动态更新日志格式: 1. 添加Apollo客户端依赖。 2. 在应用启动时,注册一个监听器,当Apollo中配置日志格式发生变化时,更新log4j2配置。 示例代码: ```java import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigChangeListener; import com.ctrip.framework.apollo.ConfigService; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder; public class Log4j2ConfigUpdater { public static void init() { Config config = ConfigService.getAppConfig(); config.addChangeListener(new ConfigChangeListener() { @Override public void onChange(ConfigChangeEvent changeEvent) { if (changeEvent.isChanged("log.pattern")) { String newPattern = changeEvent.getChange("log.pattern").getNewValue(); updateLog4j2Pattern(newPattern); } } }); } private static void updateLog4j2Pattern(String newPattern) { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); // 获取ConsoleAppender Appender appender = config.getAppender("Console"); if (appender instanceof ConsoleAppender) { ConsoleAppender consoleAppender = (ConsoleAppender) appender; // 创建新的PatternLayout PatternLayout layout = PatternLayout.newBuilder() .withPattern(newPattern) .withConfiguration(config) .build(); // 更新Appender的Layout consoleAppender.replaceAppender(layout); // 更新LoggerContext ctx.updateLoggers(); } } } ``` 注意:上面的代码是示例,实际使用时需要根据具体情况调整。 另外,我们还需要在Logstash的配置中,使用grok过滤器来解析日志中的traceId和spanId。假设我们的日志格式如下: 2024-01-01 12:00:00.000 [main] [1234567890abcdef] [1234567890abcdef] INFO com.example.Test - This is a log message 我们可以使用以下grok模式: ```ruby filter { grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:thread}\] \[%{DATA:traceId}\] \[%{DATA:spanId}\] %{LOGLEVEL:level} %{DATA:logger} - %{GREEDYDATA:message}" } } } ``` 这样,在Elasticsearch中就会存储traceId和spanId字段,我们可以在Kibana中通过traceId来搜索整个链路的日志。 但是,如果日志格式发生变化,我们需要同时更新log4j2配置和Logstash的grok模式。因此,建议将日志格式固定,或者通过Apollo统一管理,并确保Logstash的grok模式与日志格式保持一致。 总结: 1. 配置log4j2,使用%X{traceId}和%X{spanId}输出追踪信息。 2. 通过Apollo动态管理日志格式,实现热更新。 3. 配置Logstash的grok解析,提取traceId和spanId。 注意:TraceID和SpanID的传递需要依赖分布式追踪框架(如Sleuth、OpenTelemetry等)在服务间传递,并在MDC中设置。 相关问题: 1. 如何在Spring Boot应用中集成Sleuth来生成TraceID和SpanID? 2. 如何配置Logstash以支持动态的日志解析模式? 3. Apollo配置变更后如何自动更新Logstash的grok表达式? 4. 在Kibana中如何根据TraceID快速查询整个调用链的日志? 5. 如何确保日志格式变更时,Logstash的grok解析不会失败?</think>### Log4j2正则表达式配置实现ELK+Apollo全链路追踪 #### 核心配置步骤 1. **基础日志格式配置** 在`log4j2.xml`中配置TraceID/SpanID输出模式: ```xml <Configuration> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId:-N/A}] [%X{spanId:-N/A}] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> ... </Configuration> ``` 此配置会在日志输出:`[traceId] [spanId]`格式[^1] 2. **Apollo动态管理配置** 创建Apollo命名空间`logging-pattern`,添加配置项: ```properties # Apollo配置log4j2.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%X{spanId}] %-5level %msg%n ``` 3. **Log4j2动态加载Apollo配置** ```java @ApolloConfigChangeListener(interestedKeyPrefixes = "log4j2.") public void onChange(ConfigChangeEvent event) { if (event.isChanged("pattern")) { LoggerContext ctx = (LoggerContext) LogManager.getContext(false); Configuration config = ctx.getConfiguration(); // 更新所有Appender的PatternLayout config.getAppenders().values().forEach(appender -> { if (appender instanceof AbstractOutputStreamAppender) { Layout<?> layout = ((AbstractOutputStreamAppender<?>) appender).getLayout(); if (layout instanceof PatternLayout) { ((PatternLayout) layout).setPattern(event.getChange("pattern").getNewValue()); } } }); ctx.updateLoggers(config); } } ``` 4. **ELK Grok正则解析配置** 在Logstash中添加grok过滤器: ```ruby filter { grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{DATA:traceId}\] \[%{DATA:spanId}\] %{LOGLEVEL:level} %{GREEDYDATA:log}" } } } ``` #### 高级正则优化方案 ```ruby # 增强版正则(支持空处理) match => { "message" => "(?<timestamp>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.\d{3}) \[(?<traceId>[0-9a-f]{32}|N/A)\] \[(?<spanId>[0-9a-f]{16}|N/A)\] %{LOGLEVEL:level} %{GREEDYDATA:log}" } ``` #### 配置验证方法 1. **日志输出验证** 生成测试日志:`2023-08-01 14:30:45.123 [3d7f8e2a1b5c4f6a9e0d8c7b6a5f4e3d] [5a4b3c2d1e0f9a8b] INFO Service call completed` 2. **Kibana查询验证** ```kql traceId: 3d7f8e2a1b5c4f6a9e0d8c7b6a5f4e3d AND spanId: 5a4b3c2d1e0f9a8b ``` #### 动态更新演示 1. 在Apollo修改配置: ```diff - log4j2.pattern = ... [%X{traceId}] [%X{spanId}] ... + log4j2.pattern = ... TRACE-[%X{traceId}] SPAN-[%X{spanId}] ... ``` 2. 日志自动更新为: `2023-08-01 14:35:22.456 TRACE-3d7f8e2a... SPAN-5a4b3c2d... INFO New format` #### 异常处理机制 ```ruby filter { grok { match => { ... } # 上述正则 tag_on_failure => ["_grokparsefailure_tracing"] } if "_grokparsefailure_tracing" in [tags] { # 发送告警到监控系统 http { url => "http://alert-system/api/tracing-format-error" } # 原始日志单独索引 mutate { replace => { "[@metadata][target_index]" => "tracing_error_logs" } } } } ``` ### 关键技术说明 1. **TraceID生成规范** - 长度:32字符十六进制 - 生成规则:`UUID.randomUUID().toString().replace("-", "")` 2. **跨服务传递** 在HTTP头/RabbitMQ属性中传递: ```java // HTTP请求 template.header("X-Trace-Id", MDC.get("traceId")); // RabbitMQ消息 message.getMessageProperties().setHeader("traceId", MDC.get("traceId")); ``` 3. **Apollo高可用机制** 采用push+pull双模式保障配置同步[^3]: ```mermaid graph LR A[Apollo配置中心] -->|Push| B[服务实例] B -->|定时Pull| A ``` --- ### 相关问题 1. 如何在Spring Cloud Gateway中透传TraceID到下游服务?[^4] 2. 如何通过Kibana Lens可视化分析TraceID的调用链路性能? 3. Apollo配置变更后Logstash如何自动更新grok表达式? 4. 在RabbitMQ消息系统中如何保证TraceID的跨服务传递? 5. 如何配置Logstash死信队列处理格式错误的追踪日志
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nathan0529

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值