Can you configure log4net in code instead of using a config file?

96,307

Solution 1

FINAL SOLUTION:1

For anyone who may stumble upon this in the future, here is what I did. I made the static class below:

using log4net;
using log4net.Repository.Hierarchy;
using log4net.Core;
using log4net.Appender;
using log4net.Layout;

namespace Spectrum.Logging
{
    public class Logger
    {
        public static void Setup()
        {
            Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline";
            patternLayout.ActivateOptions();

            RollingFileAppender roller = new RollingFileAppender();
            roller.AppendToFile = false;
            roller.File = @"Logs\EventLog.txt";
            roller.Layout = patternLayout;
            roller.MaxSizeRollBackups = 5;
            roller.MaximumFileSize = "1GB";
            roller.RollingStyle = RollingFileAppender.RollingMode.Size;
            roller.StaticLogFileName = true;            
            roller.ActivateOptions();
            hierarchy.Root.AddAppender(roller);

            MemoryAppender memory = new MemoryAppender();
            memory.ActivateOptions();
            hierarchy.Root.AddAppender(memory);

            hierarchy.Root.Level = Level.Info;
            hierarchy.Configured = true;
        }
    }
}

And then all I had to do was replace the code where I called the XML file with the following call:

//XmlConfigurator.Configure(new FileInfo("app.config")); // Not needed anymore
Logger.Setup();

1(this answer was edited into the question by the OP, I took the liberty to make it a community answer, see here why)

Solution 2

You can also escape XML completely, I wrote a sample with minimal programmatic configuration here.

In a nutshell, here is what you need

var tracer = new TraceAppender();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(tracer);
var patternLayout = new PatternLayout {ConversionPattern = "%m%n"};
patternLayout.ActivateOptions();
tracer.Layout = patternLayout;
hierarchy.Configured = true;

Solution 3

Yes, you can configure log4net by calling:

log4net.Config.XmlConfigurator.Configure(XmlElement element)

See the log4net documentation.

Solution 4

Alternatively you could create a custom attribute that inherits from log4net.Config.ConfiguratorAttribute and hard-code you configuration there:

using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using log4net.Repository;
using log4net.Repository.Hierarchy;
using System;
using System.Reflection;

namespace ConsoleApplication1
{
    [AttributeUsage(AttributeTargets.Assembly)]
    public class MyConfiguratorAttribute : ConfiguratorAttribute
    {
        public MyConfiguratorAttribute()
            : base(0)
        {
        }

        public override void Configure(Assembly sourceAssembly, ILoggerRepository targetRepository)
        {
            var hierarchy = (Hierarchy)targetRepository;
            var patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline";
            patternLayout.ActivateOptions();

            var roller = new RollingFileAppender();
            roller.AppendToFile = false;
            roller.File = @"Logs\EventLog.txt";
            roller.Layout = patternLayout;
            roller.MaxSizeRollBackups = 5;
            roller.MaximumFileSize = "1GB";
            roller.RollingStyle = RollingFileAppender.RollingMode.Size;
            roller.StaticLogFileName = true;
            roller.ActivateOptions();
            hierarchy.Root.AddAppender(roller);

            hierarchy.Root.Level = Level.Info;
            hierarchy.Configured = true;
        }
    }
}

Then add the following to a .cs file:

[assembly: ConsoleApplication1.MyConfigurator]

Solution 5

For those who don't want to add appender to Root logger, but to current/other logger:

//somewhere you've made a logger
var logger = LogManager.GetLogger("MyLogger");

// now add appender to it
var appender = BuildMyAppender();
((log4net.Repository.Hierarchy.Logger)logger).AddAppender(appender);

logger.Debug("MyLogger with MyAppender must work now");

// and remove it later if this code executed multiple times (loggers are cached, so you'll get logger with your appender attached next time "MyLogger")
((log4net.Repository.Hierarchy.Logger)logger).RemoveAppender(sbAppender);
Share:
96,307
Michael Mankus
Author by

