如何将 Serilog.Log.ForContext 与 F# 函数或 C# 方法一起使用

Cod*_*gar 4 c# f# serilog

使用Serilog和F#如何使用.ForContextwith函数?看来它只接受类型类:

\n
type A()=\n  log = Serilog.Log.ForContext<A>() // \xe2\x9c\x85\n
Run Code Online (Sandbox Code Playgroud)\n
let f _ =\n  log = Serilog.Log.ForContext<f>() // compile error\n  log = Serilog.Log.ForContext(f.GetType()) // the information is not the same as A where it gives module + type path\n
Run Code Online (Sandbox Code Playgroud)\n

添加 F# 函数或 C# 方法的上下文的正确方法是什么(我认为应该是同一个问题)?

\n
\n

到目前为止,我的解决方案一直使用这个函数,它返回 SourceContext 与使用类 ( moduleFullName+className) 完全相同:

\n
let logFromFn _ =\n  Serilog.Log.ForContext\n    ("SourceContext",\n     StackTrace().GetFrame(1).GetMethod().DeclaringType\n     |> fun dt -> dt.FullName + "+" + dt.Name)\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 正如这个答案中所述,它可能很昂贵,我在整个程序中调用一次的地方使用它。
  2. \n
  3. 它在模块内的 F# 函数中运行良好,但在返回的入口点文件中则不太好program+program
  4. \n
\n

rob*_*ker 5

方法没有Type与之关联,因此您不能使用ForContext<T>()ForContext(Type type)重载。由于 F# 模块中的函数被编译为静态类(模块)内的静态方法,因此这同样适用于它们。作为一个简单的替代方案,您可以SourceContext自己设置该属性:

let propName = Serilog.Core.Constants.SourceContextPropertyName
Log.ForContext(propName, "App.Class.Method")
Log.ForContext(propName, "App.Module.function")
Run Code Online (Sandbox Code Playgroud)

如果您希望重命名操作更加稳健,您可以执行以下操作:

class Class
{
    public void Method()
    {
        var source = $"{typeof(Class).FullName}.{nameof(Method)}";
        var logger = Log.ForContext(Core.Constants.SourceContextPropertyName, source);
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)
module Module =
    // It's a bit fiddly to get the module type in F#, but here's one
    // approach (credit https://stackoverflow.com/a/14706890/7694577).
    type private Marker = interface end
    let private moduleType = typeof<Marker>.DeclaringType

    let loggerFor name =
        let source = sprintf "%s.%s" moduleType.FullName name
        let propName = Serilog.Core.Constants.SourceContextPropertyName
        Log.ForContext(propName, source)
    

    // Requires the `nameof` operator from F# 4.7 preview.
    // The function needs to be recursive since it is referenced when calling `nameof`.
    let rec func () =
        let logger = loggerFor (nameof func)
        // ...
Run Code Online (Sandbox Code Playgroud)

我要补充的是,通常类/模块名称足以确定消息的来源,因此我建议从源上下文中删除方法/函数名称。这将允许您使用ForContext<T>()ForContext(Type type)重载,因此会大大简化事情。