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

标签 sql haskell logging persistent monad-transformers

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 调用没有抑制输出呢?

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

最佳答案

持久化的架构有点迂回且记录不足:

  • withSqlPool需要一个建筑商。 builder 能够 build 一个 SqlBackend超出任何“日志记录功能”(基本上是 MonadLogger 使用的内部类型)。然后该函数创建一个 SqlBackend资源池 s,供您获取、释放和使用。这是延续参数 Pool SqlBackend -> m a作为返回,withSqlPool promise 会给你带来一堆副作用,输入为 (MonadIO m, MonadBaseControl IO m, MonadLogger m) => m a .

  • runSqlPool另一方面,需要 MonadBaseControl IO m => ReaderT SqlBackend m a和一个 Pool SqlBackend并返回m a 。由此我们可以推断,它基本上获得了SqlBackend。从资源池中获取,使用它构建并运行 SQL 查询,然后返回 MonadBaseControl IO => m a 。事实上,它的文档是“从池中获取连接,运行给定的操作,然后将连接返回到池中。”

虽然名称相似,但它们做两件截然不同的事情。第一个函数构造资源池,第二个函数使用它。大多数持久 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 ())

当第三个约束消失后,我们就能够统一 IO ()(MonadIO m, MonadBaseControl IO m) => m ()通过实现m ~ IO .

现在,在这个阶段,我们可以插入 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只是继承 MonadLogger 的日志记录行为由 withSqlPool 生成的约束。仅在 withSqlPool我们能够插入所需的 filterLogger 的级别打电话。

关于sql - filterLogging 不适用于 Database.Persist.Sql 的 runSqlPool 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36768459/

相关文章:

SQL with 子句动态 where 参数

python - 如何使用 truncate 在 mysqldb 中执行事务

php - 如何列出从 sql 到 html 表的结果

haskell - 通过: Cannot derive well-kinded instance推导

使用 Haskell 查找 LCS 的性能问题

java - Log4J RollingFileAppender 不强制执行最大日志大小

spring-mvc - 使用 @Async 和 TaskDecorator 记录 MDC

SQL合并2个表

haskell FFI : Top-level FunPtr to a top-level function?

java - Logback %replace 它是否为每个日志语句编译正则表达式?