filterLogging 不适用于 Database.Persist.Sql 的 runSqlPool 函数

filterLogging not working on Database.Persist.Sql's runSqlPool function

Haskell 库 Database.Persist.Sqlite 包含 运行 LoggingT 上下文中的函数,用于控制调试输出。所以我希望能够限制它们产生的调试输出,因此:

runStdoutLoggingT . filterLogger (\_ _ -> False) (runSqlPool (insertBy myData) myPool)

(根据我的实际代码进行了压缩和简化)但是,它不会抑制日志记录。 insertBy 的计算在 stdout 上产生一行

[Debug#SQL] SELECT "id","key","data_source_row_id","loaded" FROM "data_row" WHERE "key"=? AND "data_source_row_id"=?; [PersistText blahblahblah]

那么为什么 filterLogger 调用没有抑制输出?

由于该问题收到了两个反对票,我将补充一点,上面显示的模式(即 运行StdoutLoggingT .filterLogger)在许多 GitHub 项目中使用,但我看不到我的申请有何不同。在没有解释或追索手段的情况下被否决有点令人沮丧。

Persistent 的架构有点迂回且文档不足:

  • withSqlPool 需要一个建造者。构建器能够从任何 "logging function"(基本上是 MonadLogger 使用的内部类型)中构建一个 SqlBackend。该函数然后创建一个资源池 SqlBackends,供您获取和释放和使用。这是你传入的延续参数 Pool SqlBackend -> m a。在 return 中,withSqlPool 承诺会给你带来一堆副作用,输入为 (MonadIO m, MonadBaseControl IO m, MonadLogger m) => m a.

  • 另一方面,
  • runSqlPool 需要 MonadBaseControl IO m => ReaderT SqlBackend m aPool SqlBackend 以及 return 和 m a。从这里我们可以推断,它基本上是从资源池中获取一个SqlBackend,用它来构造和运行一个SQL查询,然后returns MonadBaseControl IO => m a.实际上,它的文档是 "Get a connection from the pool, run the given action, and then return the connection to the pool."

尽管名称相似,但它们做的是两件截然不同的事情。第一个函数构造资源池,第二个函数使用它。大多数持久性 SQL 代码将具有以下形状:

withSqlPool (\logFunc -> do
                conn <- makeConnection connectionString
                return SqlBackend { ... , connLogFunc = logFunc })
            numberOfOpenConnections
            (\pool -> do
              runSqlPool (insertBy myData) pool
              runSqlPool (anotherTransaction moreData) pool)

事实上,如果你使用persistent-postgresql,上面只是

的扩展形式
withPostgresqlPool connectionString
                   numberOfOpenConnections
                   (\pool -> do
                     runSqlPool (insertBy myData) pool
                     runSqlPool (anotherTransaction moreData) pool)

但是等等!我们还不能完全将其作为 IO 操作来执行。 MonadIO m, MonadBaseControl IO m, MonadLogger m 是我们的限制条件,这是我们必须解除的第三个限制条件:

main :: IO ()
main =
  runStdoutLoggingT $
    withPostgresqlPool connectionString
                       numberOfOpenConnections
                       (\pool -> do
                         runSqlPool (insertBy myData) pool
                         runSqlPool (anotherTransaction moreData) pool
                         return ())

当第三个约束消失时,我们可以通过实现 m ~ IO.

来统一 IO ()(MonadIO m, MonadBaseControl IO m) => m ()

现在,在这个阶段,我们可以插入我们的 filterLogger – 就在 runStdoutLoggingT:

解除约束之前
main :: IO ()
main =
  runStdoutLoggingT . filterLogger (\_ _ -> False) $
    withPostgresqlPool connectionString
                       numberOfOpenConnections
                       (\pool -> do
                         runSqlPool (insertBy myData) pool
                         runSqlPool (anotherTransaction moreData) pool
                         return ())

总的来说,糟糕的命名和令人印象深刻的 Database.Persist.Sql 模块造成了混乱。

让我们强调一点:runSqlPool 只是继承了 withSqlPool 生成的 MonadLogger 约束的日志记录行为。只有在 withSqlPool 级别,我们才能插入所需的 filterLogger 调用。