Michael Mankus

I've been programming since I was 16 years old. The majority of my experience is in writing non-commercial software for both the private and government sectors. My specialty is writing testbed applications and data collection / playback applications. Familiar languages include C#, C++, C, and Java.

Updated on July 08, 2022

Comments

  • Michael Mankus
    Michael Mankus almost 2 years

    I understand why log4net uses app.config files for setting up logging - so you can easily change how information is logged without needing to recompile your code. But in my case I do not want to pack a app.config file with my executable. And I have no desire to modify my logging setup.

    Is there a way for me to set up logging in code rather than using the app.config?

    Here is my simple config file:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
      </configSections>
      <log4net>
        <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
          <file value="Logs\EventLog.txt" />
          <appendToFile value="false" />
          <rollingStyle value="Size" />
          <maxSizeRollBackups value="5" />
          <maximumFileSize value="1GB" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
          </layout>
        </appender>
        <appender name="MemoryAppender" type="log4net.Appender.MemoryAppender">
        </appender>
        <root>
          <level value="Info" />
          <appender-ref ref="RollingLogFileAppender" />
          <appender-ref ref="MemoryAppender" />
        </root>
      </log4net>
    </configuration>
    

    EDIT:

    To be completely clear: It is my goal to have no XML file. Not even as an embedded resource that I turn into a stream. My goal was to define the logger completely programmatically. Just curious if it's possible and if so where I might find an example of the syntax.

  • user20358
    user20358 over 9 years
    what is the Hierarchy class for?
  • Eric Scherrer
    Eric Scherrer over 8 years
    Just a note if you use variables in your roller.File string you can use the log4net.Util.PatternString class to format it before assigning the result to foller.File.
  • Philip Bergström
    Philip Bergström almost 8 years
    I ended up getting duplicate log entries using this method. I solved it by adding "hierarchy.Root.RemoveAllAppenders();" to the beginning of the Setup().
  • Mickey Perlstein
    Mickey Perlstein over 7 years
    From all this, how do i get the ILog ?
  • Chris Berry
    Chris Berry over 7 years
    @MickeyPerlstein private static readonly ILog Log = LogManager.GetLogger(typeof(YourType));
  • Pritam
    Pritam over 7 years
    How to read the same log file? When i tried to read, it gave the error of The process cannot access the file because it is being used by another process.
  • Eivind Gussiås Løkseth
    Eivind Gussiås Løkseth about 7 years
    Doesn't work for me unless I call BasicConfigurator.Configure(hierarchy); instead of just setting hierarchy.Configured = true;.
  • Søren Boisen
    Søren Boisen about 6 years
    @PhilipBergström you're my hero! Finally no more duplicated log output, phew!
  • codah
    codah almost 6 years
    Trying to use this for Godot engine logging but I'm getting nothing in the logfile. The logfile does get created though. I'm using @EivindGussiåsLøkseth idea but still didn't work..
  • Manfred
    Manfred almost 6 years
    Make sure the process that you expect to write to the log file has write permissions in the folder to which you want the log file to be written. To diagnose log4net problems add log4net.Util.LogLog.InternalDebugging = true; before any other log4net call, then run under debugger and inspect the output. log4net will tell you where things go wrong.
  • Toby Smith
    Toby Smith over 5 years
    Link is now dead
  • Joe
    Joe over 5 years
    @TobySmith - fixed.
  • Raj Kamal
    Raj Kamal almost 5 years
    @codah were you able to solve your problem? I am facing the exact same issue
  • codah
    codah almost 5 years
    @RajKamal sorry can't remember, haven't used Godot for a long time
  • Raj Kamal
    Raj Kamal almost 5 years
    @codah no need. In my case, I needed to create and add [assembly: Repository(<repo name>)] to ensure that log4net uses my configuration. instead of default config
  • Andrew Keeton
    Andrew Keeton about 4 years