我这边的业务日志一般是: 原始业务表的数据Copy + 日志创建时间 + 操作人 + 操作Id + (可选)操作类型(一般是一个枚举)
至于怎么Copy原始业务表,AutoMapper映射下不要太简单
然后结合下上面的理论篇,我们这里需要获取到一个操作Id用于接下来和参数日志关联。
在现在Core的年代下直接用Activity即可
在你请求进来的时候它默认就已经构造了,并且能确保当前请求内是唯一,Activity生成的Id也是符合opentelemetry规范的分布式追踪Id
其他一些APM工具(比如我用的AppInsights)现在它内部的追踪Id也都是基于这套来进行运作
如何存参数日志
首先结合之前说到参数日志的特点,量大,单位价值低
之前我们没更好的存储介质的时候也是直接存数据库里,然后DBA就经常跟我们说这个太大了,要定期清理下,然后我们大概是3周一清
如果一个问题潜伏3周以上对我们就是个麻烦事了
而且也因此导致我们对存储参数日志也比较谨慎(稍微量上去了就会叫)
所以我们认清了如下几个基本事实:
①关系型数据库是属于昂贵存储,它应该存储的是价值高的昂贵数据
②数据必须分层,高价值的和低价值的分开
在结合下前面我们提到的基于一个分布式追踪Id的日志设计体系,所以还要提供不低于1个索引能力的查询支持
后面我们就用上了Azure Table Storage
具体Table是什么我之前有一篇文章有简单介绍 Azure Table Storage 简单介绍
我们把分布式追踪Id作为PartitionKey,其他abp里能提供的数据统统塞Table里
最后的代码大概是这样
里面折叠的那个FillAudit方法
经过上述设计,我们整个日志现在基本就玩的比较转,一旦有什么问题,我们先查询业务日志,然后可以通过任意一条业务日志在关联到参数日志定位到当时是什么参数进来的,由此提升排查问题的速度
Note:可能有些眼尖的人会发现我的Async的方法没await,经过测试证明Table那边的调用可以FireAndForgot的,而且基本上也不会丢数据,So这不是Bug或者疏忽,是故意的,反而那个Catch可能是一句无效代码
上面我重写Audit的是每次来一个请求我就往Table存一条记录,如果是面向高并发接口(比如查询类的接口)
上面我所说的这个做法会让你死得很惨
正确做法应该是:
将数据先在本地内存缓存一段时间后,当达到某个时间阈值或者数据量累计到一定程度再发送
这个做法背后还是蛮复杂的,不过当年我们再琢磨这个东西的时候发觉我们用的AppInsights的SDK里也有这个玩意,我们直接拿出来稍微定制了下后发觉还真能用。