2. 工业设备软件日志体系设计

工业设备软件的日志与互联网服务日志有本质差异:它面对的是实时控制回路、现场总线、PLC 扫描周期和毫秒级时序约束。日志写得太细会拖慢控制线程,写得太粗则在故障复现时无从下手。本节围绕日志分级、结构化规范、工业协议与设备事件日志、采集点选择、生命周期管理、面向诊断的字段设计六个方面展开,并最终落到一个可执行的实战任务:为某 PLC 上位机软件设计日志规范。

一、日志分级:按“谁来看、多久看”划分

工业上位机常见的分级是 TRACE / DEBUG / INFO / WARN / ERROR / FATAL 六级,但真正决定分级是否可用的是判定标准,而不是级别名称。建议用“动作主体 + 影响范围”来定级:

  • FATAL:进程无法继续,如与控制器的通信线程崩溃、许可证校验失败导致主功能不可用。
  • ERROR:一次业务操作失败但进程存活,如写 PLC 寄存器返回超时、配方下发校验不通过。
  • WARN:指标越界或降级运行,如通信重连成功、扫描周期超过设定阈值但仍完成。
  • INFO:状态迁移与关键业务动作,如“连接建立”“进入自动模式”“批次 B20240513 开始”。
  • DEBUG:单次交互的输入输出,如一条 Modbus 请求的报文摘要。
  • TRACE:逐字节/逐帧细节,仅用于短时抓取,默认关闭。

关键约束是:INFO 及以上必须默认开启且可长期保留,DEBUG/TRACE 通过运行时开关按模块动态打开,避免为了排障而重启上位机——重启往往会让现场状态丢失,故障无法复现。

二、结构化日志规范

工业现场排障常需要按“设备 + 点位 + 时间窗”检索,纯文本日志几乎无法支撑。结构化日志的核心是固定字段名与取值约定。推荐以 JSON Lines 输出,每行一条记录,字段分三层:

  • 公共层:ts(ISO8601 带毫秒与时区)、level、logger、pid、thread、host、app、app_ver。
  • 设备层:device_id、device_type、protocol、endpoint(如 192.168.1.10:502)、unit_id。
  • 业务层:event_code、point(如 DB1.DBD0)、value、duration_ms、result、trace_id。

其中 event_code 建议采用“模块.对象.动作”的稳定编码,例如 comm.modbus.write_timeout、recipe.download.checksum_mismatch。编码一旦发布不得随意改名,否则历史日志的聚合统计会断裂。trace_id 用于把一次“操作员点击下发配方”引发的通信、校验、写库多条日志串成一条链路。

三、工业协议与设备事件日志

协议层日志不能只记“通信失败”,要能回答“哪一帧、哪个字段、什么异常码”。以 Modbus TCP 为例,一次写保持寄存器失败,应记录功能码 0x10、起始地址、寄存器数量、异常码(如 0x02 非法数据地址、0x0B 网关目标设备无响应)以及耗时。S7 通信则应记录 PDU 参考号、区域(DB/I/Q/M)、字节偏移与返回状态码。

设备事件日志与协议日志要分开:前者描述设备自身状态变化(急停按下、伺服使能丢失、安全门打开),来源可能是 PLC 的报警位、OPC UA 事件订阅或设备自带诊断缓冲区;后者描述上位机与设备之间的交互。二者用同一 trace_id 关联,才能在“设备报警 → 上位机响应 → 操作员处置”之间建立因果链。

PLC 上位机日志体系:采集点、字段与生命周期 采集点 通信驱动层 帧/异常码/耗时 业务逻辑层 配方/批次/校验 设备事件层 报警位/安全信号 UI/操作层 操作员动作 系统资源层 CPU/内存/队列 结构化字段 公共层 ts / level / logger pid / thread / app_ver 设备层 device_id / protocol endpoint / unit_id 业务层 event_code / point value / duration_ms result / trace_id 日志生命周期 热存储 7 天 · 全量 温存储 90 天 · INFO+ 归档 2 年 轮转与保护策略 • 单文件 50 MB,按天+大小双触发轮转 • 磁盘占用超 80% 时优先淘汰 DEBUG/TRACE • ERROR/FATAL 独立文件,禁止被轮转覆盖 诊断检索路径 trace_id → 全链路还原 device_id + 时间窗 → 设备故障史 event_code 聚合 → 高频故障排序

