优雅的关闭 F# 日志记录的方法

4

我在我的F#代码中有很多日志记录,类似于以下内容:

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

这一切都很好,但即使使用NullLogger,在大量sprintf调用的情况下性能仍然较低。日志调用的字符串参数完全形成,然后在Log函数内部结尾处被忽略。

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


1
通常的做法是让 Log 方法本身接受格式字符串和所有参数。 - Fyodor Soikin
这不会减轻对 this.GetSomething 函数的大量调用。 - irriss
1
然后将其包装在lambda中 - Fyodor Soikin
1
不要构建字符串,而是使用结构化日志记录。对于极少数需要调用某些函数而不是记录值的情况,您可以手动检查记录器是否启用所需的日志级别。 - Sergey Berezovskiy
1个回答

4

我认为你可以通过使用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中的消息。


1
警告:ConditionalAttribute 仅适用于具有非柯里化参数且未用作一等函数的成员。但是,您可以考虑在元组样式参数中创建 sprintf 样式重载,其中第一个参数是 sprintf 字符串:如果正确执行,则参数的字符串着色将保持不变。这就是我在自己的日志框架中所做的。另请参阅此讨论和语言建议:https://github.com/fsharp/fslang-suggestions/issues/846。 - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接