开发者

What logging framework is better to use in F# code [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.

We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.

开发者_JAVA百科

Closed 2 years ago.

Improve this question

I need to add logging to my F# project. For C# code we used: Log4net or NLog (possible two of the most popular logging frameworks for .Net).

What is the best choice to use in F# code? I mean, is there any specific logging framework written for usage in F# code?


The Logary library

https://github.com/logary/logary

I'm the author of Logary, which supports logging, metrics and distributed tracing for .Net Core.

Targets include: 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).

Further, you can expose a HTTP server for Proemetheus to scrape with Logary.Prometheus.

It also has a Dash service that supports real-time push of logs to your web browser.

Further, Logary Rutta is a sidecar container implementation or stand-alone log router for the cloud-native era.

Logary JS is a logging and metrics library for JavaScript that can ship into Logary Rutta on the server side, from where you can then furthr the logs to any of the available targets.

Logary Facade is an Apache 2-licensed facade you can copy-n-paste into all your C# and F# libraries and get high-quality console logging with.

Logary is written in F# for F# primarily.

Install-Package Logary

docs here

All of the above is free to use for non-commercial purposes. You can see the different licenses here.


As far as I know, they're the same for F#, i.e. there's nothing F# specific about them (whether good or bad). Aside from configuration, usage is pretty much the same for all logging libraries.

What you might want to add is printf-enabled logging, so instead of logger.DebugFormat("Hello {0}", "world") or logger.Debug(sprintf "Hello %s" "world") you can just do logger.Debugf "Hello %s" "world". Use type extensions and kprintf to do this.


I did code something like this (using verbosal syntax):

#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

usage:

"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");

produces:

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

just simple and eazy to use for me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