通过haskell元编程提取用于跟踪/记录的上下文

cvo*_*ogt 6 logging trace haskell metaprogramming template-haskell

在我们的 haskell 代码库中,业务逻辑与跟踪和日志代码交织在一起。这会模糊业务逻辑,使其更难理解和调试。我正在寻找如何减少日志记录和跟踪的代码占用空间以使业务逻辑更加突出的想法。

我们的代码目前大致如下所示:

someFunction a b cs = 
  withTaggedSpan tracer "TRACE_someFunction" [("arg_b", show b)] $ do
    logDebug logger $ "someFunction start: " <> show (trimDownC <$> cs)
    result <- do ... some business logic ...
    if isError result then
      logError logger $ "someFunction error: " <> show result
    else
      logDebug logger $ "someFunction success: " <> show (trimDownResult result)
Run Code Online (Sandbox Code Playgroud)

一个观察结果是 whe 主要跟踪整个函数体并在开始和结束时记录。这应该允许将跟踪和日志记录合并到单个帮助程序中,并通过元编程自动提取函数名称和捕获值的名称。我之前在其他语言中使用过 AST 转换编译时宏和运行时内省,但没有在 Haskell 中使用过。

使用 Template Haskell、HasCallStack 或其他选项执行此操作的好方法是什么?

(交叉发布在https://www.reddit.com/r/haskell/comments/gdfu52/extracting_context_for_tracinglogging_via_haskell/

Mar*_*ann -2

纯函数是确定性的。如果您知道其中的内容,则始终可以重现结果。因此,您不需要在功能代码库的主要部分内进行大量日志记录。

仅记录不纯的操作,并将您的代码构建为具有小型命令式 shell 的纯核心。仅记录 shell 中发生的不纯操作。我已在此处的博客文章中描述了该技术。

  • 出于对 FP 的喜爱,我们在与其他服务、我们的开发资源和历史架构决策的交互中尽可能地分离纯代码和非纯代码。对系统进行彻底的重新架构可以实现的是一个值得思考的实验,但并不是很快就能实现的现实。我们正在寻求对我们的情况进行小幅渐进式改善。此外,我们还有内部和外部 SLA,要求系统随时记录其正在执行的操作。 (2认同)
  • 也就是说,如您的文章中所述,使用免费 monad 通过从外部进行日志记录和跟踪来增强执行确实是一个很棒的实验!我可以帮助减少业务逻辑中的跟踪/记录足迹。元编程可能仍然有助于使该方法更加 DRY。 (2认同)