53

I am trying to find somebody smarter than me to validate some syntax I wrote up. The idea is to configure the filename of my RollingFileAppender to the name of the assembly in order to make it more re-usable for my projects.

I've seen this previous SO article but it wasn't exactly able to answer my question...

I've had a dickens of a time trying to understand the inner components of Log4net and this is what I came up with (residing in the Global.asax file - Application_Start method):

// Bind to the root hierarchy of log4net
log4net.Repository.Hierarchy.Hierarchy root = 
  log4net.LogManager.GetRepository() 
    as log4net.Repository.Hierarchy.Hierarchy;

if (root != null)
{
  // Bind to the RollingFileAppender
  log4net.Appender.RollingFileAppender rfa = 
    (log4net.Appender.RollingFileAppender)root.Root.GetAppender("RollingLogFileAppender");

  if (rfa != null)
  {
    // Set the file name based on the assembly name
    string filePath = 
      string.Format("~/App_Data/{0}.log", GetType().Assembly.GetName().Name);

    // Assign the value to the appender
    rfa.File = Server.MapPath(filePath);

    // Apply changes to the appender
    rfa.ActivateOptions();
  }
}

Can anyone tell me, 'this is hideous', or 'this should work fine'? Also, if I set the file dynamically can I still expect the log4net behavior to rotate the files based on the log4net.config file settings?

Much appreciated!

Community
  • 1
  • 1
Dscoduc
  • 7,714
  • 10
  • 42
  • 48

4 Answers4

126

You are doing this the hard way! Define your log4net config as XML in your application's configuration file and use %property{} to advantage:

<appender name="YourAppender" type="log4net.Appender.RollingFileAppender">
  <file type="log4net.Util.PatternString" value="~/App_Data/%property{LogName}" />
  ....
</appender>

This is dynamic -- you just have to set the log4net property "LogName" before you initialize log4net. Thus, in your code any time before you configure log4net, set the desired value of this property:

string LogName = GetType().Assembly.GetName().Name + ".log";
log4net.GlobalContext.Properties["LogName"] = LogName;

Of course, you may use any property name. I've chosen "LogName" for a simple example, but you can have one per application if you want, as long as your code knows what the correct property name is and what the correct value should be.

Eddie
  • 53,828
  • 22
  • 125
  • 145
  • 2
    Ah, exactly why I posted this... It seemed more difficult than it should have been. Thank you... – Dscoduc Feb 21 '09 at 03:18
  • 2
    Do you know if there is an equivalent method or way to do this when using the log4netfactoryadapter? I am using common.logging in all my code and declaratively defining the configuration (app.config). I have tried the GlobalContext method but end up with (null) in my file name, and I know the variable I'm using is not null. – Kyle LeNeau Jan 22 '10 at 16:07
  • 1
    Unfortunately, I'm not familiar with the log4netfactoryadapter. Are you sure you're using GlobalContext ** before ** log4net is initialized or used? If log4net gets used or initialized before you define your properties, they'll be null. – Eddie Jan 23 '10 at 05:14
  • Do we have to set this in code using GlobalContext.Properties or is there a way to set the LogName property in a config file? – Jay Sullivan Oct 22 '13 at 15:49
  • You could, of course, have your code read that other config file and use it to set the desired value in GlobalContext.Properties. But this has to be done before logging is initialized. – Eddie Oct 23 '13 at 23:21
  • 23
    Worth mentioning, that type="log4net.Util.PatternString" line is important. I spent two hours searching why do I get "%property{FileName}" file in Debug folder instead of "events.txt" in Log folder. – Aleksey Dec 23 '14 at 16:22
  • 1
    What about multithreaded situation? It seems to be a static setting. In my app there are many classes trying to log things simultaneously to different files, which names I want to set dynamically. Do I have to synchronize the writes and change the "LogName" equivalent property for each thread? – user1713059 Jun 24 '15 at 16:33
  • 1
    The statements are contradictory: "This is dynamic" "you just have to set the log4net property LogName before you initialize log4net." If it was dynamic, you could change it. You imply that you can't, and the order is important. That's the opposite of dynamic. – theta-fish Dec 02 '15 at 14:39
  • 1
    @SebastianHäni's solution below looks much easier if you just want the assembly name. But this solution is great if you want something else. @shahzbot If you want the value to be dynamic depending on app state then set the property to an object whose `ToString()` method returns the dynamic value you want. – Rory Feb 27 '16 at 16:28
  • 1
    e.g. this provides the current user's name, or anonymous, based on httpcontext: `GlobalContext.Properties["User.Identity.Name"] = new DeferredUsernameProvider(); public class DeferredUsernameProvider { public override ToString() { if (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity.Name != null) { return HttpContext.Current.User.Identity.Name; } return "anonymous"; } }` – Rory Feb 27 '16 at 16:29
  • 6
    For me this did only work with reloading configuration by calling `log4net.Config.XmlConfigurator.ConfigureAndWatch("log4net.config.xml")` – Tobias May 06 '16 at 08:38
  • Same point as @Tobias I followed this tutorial: https://stackify.com/log4net-guide-dotnet-logging/ Which configures a log4net.config file in AssemblyInfo with the following line: `[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")]` I saw this page before I saw had already posted this http://geekswithblogs.net/Lance/archive/2010/08/13/dynamic-configuration-of-log4net.aspx – k3yz101 Oct 21 '17 at 19:19
13

Here is way to set or change the logfile of the first appender at runtime:

var appender = (log4net.Appender.FileAppender)LogManager.GetRepository().GetAppenders()[0];
appender.File = "C:\whatever.log";
appender.ActivateOptions();
10

In 2015, we do it like this:

<file type="log4net.Util.PatternString">
  <conversionPattern value="%appdomain.log" />
</file>

No other code required.

App domain is the executing assembly's file name.

Sebastian Häni
  • 566
  • 4
  • 17
4

it worked for me with the date <file type="log4net.Util.PatternString" value="./Log/logQueueService%date{yyyy_MM_dd}.log" />

  • 3
    Try to explain more clearly why this is an answer to the question. – Jeroen Heier Dec 27 '18 at 16:42
  • it will create dynamic file name. e.g ./Log/logQueueService%date{yyyy_MM_dd}.log" . -> root path log -> folder logQueueService -> fix file name %date{yyyy_MM_dd} -> dynamic date. – M Danish Sep 21 '21 at 05:56