Skip to content

Instantly share code, notes, and snippets.

@litetex
Last active September 18, 2024 02:25
Show Gist options
  • Save litetex/b88fe0531e5acea82df1189643fb1f79 to your computer and use it in GitHub Desktop.
Save litetex/b88fe0531e5acea82df1189643fb1f79 to your computer and use it in GitHub Desktop.
Serilog (C#): How to get current MethodName, FileName/Path and LineNumber without reflection

Serilog (C#): How to get the current MethodName, FileName/Path and LineNumber without reflection

This is a simple setup for reflectionless logging with serilog using caller information (and a single static class).

See also https://stackoverflow.com/a/46905798

Log.cs

Create your own Log.cs in your Root-Namespace (you can use the class below).

This class is required to detect where the call is coming from; it uses Caller-Information to speed up the program execution, because the attributes are resolved at compile-time.

You can now also remove all using Serilog;-imports - if you have any - in the classes where you want to log, because the Log.cs is everywhere in the namespace visble and easy accessible.

Serilog-Output Template

Now you can use the added properties (here: MemberName, FilePath, FileName, LineNumber) in your outputTemplate:

⚠️ Note: For more performance you can remove/uncomment unused properties, here e.g. FilePath and LineNumber in SetContext(...)

Final Example

OutputTemplate: {Timestamp:HH:mm:ss,fff} {Level:u3} {FileName} [{MemberName}] {Message:lj}{NewLine}{Exception}

namespace Demo
{
  public class TestClass
  {
    public void TestMethod()
    {
      Log.Info("Some test");
    }
  }
}

Produces the following output: 18:16:40,183 INFO TestClass [TestMethod] Some test

Changelog

  • 2020-03-21: Tuned docs a bit; updated and reformatted the Log.cs class
  • 2020-05-29: Tuned docs a bit; Reformatted the Log.cs; References to CoreFramework.Logging
// MIT License
// Copyright (c) 2020 litetex
// See also https://github.com/litetex/CoreFramework/blob/develop/CoreFramework.Logging/Log.cs
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace CoreFramework
{
public static class Log
{
private static string FormatForException(this string message, Exception ex)
{
return $"{message}: {(ex != null ? ex.ToString() : "")}";
}
private static string FormatForContext(
this string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
var fileName = Path.GetFileNameWithoutExtension(sourceFilePath);
var methodName = memberName;
return $"{fileName} [{methodName}] {message}";
}
public static void Verbose(
string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Verbose(
message
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Verbose(
string message,
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Verbose(
message
.FormatForException(ex)
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Verbose(
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Verbose(
(ex != null ? ex.ToString() : "")
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Debug(
string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Debug(
message
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Debug(
string message,
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Debug(
message
.FormatForException(ex)
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Debug(
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Debug(
(ex != null ? ex.ToString() : "")
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Info(
string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Information(
message
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Info(
string message,
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Information(
message
.FormatForException(ex)
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Info(
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Information(
(ex != null ? ex.ToString() : "")
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Warn(string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Warning(
message
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Warn(
string message,
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Warning(
message
.FormatForException(ex)
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Warn(
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Warning(
(ex != null ? ex.ToString() : "")
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Error(
string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Error(
message
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Error(
string message,
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Error(
message
.FormatForException(ex)
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Error(
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
Serilog.Log.Error(
(ex != null ? ex.ToString() : "")
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Fatal(
string message,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
FatalAction();
Serilog.Log.Error(
message
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Fatal(
string message,
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
FatalAction();
Serilog.Log.Error(
message
.FormatForException(ex)
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
public static void Fatal(
Exception ex,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
FatalAction();
Serilog.Log.Error(
(ex != null ? ex.ToString() : "")
.FormatForContext(memberName, sourceFilePath, sourceLineNumber)
);
}
private static void FatalAction()
{
Environment.ExitCode = -1;
}
}
}
@NeverMorewd
Copy link

How to implement the Constants? Could upload a more complete code please, thank you very much

@marazattila
Copy link

The solution of @morteng85 uses reflection when calling GetMethod() in the GetCallerStackFrame function, so it is not a real solution for the original question!

@NeverMorewd CreateProperty() methods first parameter is the log property name (or key) and the second is the property value. Eg:
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("my_caller_method_name", methodName));

@NeverMorewd
Copy link

NeverMorewd commented Sep 18, 2024

@marazattila Thanks for your reply.
Eventually I found another similar method: https://gist.github.com/nblumhardt/0e1e22f50fe79de60ad257f77653c813.
It used reflection as well, and I can not find any one without reflection.
My app does not seems to support native aot anymore -_-

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment