扩展RIO日志函数以在内存中存储日志
在RIO中实现带日志存储功能的LogFunc
要实现既能存储日志到IORef [UTF8Builder],又能调用常规RIO日志函数的LogFunc,核心是利用官方暴露的mkLogFunc和runLogFunc接口,完全不需要依赖未导出的unLogFunc。以下是具体实现方案:
1. 核心实现代码
首先导入必要的模块:
import RIO
然后编写创建带存储功能的LogFunc的函数:
mkStoredLogFunc :: IORef [UTF8Builder] -> LogFunc -> IO LogFunc mkStoredLogFunc logRef originalLogFunc = mkLogFunc $ \ctxt level msg -> do -- 将日志消息原子性地添加到IORef的列表中 atomicModifyIORef' logRef (\logs -> (msg : logs, ())) -- 调用原有的常规LogFunc,保持原有日志输出逻辑 runLogFunc originalLogFunc ctxt level msg
2. 使用示例
在主程序中可以这样使用:
main :: IO () main = do -- 初始化存储日志的IORef,初始为空列表 logStorage <- newIORef [] -- 创建常规的控制台输出LogFunc(日志级别设为Debug) consoleLog <- logFuncOptions stdout LogDebug -- 生成带存储功能的LogFunc storedLog <- mkStoredLogFunc logStorage consoleLog -- 用这个LogFunc运行RIO程序 runRIO storedLog $ do logInfo "用户登录成功" logWarn "磁盘空间不足" logError "数据库连接失败" -- 读取并打印存储的日志(注意反转列表以恢复顺序) storedLogs <- liftIO $ readIORef logStorage liftIO $ do putStrLn "\n存储的日志内容:" mapM_ (putStrLn . decodeUtf8 . toLazyByteString) (reverse storedLogs)
关键说明
- 避免依赖未导出接口:通过
mkLogFunc创建自定义LogFunc,通过runLogFunc调用原有日志函数,都是RIO官方提供的稳定接口,不会因为内部实现变更而失效。 - 线程安全:使用
atomicModifyIORef'保证多线程场景下日志存储的安全性,避免竞态条件。 - 灵活扩展:如果只需要存储日志不需要转发,直接移除
runLogFunc那一行即可;如果需要修改存储的日志格式,可以在存储前对msg进行处理。
内容的提问来源于stack exchange,提问作者Moritz
相关产品推荐
相关产品推荐

