写在开头
hi,我是可乐,今天我们来聊一聊日志
有一次线上出问题,反馈说导入了一批商品数据,系统提示成功,但页面就是搜不到。我查了半天数据库,发现一条都没进去。
我去翻日志,想看看导入过程中发生了什么,结果只找到两条:
INFO - 开始导入INFO - 导入完成中间解析了多少条?校验失败了几个?入库成功了多少?一概不知。最后是把Excel文件要过来,本地跑了一遍才定位到问题——有一行的价格字段格式不对,导致整批数据回滚了。
那天我学到一个道理:日志不是打给自己看的,是打给半夜被叫起来排查问题的自己看的。
但问题来了:什么时候该打日志?打什么内容?用info还是error?这事如果直接问AI,它大概率会给你一个“看起来都对但没什么用”的答案。因为它根本不知道你这导入流程是怎么设计的。
今天聊聊正确的姿势:先让AI理解你的业务逻辑,再让它给出日志建议。
一、场景痛点:一个“哑巴”式的导入方法
假设我们做了一个商品信息的Excel导入功能。Controller接收文件,Service负责解析和入库。代码大概长这样:
@ServicepublicclassProductImportService{privatestaticfinal Logger logger = LoggerFactory.getLogger(ProductImportService.class);@Autowiredprivate ProductMapper productMapper;@TransactionalpublicvoidimportProducts(MultipartFile file){ logger.info("开始导入商品"); List<ProductExcelDTO> excelData = ExcelUtils.read(file, ProductExcelDTO.class); List<Product> products = new ArrayList<>();for (ProductExcelDTO dto : excelData) {if (StringUtils.isBlank(dto.getName()) || dto.getPrice() == null) {continue; } Product p = new Product(); p.setName(dto.getName()); p.setPrice(dto.getPrice()); p.setCategory(dto.getCategory()); products.add(p); } productMapper.batchInsert(products); logger.info("导入完成"); }}这段代码的日志有什么问题?
导入了多少条数据?不知道。 跳过了多少条无效数据?不知道。 批量插入成功了多少条?不知道。 整个导入花了多长时间?没打。 万一入库失败,能看到的只有异常堆栈,没有业务上下文。
排查问题的时候,你只能对着一个“导入完成”发呆——更可气的是,如果入库失败了,这条“导入完成”根本不会打印,但“开始导入”之后发生了什么,完全是个黑盒。
二、正确的姿势:先让AI理解业务,再让它给日志建议
直接把代码丢给AI让它“加日志”,AI只会机械地在每个循环里塞一句logger.info("处理第{}行", i)。正确的方式是:先用自然语言告诉AI这个导入流程是怎么设计的,有哪些关键节点,再让它判断哪里该打日志。
提示词示例:我有一段Excel导入的Java代码,请先理解业务逻辑,然后给出日志打点建议。业务背景描述:- 用户通过Web页面上传一个Excel文件,文件中每一行是一条商品信息- 系统需要解析Excel,逐行校验数据(商品名称和价格不能为空)- 校验通过的数据批量插入数据库- 校验不通过的行直接跳过,不影响其他行的处理- 整个导入过程在一个事务中,如果入库失败则整体回滚请你先复述你对这个业务流程的理解,然后回答:1. 这个流程中有哪些“关键时刻”需要记录日志?2. 每个关键时刻应该记录什么信息?3. 哪些地方用info,哪些用warn,哪些用error?4. 最后给出修改后的代码。代码如下:[粘贴代码]AI先复述业务,再给建议
如果提示词写到位,AI会先输出它对业务的理解:
我的业务理解:这是一个Excel导入功能,包含以下关键步骤:
接收文件:用户上传了一个Excel文件 解析文件:将Excel每一行转换为DTO对象 数据校验:过滤掉商品名称或价格为空的行 批量入库:将有效数据批量插入数据库 事务控制:整个过程在事务内,入库失败则全部回滚
然后基于这个理解给出日志建议:
日志打点建议:
入口处:记录文件名和文件大小,方便追溯 解析完成后:记录总行数 校验阶段:记录跳过的无效数据条数 入库前:记录待入库的有效数据条数 入库后:记录成功入库的条数 出口处:记录整个导入的统计信息和耗时 异常处理:解析失败或入库失败时记录完整的错误堆栈和业务上下文
三、优化后代码:日志能讲故事了
@ServicepublicclassProductImportService{privatestaticfinal Logger logger = LoggerFactory.getLogger(ProductImportService.class);@Autowiredprivate ProductMapper productMapper;@TransactionalpublicvoidimportProducts(MultipartFile file){long startTime = System.currentTimeMillis(); String fileName = file.getOriginalFilename();long fileSize = file.getSize(); logger.info("开始导入商品, fileName={}, fileSize={}bytes", fileName, fileSize);// 1. 解析Excel List<ProductExcelDTO> excelData;try { excelData = ExcelUtils.read(file, ProductExcelDTO.class); } catch (Exception e) { logger.error("Excel解析失败, fileName={}", fileName, e);thrownew BusinessException("Excel文件解析失败,请检查文件格式"); } logger.info("Excel解析完成, 总行数={}", excelData.size());// 2. 校验和转换 List<Product> validProducts = new ArrayList<>();int skipCount = 0;for (ProductExcelDTO dto : excelData) {if (StringUtils.isBlank(dto.getName()) || dto.getPrice() == null) { skipCount++;continue; } Product p = new Product(); p.setName(dto.getName()); p.setPrice(dto.getPrice()); p.setCategory(dto.getCategory()); validProducts.add(p); }if (skipCount > 0) { logger.warn("校验阶段跳过无效数据, 跳过条数={}", skipCount); } logger.info("校验完成, 有效数据条数={}", validProducts.size());// 3. 入库if (validProducts.isEmpty()) { logger.info("无有效数据需要导入, fileName={}, 导入结束", fileName);return; }try { productMapper.batchInsert(validProducts); logger.info("批量入库成功, 入库条数={}", validProducts.size()); } catch (Exception e) { logger.error("批量入库失败, 事务将回滚, 待入库条数={}, fileName={}", validProducts.size(), fileName, e);thrownew BusinessException("数据入库失败,已回滚"); }long costTime = System.currentTimeMillis() - startTime; logger.info("导入完成, fileName={}, 总行数={}, 有效行数={}, 跳过行数={}, 耗时={}ms", fileName, excelData.size(), validProducts.size(), skipCount, costTime); }}关键改动说明:
logger.info("开始导入商品") | ||
logger.info("导入完成") | ||
特别注意:最后那条“导入完成”日志放在入库成功之后、方法正常返回之前。如果入库抛异常,根本走不到这行,不会出现“入库失败却打印导入完成”的逻辑矛盾。
四、这个方法的本质:让AI扮演Code Review的同事
你想想,平时你怎么让同事帮你看日志打得合不合适?
你会把代码往他面前一丢说“帮我看看”吗?不会。你会先跟他讲:这个导入流程分几步,先解析Excel,再校验,最后批量入库,校验不通过的跳过。他理解了这些,才能告诉你“解析完应该打一条,记录总行数”、“校验完应该打一条,记录跳过了多少”。
AI也是一样。你不给它业务上下文,它就给你废话。
五、AI提示词模板(可直接复制)
我有一段Java业务代码,请先理解业务逻辑,然后给出日志打点建议。【业务背景描述】- 这个功能是做什么的?(例如:用户上传Excel批量导入商品)- 处理流程分几步?(例如:解析文件→逐行校验→批量入库)- 有哪些业务规则?(例如:名称和价格不能为空,为空的行跳过)- 事务范围是怎样的?(例如:整体一个事务,失败则回滚)请你:1. 用你自己的话复述一遍你对这个业务流程的理解2. 列出这个流程中的“关键时刻”,以及每个时刻该记录什么信息3. 给出日志级别的建议(info/warn/error)4. 最后给出修改后的完整代码代码如下:[在此粘贴你的代码]今天分享到这里,我们下期再见
喜欢的话记得点赞哦
夜雨聆风