【发布时间】:2011-03-10 09:23:49
【问题描述】:
我需要将日志记录添加到我的 F# 项目中。 对于我们使用的 C# 代码:Log4net 或 NLog(可能是 .Net 最流行的两个日志框架)。
在 F# 代码中使用的最佳选择是什么? 我的意思是,是否有专门为 F# 代码编写的日志框架?
【问题讨论】:
我需要将日志记录添加到我的 F# 项目中。 对于我们使用的 C# 代码:Log4net 或 NLog(可能是 .Net 最流行的两个日志框架)。
在 F# 代码中使用的最佳选择是什么? 我的意思是,是否有专门为 F# 代码编写的日志框架?
【问题讨论】:
https://github.com/logary/logary
我是 Logary 的作者,它支持 .Net Core 的日志记录、指标和分布式跟踪。
目标包括:TextWriter、Console、LiterateConsole、Debugger、GCP Pub/Sub、GCP BigQuery、GCP Stackdriver、Jaeger、TCP(Shipper)、UDP(Shipper)、ZeroMQ(Shipper)Elasticsearch、Graphite/statsd、elmah.io , Aliyun, Azure ApplicationInsights, Mixpanel (commercial), OpsGenie (commercial), Server-sent-events (web push)。
此外,您可以公开 HTTP 服务器以供 Proemetheus 使用 Logary.Prometheus 进行抓取。
它还有一个Dash service,支持将日志实时推送到您的网络浏览器。
此外,Logary Rutta 是云原生时代的 sidecar 容器实现或独立日志路由器。
Logary JS 是一个用于 JavaScript 的日志记录和指标库,可以发送到服务器端的 Logary Rutta,然后您可以从那里将日志进一步发送到任何可用的目标。
Logary Facade 是一个获得 Apache 2 许可的外观,您可以将其复制并粘贴到所有 C# 和 F# 库中,并获得高质量的控制台日志记录。
Logary 主要是为 F# 用 F# 编写的。
Install-Package Logary
以上所有内容均可免费用于非商业目的。你可以在这里看到不同的licenses。
【讨论】:
我编写了类似这样的代码(使用详细语法):
#light "off"
open System.Runtime.CompilerServices
let inline (|?) (a: 'a option) b = if a.IsSome then a.Value else b; // coalesce operator
type T() = class
static member private printLog(par) =
match ( par) with
| msg, Some m, Some p, Some l -> (
let pl = Array.head (Array.rev( string(p).Split([|'\\';'/'|]))) in
printfn "at %s(%s: line %d) %s" m pl l msg
)
| msg, _,_,_ -> printfn "at ?? %s" msg
static member LOG(msg: string, ?a:obj,
[<CallerMemberName>] ?memberName: string,
[<CallerFilePath>] ?path: string,
[<CallerLineNumber>] ?line: int) = match a with
| Some a -> (match a with
| :? int as i -> T.printLog((sprintf "%s %d" msg i), memberName, path,line)
| :? float as f -> T.printLog((sprintf "%s %f" msg f), memberName, path,line)
| _ -> T.printLog((sprintf "%s %A" msg a), memberName, path,line)
)
| None -> T.printLog(msg, memberName, path,line)
static member EXIT(?msg:string, [<CallerMemberName>] ?memberName: string,
[<CallerFilePath>] ?path: string,
[<CallerLineNumber>] ?line: int) =
printf "Exiting ... ";
T.printLog((msg |? "Giving up!"), memberName, path,line);
exit 1
end
用法:
"text pushed in" |> T.LOG;
T.LOG "just text at line ";
T.LOG ("just text at line in par");
T.LOG ("string ", "text i got");
T.LOG ("int ", 1);
T.LOG ("tuple ", (1,2));
let msg = Some "existing optional value" in
printfn """ (msg |? "this is default value\") ---> %A""" (msg |? "d
T.EXIT( "after all test done no TODO new extentions");
产生:
at testit(TautoLogics.fs: line 49) text pushed in
at testit(TautoLogics.fs: line 52) just text at line
at testit(TautoLogics.fs: line 53) just text at line in par
at testit(TautoLogics.fs: line 54) string "text i got"
at testit(TautoLogics.fs: line 55) int 1
at testit(TautoLogics.fs: line 56) tuple (1, 2)
'(msg |? "this is default value\") ---> "existing optional value"
Exiting ... at testit(TautoLogics.fs: line 63) after all test done
对我来说简单易用。
【讨论】:
据我所知,它们对于 F# 是相同的,即它们没有特定的 F#(无论好坏)。除了配置之外,所有日志库的使用几乎相同。
您可能想要添加的是启用 printf 的日志记录,因此您可以使用 logger.Debugf "Hello %s" "world" 而不是 logger.DebugFormat("Hello {0}", "world") 或 logger.Debug(sprintf "Hello %s" "world")。使用type extensions 和kprintf 来执行此操作。
【讨论】:
kprintf 来制作您建议的一组函数,但我将它们发布到MailboxProcessor,该MailboxProcessor 异步写入我碰巧使用的任何底层日志框架 - 这可能只需为简单的命令行实用程序以不同颜色写入控制台即可。