四、采集点选择

采集点不是越多越好。选择原则是“能定位到责任边界”:通信驱动层记录帧级交互与异常码,用于判断是网络、设备还是上位机的问题;业务逻辑层记录配方、批次、校验结果,用于判断业务规则是否被正确执行;设备事件层记录报警与安全信号,用于还原现场工况;UI/操作层记录操作员动作,用于区分人为操作与系统异常;系统资源层记录 CPU、内存、日志队列积压,用于发现日志本身成为瓶颈。

需要特别注意的是日志写入不能阻塞控制线程。推荐异步队列 + 独立写盘线程,队列水位超过阈值时降级丢弃 TRACE/DEBUG 并产生一条 WARN,而不是让通信线程等待磁盘 IO。

五、日志生命周期管理

工业现场上位机常部署在无外网的工控机上,磁盘容量有限。建议采用三级生命周期:热存储保留 7 天全量日志,支持秒级检索;温存储保留 90 天 INFO 及以上级别,用于月度分析;归档保留 2 年,仅保留 ERROR/FATAL 与关键业务事件,用于质量追溯。轮转策略采用“按天 + 按大小”双触发,单文件 50 MB。磁盘占用超过 80% 时,优先淘汰 DEBUG/TRACE,ERROR/FATAL 单独文件且禁止被轮转覆盖。

六、面向诊断的日志字段设计

字段设计要服务于“排障时你会怎么问”。常见问题与对应字段:

排障问题必需字段
哪台设备出问题?device_id、endpoint、unit_id
什么时候开始?ts(毫秒精度)、duration_ms
是通信还是业务问题?protocol、event_code、result
影响哪些点位?point、value
能否还原完整链路?trace_id、thread、pid

实战任务:为某 PLC 上位机软件设计日志规范

假设对象为一套注塑机 PLC 上位机软件,通过 Modbus TCP 与 3 台 PLC 通信,周期 100 ms 采集温度与压力,支持配方下发。规范要点如下:

  1. 分级:INFO 默认开启;通信超时、配方校验失败记 ERROR;扫描周期超 150 ms 记 WARN;帧级细节记 DEBUG,默认关闭。
  2. 格式:JSON Lines,字段固定为 ts、level、logger、device_id、protocol、endpoint、unit_id、event_code、point、value、duration_ms、result、trace_id。
  3. 事件编码:comm.modbus.read_timeout、comm.modbus.write_exception、recipe.download.checksum_mismatch、device.alarm.over_temp。
  4. 采集点:通信驱动、配方服务、报警订阅、操作日志、资源监控五处。
  5. 生命周期:热 7 天、温 90 天、归档 2 年;单文件 50 MB;磁盘 80% 触发降级。

示例日志行(配方下发校验失败):

{"ts":"2024-05-13T09:21:07.482+08:00","level":"ERROR","logger":"recipe.service",
 "device_id":"IMM-01","protocol":"modbus_tcp","endpoint":"192.168.1.10:502","unit_id":1,
 "event_code":"recipe.download.checksum_mismatch","point":"DB1.DBD0","value":null,
 "duration_ms":38,"result":"fail","trace_id":"a3f9c1e2"}

验证方式:人为制造一次校验失败,确认该行日志出现且 trace_id 能关联到同一次操作的下发请求与 PLC 返回帧;随后按 device_id 与时间窗检索,应能还原“操作员下发 → 校验失败 → 未写入 PLC”的完整链路。若 trace_id 缺失或 event_code 不统一,则规范未达标,需回到字段设计阶段修正。

建议把 event_code 清单纳入版本管理,新增编码需评审;日志字段一旦上线,删除或改名必须走兼容流程,否则历史日志的聚合分析会失效。