You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

扩展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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 04:37:10