【问题标题】:Elegant way to switch off logging F#关闭日志记录 F# 的优雅方式
【发布时间】:2021-01-07 05:18:46
【问题描述】:

在我的 F# 代码中,我有很多日志记录。像这样的

logger.Log (sprintf "%A" (this.GetSomething parameters))

这一切都很好,但由于大量的 sprintf 调用,即使使用 NullLogger 性能也很低。日志调用的字符串参数完全形成,然后在日志函数的末尾被忽略

有没有完全关闭日志记录的好方法?当然我可以做预处理指令(F# 中有这样的东西吗?)或者以某种方式使用“if flag then ....”,但我想知道是否有一个 F# 魔法可以很好地为我做这件事?

【问题讨论】:

  • 通常的做法是让Log方法本身接受格式字符串和所有参数。
  • this.GetSomething 函数的大量调用无济于事
  • 然后将其包裹在一个 lambda 中
  • 只需使用结构化日志记录而不是构建字符串。在极少数情况下,当您调用某些函数而不是记录值时,您可以手动检查是否为所需的日志级别启用了记录器。

标签: logging functional-programming f#


【解决方案1】:

我认为你可以通过使用Conditional("SYMBOL") 属性来做到这一点。 Log 方法可能已经也可能没有这个(因为这是一个标准的 .NET 属性)。如果在方法上应用Conditional 属性,编译器将仅在指定属性时编译调用 - 因此您可以使用Conditional("DEBUG") 完全删除调用,除非您使用--define:DEBUG 进行编译。最重要的是,这也删除了计算参数的所有代码。例如:

type Logger() = 
  [<System.Diagnostics.Conditional("DEBUG")>]
  member x.Log(s:string) = printfn "%s" s

let slowprintf f =
  Printf.kprintf (fun k -> printfn "SLOWPRINTF!"; k) f

let l = Logger()
l.Log(slowprintf "Yo %d" (System.Random().Next()))

如果你用--define:DEBUG 编译它,它会打印SLOWPRINTF!(格式化时),然后是带有一些随机数的Yo xyz(记录时)。但是如果没有--define:DEBUG,它不会打印任何东西——甚至不会打印来自slowprintf 的消息。

【讨论】:

  • 一句警告:ConditionalAttribute 仅适用于具有非柯里化参数且不用作一等函数的成员。但是,您可以考虑在第一个参数是 sprintf-string 的元组样式参数中进行 sprintf-style 重载:如果操作正确,参数的字符串内着色将保留。这就是我在自己的日志框架中的做法。另请参阅此讨论和语言建议:github.com/fsharp/fslang-suggestions/issues/846
猜你喜欢
  • 2011-07-13
  • 2010-12-08
  • 1970-01-01
  • 2012-05-22
  • 2012-10-23
  • 1970-01-01
  • 2014-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多