27

I want to write my own logger.

This is my logger manager:

public static class LoggerManager
{
    public static void Error(string name)
    {

    }
}

I am calling Error(string name); method as below:

public class Foo
{
    public void Test()
    {
        LoggerManager.Error(this.GetType().FullName);
    }
}

In this way, I am geting the caller class name in my method called Error.

But I don't want to pass the name to error method every time. I want to make my logger (Or another logger methods: Info(), Warn()) method get the name by itself.

Thanks for your best practice...

LuizLoyola
  • 386
  • 3
  • 20
  • See the duplicate but instead of calling `.Name` call `.DeclaringType` instead to get the `Type` instance, you can then get the name, full name, assembly info, whatever. – Igor Feb 01 '18 at 19:53
  • I voted reopen the question. The OP wants to get caller class instead of method. – lucky Feb 01 '18 at 19:56
  • But you can easily get the class a method is defined in, can´t you? If we´d reopen this question, one may also ask how to get the namespace or also how to get a class a property is defined in. Only because the question doesn´t fit the exact use-case it can answer the question. – MakePeaceGreatAgain Feb 01 '18 at 20:00
  • @HimBromBeere, I don't agree with you. Of course, we can easily get the class name with referenced question but the question is pretty clear about getting the class name. Referenced answer doesn't fit exact answer anyway. – lucky Feb 01 '18 at 20:14
  • The point is, that if we are looking for duplicates that *exactly* match the context, then we are unlikely to ever find *any* duplicate, as the context may slightly be ifferent from those in the duplicates. – MakePeaceGreatAgain Feb 01 '18 at 20:21
  • Why do you want to reinvent the wheel? There are many loggers that will solve this and lots of other problems you will come across. All of a sudden, you will be asked to write the logs to different files depending on the date, then you will need to write the current thread into each log line, then a different format to a error log and a debug log, and by then, you've probably duplicated nlog or log4net. – Neil Feb 01 '18 at 21:55

2 Answers2

18

You could grab it from StackTrace instance.

public static class LoggerManager
{
    public static void Error()
    {
        var methodInfo = new StackTrace().GetFrame(1).GetMethod();
        var className = methodInfo.ReflectedType.Name;
    }
}
Amintabar
  • 2,198
  • 1
  • 29
  • 29
lucky
  • 12,734
  • 4
  • 24
  • 46
11

You can use CallerMemberName and CallerFilePath attributes

public static void Log(string text, [CallerMemberName] string caller = "", [CallerFilePath] string file = "")
{
   WriteLog(text, caller, file);
}


Log("Something happened");

See also CallerLineNumber


BTW: You may want to compare the speed of costly StackFrame with built-in attributes.

int num = 500000;
var t1 = Measure(() => NameOfCallingClass(), num); //<-- 9000
var t2 = Measure(() => Log("aa"), num); //<--26


long Measure(Action func, int num)
{
    func();
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < num; i++)
    {
        func();
    }
    return sw.ElapsedMilliseconds;
}
Pang
  • 9,564
  • 146
  • 81
  • 122
L.B
  • 114,136
  • 19
  • 178
  • 224
  • 16
    Caller info attributes does not answer the question. He wants the class name, not the member name or the file path of the residing class. Using stackframe voodoo is currently the only known way to do this. Also, using [CallerFilePath] will get the path of the file when it was compiled. All in all, in a production log this will look like garbage. – Oyvind May 09 '19 at 07:15
  • Something like $(SolutionDir)=.\ in csproj fixes that last objection by Oyvind. – Jannes May 26 '20 at 14:10
  • 4
    Or `string callerClassName = Path.GetFileNameWithoutExtension(callerFilePath);` will work for class name, assuming file names correspond to contained class names. – Sepster Apr 28 '21 at 06:03
  • @Sepster that will fix it for output, but the value will still be there and can be retrieved via reflection, or even just by inspecting the strings in the binary. The PathMap element is designed to fix the problem at the project level and doesn't cost memory and CPU cycles at runtime. – dodexahedron Aug 18 '23 at 22:04