Hi!
I've not found any way to do this pattern, since it's the second project where i found it very useful I'll try to explain my needs.
I would like to use one instance of Logger with the name of the class, and I have many instances of this class, this pattern is repeated many times.
I need to add some context information, that is different for each class instance, i see two way to do it
1) Create a Logger with the name of the class + the context differentiator.
2) I would like to create one logger per each class as usually, but on each instance, wrap this logger with some thing that i did not find, where I can inject a parameter to the LogEventInfo at the last possible moment.
Example of code that could be written just to communicate the intent better, any other idea is ofc welcome
```c#
class LoggerWrapper : SomeMagicBaseClass
{
string _contextId;
public LoggerWrapper(Logger logger, string contextId) : base(logger)
{
_contextId = contextId;
}
override void OnBeforeSomething(LogEventInfo eventInfo)
{
eventInfo.Properties.Add("ContextId", _contextId);
}
public static ILogger CreateLogger(string contextId, object currentObject)
{
var className = currentObject.GetType().FullName;
var logger = LogManager.GetLogger(className);
var wrapper = new LoggerWrapper(logger, contextId);
return wrapper;
}
}
```
Hi! Thanks for opening your first issue here! Please make sure to follow the issue template - so we could help you better!
What about an event on the Logger to give this possibility in this point of the process ?
https://github.com/NLog/NLog/blob/eeba89e49de6bdaefe47f8cedeb931fb5fea42cb/src/NLog/Logger.cs#L497
something like this
https://github.com/NLog/NLog/pull/4405
Could your requirement be handled like this:
c#
var globalLogger = LogManager.GetLogger(className);
var loggerWithContext = globalLogger.WithProperty("ContextId", contextId);
See also: https://github.com/NLog/NLog/wiki/Context#logevent-properties
Hi,
thanks @snakefoot it does works, i'm a little bit concerned about the recommendation in the wiki :
_Minimize the number of calls to LogManager.GetLogger() and LogManager.GetCurrentClassLogger() by using static readonly variables_
since the number of log will increase with the data the application have, since the WithProperty method creates a new logger internally.
```c#
public Logger WithProperty(string propertyKey, object propertyValue)
{
if (string.IsNullOrEmpty(propertyKey))
throw new ArgumentException(nameof(propertyKey));
Logger newLogger = Factory.CreateNewLogger(GetType()) ?? new Logger();
newLogger.Initialize(Name, _configuration, Factory);
newLogger._contextProperties = CreateContextPropertiesDictionary(_contextProperties);
newLogger._contextProperties[propertyKey] = propertyValue;
newLogger._contextLogger = _contextLogger; // Use the LoggerConfiguration of the parent Logger
return newLogger;
}
```
EDIT : It also requires this code to run multiple times if we need to add more properties.
The performance issue is mostly for very critical appplicattion where memory-allocation is not allowed. Especially LogManager.GetCurrentClassLogger() is super expensive because it captures callsite-stacktrace to extract logger-name from class-type-name. The LogManager.GetLogger() is not as expensive, but has to acquire a "global"-lock to register the global-logger, which can hurt when having 8 threads (or more) that constantly calls LogManager.GetLogger(). But WithProperty is quite cheap since there is no global-lock or stacktrace-capture (Just allocation of Logger-object and Dictionary-object)
And when you have accepted the performance-overhead with structured-logging (LogEventInfo-Properties-dictionary-allocation for every LogEvent), then calling WithProperty does not introduce any real overhead. Instead of 2 million logevents/sec then you only get 1 million logevents/sec (Very few applications generates more than 50000 logevents/sec)
Thank you for explaining it, it makes sense !
No problem. Happy that Logger.WithProperty was an acceptable solution :)