Skip to content

Instantly share code, notes, and snippets.

@TheAngryByrd
Last active February 18, 2025 14:15
Show Gist options
  • Save TheAngryByrd/bcd07468ba191c8e7e6cc4b614cef7d3 to your computer and use it in GitHub Desktop.
Save TheAngryByrd/bcd07468ba191c8e7e6cc4b614cef7d3 to your computer and use it in GitHub Desktop.
F# Collecting logging metadata like namespace, function name, filepath, and line number
open System.Runtime.CompilerServices
type Log() =
static member inline GatherLogMeta
(
?name_space: string,
[<CallerMemberName>] ?cmb: string,
[<CallerLineNumber>] ?cln: int,
[<CallerFilePath>] ?cfp: string
) =
let name_space =
match name_space with
| Some ns -> ns
| _ ->
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName.Split('+')
|> String.concat "."
let cmb = defaultArg cmb ""
let cln = defaultArg cln 0
let cfp = defaultArg cfp ""
printfn $"{name_space}.{cmb} was called {cfp}:{cln}" // Filepath:LineNumber is a format many tools know how to use for navigation to the source code
module Log =
open Microsoft.FSharp.Quotations.Patterns
let rec getModuleNamespace =
function
| PropertyGet(_, propertyInfo, _) -> propertyInfo.DeclaringType.FullName.Split('+') |> String.concat "."
| x -> failwithf "Expression is not a property. %A" x
module MyTestModule1 =
let functionInlineReflection () = Log.GatherLogMeta()
let rec moduleLocation = lazy Log.getModuleNamespace <@ moduleLocation @>
let functionRecMarker () = Log.GatherLogMeta(name_space = moduleLocation.Value)
type internal Marker = interface end
let moduleLocation2 = lazy(typeof<Marker>.DeclaringType.FullName.Split('+') |> String.concat ".")
let functionWithTypeOfMarker () = Log.GatherLogMeta(name_space = moduleLocation2.Value)
do MyTestModule1.functionInlineReflection ()
do MyTestModule1.functionRecMarker ()
do MyTestModule1.functionWithTypeOfMarker ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment