leniu-java-logging

SKILL.md

leniu 日志规范

基本规则

  • 使用 @Slf4j(Lombok),禁止直接用 Log4j/Logback API
  • 使用 {} 占位符,禁止字符串拼接
  • 异常对象作为 log.error最后一个参数(自动打印堆栈)
  • 日志用中文,用 【模块名】 前缀便于检索
  • 禁止记录密码、完整手机号等敏感信息

日志级别选择

级别 场景 示例
ERROR 系统错误、需立即处理 数据库异常、外部服务失败
WARN 非预期但可处理 配置缺失用默认值、数据不存在
INFO 关键业务节点 订单创建/支付成功、定时任务完成
DEBUG 开发调试(生产不输出) 查询参数、中间结果

模块标识格式

log.info("【订单】开始创建订单, userId:{}", userId);
log.info("【支付】支付成功, orderId:{}, transactionId:{}", orderId, txId);
log.info("【库存】扣减库存, productId:{}, quantity:{}", productId, qty);
log.error("【远程调用】用户服务调用失败, userId:{}", userId, e);

MQ 消费用方括号:

log.info("[xxx事件]MQ消费:开始");
log.info("[xxx事件]MQ消费:消息消费完成");
log.error("[xxx事件]MQ消费:处理异常", e);

异常日志(最重要)

// ✅ 正确:异常 e 作为最后参数,保留完整堆栈
try {
    doProcess(orderId);
} catch (Exception e) {
    log.error("订单处理失败, orderId:{}", orderId, e);
    throw new LeException("订单处理失败");
}

// ✅ 记录案发现场(关键参数 + 上下文)
try {
    updateStatus(orderId, status);
} catch (Exception e) {
    log.error("订单状态更新失败, orderId:{}, oldStatus:{}, newStatus:{}",
              orderId, oldStatus, status, e);
    throw new LeException("订单状态更新失败");
}

// ❌ 错误:只记录 message,丢失堆栈
log.error("处理失败:{}", e.getMessage());

各层日志规范

Business/Service 层(关键业务)

@Slf4j
@Service
public class OrderService {

    @Transactional(rollbackFor = Exception.class)
    public Long create(OrderParam param) {
        log.info("【订单】开始创建订单, userId:{}, productId:{}",
                 param.getUserId(), param.getProductId());
        try {
            Order order = buildOrder(param);
            orderMapper.insert(order);
            log.info("【订单】订单创建成功, orderId:{}", order.getId());
            return order.getId();
        } catch (Exception e) {
            log.error("【订单】订单创建失败, param:{}", param, e);
            throw new LeException("订单创建失败");
        }
    }
}

定时任务

@Slf4j
@Component
public class DataSyncJob {

    @XxlJob("syncDataJob")
    public void syncData() {
        log.info("【定时任务】开始同步数据");
        try {
            int count = doSync();
            log.info("【定时任务】数据同步完成, 同步数量:{}", count);
        } catch (Exception e) {
            log.error("【定时任务】数据同步失败", e);
        }
    }
}

MQ 消费者

@Slf4j
@MQMessageListener(group = "order-order-v3-xxx", topic = "order", tag = "order-v3-xxx")
public class OrderMqListenerXxx implements MQListener<MqPayload<String>> {

    @Override
    public void onMessage(MqPayload<String> payload) {
        log.info("[xxx事件]MQ消费:开始");
        orderMqHandler.handleMessage(payload, OrderXxxPO.class, OrderMqHandler::handleXxx);
    }
}

外部调用

public UserDTO getUserFromRemote(Long userId) {
    log.info("【远程调用】开始调用用户服务, userId:{}", userId);
    try {
        UserDTO user = remoteUserService.getUser(userId);
        log.info("【远程调用】用户服务调用成功, userId:{}", userId);
        return user;
    } catch (Exception e) {
        log.error("【远程调用】用户服务调用失败, userId:{}", userId, e);
        throw new LeException("用户信息获取失败");
    }
}

性能规则

// ✅ debug 级别用条件判断或 Lambda(避免无用计算)
if (log.isDebugEnabled()) {
    log.debug("详细数据: {}", expensiveOperation());
}

// ✅ 批量操作:前后各一条,不在循环内打印
log.info("开始处理订单, 数量:{}", orders.size());
int success = 0, fail = 0;
for (Order order : orders) {
    try { process(order); success++; }
    catch (Exception e) { log.error("订单处理失败, orderId:{}", order.getId(), e); fail++; }
}
log.info("订单处理完成, 成功:{}, 失败:{}", success, fail);

// ✅ 只记录关键信息,不序列化大对象
log.info("查询结果数量: {}", orders.size());  // ✅
// log.info("查询结果: {}", orders);          // ❌ 大对象

敏感信息脱敏

// ❌ 禁止记录:密码、完整手机号、身份证、银行卡
log.info("用户登录, username:{}, password:{}", username, password);

// ✅ 脱敏后记录
log.info("发送验证码, mobile:{}", maskMobile(mobile)); // 138****1234

脱敏工具:详见 references/data-mask.md

Logback 配置

配置文件:core-starter/src/main/resources/logback-spring.xml

Profile 作用
no_log_console 不输出到控制台
no_log_file 不输出到文件
# application.yml 日志级别
logging:
  level:
    net.xnzn.core: INFO        # 项目
    com.baomidou.mybatisplus: INFO
    org.springframework: WARN

开发环境 net.xnzn.core: DEBUG,生产环境 INFO + no_log_console

禁止项

// ❌ 直接用 Log4j API
import org.apache.log4j.Logger;

// ❌ 字符串拼接
log.info("userId:" + userId + ", name:" + name);

// ❌ 无意义日志
log.info("进入方法");
log.info("退出方法");

// ❌ 英文日志(项目要求中文)
log.info("Order created successfully");

// ❌ 丢失异常堆栈
log.error("失败:{}", e.getMessage());

参考文档

  • 详细场景示例(Controller/分页/远程调用):详见 references/logging-scenarios.md
  • 脱敏工具方法:详见 references/data-mask.md
Weekly Installs
3
GitHub Stars
8
First Seen
8 days ago
Installed on
gemini-cli3
github-copilot3
codex3
kimi-cli3
cursor3
amp3