Solon 的日志设计哲学:不只是用 SLF4J 做统一门面

每个 Java 项目都需要日志。每个 Java 开发者都有一两个关于日志配置的"战争故事"------那个膨胀到 200 行的 XML、互相打架的桥接包、深夜因为日志级别没控制好打满磁盘的报警。

Solon 换了一种做法:保留行业标准(SLF4J),但用一段 YAML 替代了 XML 配置的混乱。日志配置不再是一个需要单独学习的"副项目",而是应用配置的自然延伸。

全栈:SLF4J 直通

Solon 原生使用 SLF4J 作为日志门面,没加任何私有包装层:

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OrderService {
    static final Logger log = LoggerFactory.getLogger(OrderService.class);

    public void createOrder(Order order) {
        log.info("创建订单: {}", order.getId());
    }
}

没有桥接,没有适配器,没有额外依赖。如果你用过 SLF4J,你已经在用 Solon 的日志 API 了。

五个插件,一套配置

Solon 提供了五种日志实现,每种都对接同一套配置模型。切换实现只需换一个依赖:

插件 添加器支持 适用场景
solon-logging-simple console, cloud 测试/轻量,不产生本地日志文件
solon-logging-logback console, file, cloud 生产推荐(Logback 1.3.x, Java 8+)
solon-logging-logback-jakarta console, file, cloud Jakarta 命名空间(Logback 1.5.x, Java 11+)
solon-logging-log4j2 console, file, cloud 团队统一使用 Log4j2
water-solon-cloud-plugin console, cloud Water 服务治理平台对接

加入一个依赖就完成了配置:

xml 复制代码
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-logging-logback</artifactId>
</dependency>

就这样。不需要 logback.xml,不需要 log4j2.xml------除非你需要高级定制。

配置:一段 YAML 搞定

所有日志配置集中在 solon.logging.appendersolon.logging.logger 两个字段下:

yaml 复制代码
solon:
  app:
    name: demoapp

solon.logging.appender:
  console:
    level: TRACE
    enable: true
    pattern: "%highlight{%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} #%5X{pid} [-%t][*%X{traceId}]%tags[%logger{20}]:} %n%msg%n"
  file:
    name: "logs/${solon.app.name}"
    level: INFO
    enable: true
    extension: ".log"
    maxFileSize: "10 MB"
    maxHistory: "7"
    pattern: "%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} #%5X{pid} [-%t][*%X{traceId}]%tags[%logger{20}]: %n%msg%n"
  cloud:
    level: INFO
    enable: true

框架内置三个添加器:

  • console --- 标准输出,默认启用
  • file --- 滚动日志文件,默认启用
  • cloud --- 远程日志服务,默认关闭

按包控制日志级别

yaml 复制代码
solon.logging.logger:
  "root":
    level: DEBUG
  "com.zaxxer.hikari":
    level: WARN
  "com.demo.order":
    level: INFO

优先级规则很简单:appender 级别 > logger 级别 > root 级别,更具体的配置优先。

五个级别,标准语义

text 复制代码
TRACE < DEBUG < INFO < WARN < ERROR

和你一直在用的级别一样。

MDC:SLF4J 标准支持

Solon 直接继承 SLF4J 的 MDC 能力,没有封装私有 API。默认日志 pattern 中已经包含了 %X{pid}(进程 ID)和 %X{traceId}(分布式链路追踪 ID),这些由框架自动填充。

如果需要自定义上下文,用标准 SLF4J 方式:

java 复制代码
import org.slf4j.MDC;

MDC.put("orderId", order.getId());
log.info("处理支付");
MDC.remove("orderId");

没有 Solon 专属的 MDC 包装类,就是原生 SLF4J。

自定义添加器

内置添加器不够用时,继承 AppenderBase

java 复制代码
package demo.log;

import org.noear.solon.logging.event.AppenderBase;
import org.noear.solon.logging.event.LogEvent;

public class JsonAppender extends AppenderBase {
    @Override
    public void append(LogEvent logEvent) {
        String json = toJson(logEvent);
        send(json);
    }
}

app.yml 中注册:

yaml 复制代码
solon.logging.appender:
  json:
    level: INFO
    class: demo.log.JsonAppender

异步批量日志:PersistentAppenderBase

对于高吞吐场景,Solon 提供了 PersistentAppenderBase------一个将日志事件缓冲后批量刷盘的基类:

java 复制代码
package demo.log;

import org.noear.solon.logging.persistent.PersistentAppenderBase;
import org.noear.solon.logging.event.LogEvent;
import org.noear.solon.Solon;

public class DatabaseAppender extends PersistentAppenderBase {
    LogService logService;

    public DatabaseAppender() {
        Solon.context().getBeanAsync(LogService.class, bean -> {
            logService = bean;
        });
    }

    @Override
    public void onEvents(List<LogEvent> list) {
        if (logService != null) {
            logService.insertList(list);
        }
    }
}

适合将日志写入数据库、Elasticsearch 或其他远程存储,不阻塞请求线程。批量写入在高负载下能显著降低 I/O 开销。

高级定制:XML 逃生门

如果 YAML 不满足你的需求,在 classpath 根目录放一个 logback-solon.xmllog4j2-solon.xml 即可。框架会自动识别,且支持环境变体(logback-solon-dev.xmllogback-solon-prod.xml)。

也可以用标准的 logback.xmllog4j2.xml------但这样会失去按环境切换的能力。

云端日志:一个插件的事

分布式环境下,引入 water-solon-cloud-plugin 并启用 cloud 添加器:

yaml 复制代码
solon.logging.appender:
  cloud:
    level: INFO
    enable: true

日志自动上报 Water 服务治理平台,无需额外部署日志采集 agent。

诚实地说

Solon 的日志模块不会替代完整的可观测性管道(Logstash + Elasticsearch、Loki + Grafana)。但对绝大多数项目来说,它覆盖了所有日常需求:

  • ✅ SLF4J 原生,告别桥接依赖
  • ✅ YAML 驱动,告别 XML 样板代码
  • ✅ 三个内置添加器(console / file / cloud)
  • ✅ 自定义添加器支持
  • ✅ 异步批量持久化
  • ✅ MDC 开箱即用
  • ✅ 按包控制日志级别
  • ✅ 环境感知配置切换
  • ✅ Logback/Log4j2 XML 逃生门

设计哲学和 Solon 的其他模块一样:用最少的配置解决最常见的问题,需要定制时绝不挡路。


如果你想了解完整的插件列表和配置参考,官方文档在 solon.noear.org

相关推荐
Flittly4 小时前
【雕虫大技】Agent 动态 Skill 供应链安全加固(二):执行隔离沙箱实战
java·spring boot·spring
程序员黑豆4 小时前
Java变量详解:从入门到精通
java·前端·ai编程
karry_k4 小时前
Skill 到底是什么?从提示词、脚本到多智能体工作流的完整指南
java·人工智能·后端
qq_401700414 小时前
Qt自定义信号槽详解:带参发射 vs sender()获取,两种多信号关联方案全掌握
java·数据库·qt
周杰伦fans5 小时前
数列极限的定义
java·开发语言
小白的后端世界5 小时前
LangChain 模型初始化参数详解:从基础配置到企业级实践
java·人工智能·langchain
广州浮点FLOATLIC5 小时前
Mentor Graphics浮动许可证管理为什么一到流片节点就失控
java·大数据·数据库·许可证管理·cad 许可证优化
Loongproxy5 小时前
大规模采集为啥用隧道代理IP?会话保持如何做到无感轮换
java·服务器·网络
杰克尼6 小时前
天机学堂面试题
java