haskell - 在 Haskell 中日志记录功能的不同实现之间切换的有效方法?

我的 Haskell web 应用程序以特定的日志记录配置开始。 Web 服务器启动后,日志配置将无法更改。这是日志记录配置控制的内容:

  • 日志输出格式:文本日志(主要用于本地开发)与 JSON 日志(主要用于生产环境)
  • 是否为每个请求/结果计算和发出聚合指标,例如 SQL 语句的数量、发出的下游 HTTP 请求的数量、SQL 花费的时间、API 调用花费的时间等。
  • 日志详细程度:在开发环境中,实际执行的 SQL 语句、对下游系统进行的 API 调用的详细请求/资源日志等都会被记录下来。在生产环境中,这些被跳过。

编写日志函数的简单方法是检查,对于每个日志语句,日志配置以确定 (a) 是否输出日志,(b) 使用哪种格式 -文本 vs json,以及 (c) 是否更新聚合指标

不知何故,这对我来说似乎效率很低。

是否有可能有效执行以下操作:

  • 应用程序启动后,根据日志记录配置,选择几种实现方式之一
  • 以某种方式将此实现注入(inject)到应用程序的 monad(可能是 MonadLogger 的一个实例)中,这样编译器仍然能够执行它本来会执行的任何优化。

最佳答案

当然。比较以下两个函数:

convertData :: Loggable a => Bool -> a -> ByteString
convertData b x = case b of
    False -> viaString x
    True -> viaJSON x

convertCode :: Loggable a => Bool -> a -> ByteString
convertCode b = case b of
    False -> \x -> viaString x
    True -> \x -> viaJSON x

在 GHC 中,如果您编写 convertData False,那么它会在每次调用时检查并重新检查此 Bool;而如果您编写 convertCode False,则会检查一次 Bool(并返回一个已经“内部化”Bool 的函数)。

这也适用于您的其他要求。只需将您的日志记录函数编写为一个函数,该函数采用日志记录配置,立即执行其所有 case 语句和其他检查,然后在每个结果案例中返回一个接受剩余参数的专用日志记录函数。

(为什么命名为 convertDataconvertCode?因为它们是 convert 函数的两个版本;一个将其配置显式存储为关闭-通过数据,而另一个将其配置隐式存储在程序计数器中。)

https://stackoverflow.com/questions/71791219/

相关文章:

python - 将列表附加到现有数据框

android - 我无法将 Android 项目从 Delphi 10.4 迁移到 Delphi

c - 你怎么能告诉计算机它正在添加而没有 addl 在程序集中

authentication - 是 CQRS 中的登录/注册命令或查询

c - 在格式控制字符串中使用消息

node.js - 如何在某个日期之前安装 Node 包及其依赖项?

node.js - Remix.run 不使用 node.js 作为后端吗?

java - 如何使用 Collectors.collectionAndThen 和 Collect

c++ - 临时初始化和引用初始化

c# - 使用 EF Core 按 Id 检索实体的通用方法