1

I have a program that has a different set of modules called based an input parameter. Modules like Orders, Shipments, Pricing etc. I wrote a logging class with log4net being the foundation though there is a need for some custom logging as well. What I want is to have each module have its own logging file and to that point, I was able to get log4net to dynamically create the appenders for each file.

I was also able to get a console display for the times when it may be run manually, but what I lost (and cannot figure how to get it to work is the Colored Console appender. I found the basic solution here for creating appenders and I then used this link to figure out how to create console and ManagedColoredConsole appenders, but while it still writes to the console, I do not get color.

There is something missing, but I I don't know what. I wrote a small testing program to try and figure this out and this is the logging class:

using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using System;
using System.Linq;

namespace TestLogging
{
    public class Logging
    {

        // Since the current version of logging will require more custom fields passed into the logging table
        // I'm going to set up a wrapper around the log for net processing. This should simplify the way we call it in 
        // the main program sections so we don't have to keep adding constants like pid and we can deal with variables 
        // like item, order number, shipping numbers

        public static ILog log = null;

        public string transType = "";
        public string pid = "0";
        private string logModule = "main";
        private string path = "";

        public Logging(string LogModule)
        {
            logModule = LogModule;    // set up to default to main then pass in the specific log file name for log4net

            SetLevel("Log4net.MainForm", "ALL");
            path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            string execPath = AppDomain.CurrentDomain.BaseDirectory;

            if (log.Logger.Repository.GetAppenders().Count() == 0)
            {
                //CreateConsoleAppender();
                CreateManagedColorConsoleAppender();
            }

            AddAppender(LogModule, CreateFileAppender(logModule, execPath + "\\logs\\" + logModule + ".log"));

        }
        public void Info(string message, string sohnum = null, string itmref = null, string sdhnum = null, double processtime = 0.0)
        {
            setCustom(sohnum, itmref, sdhnum, processtime);
            log.Info(message);
        }
        private void setCustom(string sohnum = null, string itmref = null, string sdhnum = null, double processtime = 0.0)
        {
            log4net.ThreadContext.Properties["TransType"] = transType;

            log4net.ThreadContext.Properties["sohnum_0"] = sohnum;
            log4net.ThreadContext.Properties["itmref_0"] = itmref;
            log4net.ThreadContext.Properties["sdhnum_0"] = sdhnum;
            log4net.ThreadContext.Properties["processtime"] = processtime.ToString();
            log4net.ThreadContext.Properties["pid"] = pid;

        }
        // Set the level for a named logger
        public static void SetLevel(string loggerName, string levelName)
        {
            log = LogManager.GetLogger(loggerName);
            Logger l = (Logger)log.Logger;

            l.Level = l.Hierarchy.LevelMap[levelName];
        }

        // Add an appender to a logger
        public static void AddAppender(string loggerName, IAppender appender)
        {
            log = LogManager.GetLogger(loggerName);
            Logger l = (Logger)log.Logger;

            l.Repository.Configured = true;
            l.AddAppender(appender);
        }

        // Create a new file appender
        public static IAppender CreateFileAppender(string name, string fileName)
        {
            FileAppender appender = new
                FileAppender();
            appender.Name = name;
            appender.File = fileName;
            appender.AppendToFile = true;

            PatternLayout layout = new PatternLayout();
            layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
            layout.ActivateOptions();

            appender.Layout = layout;
            appender.ActivateOptions();

            return appender;
        }
        public static IAppender CreateConsoleAppender()
        {
            ConsoleAppender appender = new ConsoleAppender();
            appender.Name = "console";

            PatternLayout layout = new PatternLayout();
            layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
            layout.ActivateOptions();

            appender.Layout = layout;
            appender.ActivateOptions();

            var hierarchy = (Hierarchy)LogManager.GetRepository();

            hierarchy.Configured = true;

            hierarchy.Root.AddAppender(appender);


            return appender;
        }
        public static IAppender CreateManagedColorConsoleAppender()
        {

            ManagedColoredConsoleAppender appender = new ManagedColoredConsoleAppender();
            ManagedColoredConsoleAppender.LevelColors mapping = new ManagedColoredConsoleAppender.LevelColors();

            appender.Name = "ManagedColoredConsoleAppender";
            mapping.Level = log4net.Core.Level.Debug;
            mapping.ForeColor = ConsoleColor.Blue;
            appender.AddMapping(mapping);
            mapping.Level = log4net.Core.Level.Info;
            mapping.ForeColor = ConsoleColor.Green;
            appender.AddMapping(mapping);
            mapping.Level = log4net.Core.Level.Error;
            mapping.ForeColor = ConsoleColor.Yellow;
            appender.AddMapping(mapping);
            mapping.Level = log4net.Core.Level.Fatal;
            mapping.ForeColor = ConsoleColor.Red;
            appender.AddMapping(mapping);

            PatternLayout layout = new PatternLayout();
            layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
            layout.ActivateOptions();

            appender.Layout = layout;
            appender.ActivateOptions();


            var hierarchy = (Hierarchy)LogManager.GetRepository();

            hierarchy.Root.AddAppender(appender);
            hierarchy.Configured = true;
            hierarchy.Root.Level = log4net.Core.Level.Info;
            
            return appender;

        }
    }
}

It is rough, but this is just for testing and learning.

This is the main program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestLogging
{
    public class Program
    {
        //private Logging logging = new Logging("file");
        private static Logging logit = new Logging("main");

        static void Main(string[] args)
        {

            logit.Info("This is the main program");

            ordersClass orders = new ordersClass();
            orders.callMe();
            shipments shipit = new shipments();
            shipit.shipMe();

        }
    }
}

and one of the classes that writes to a different log file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestLogging
{
    public class ordersClass
    {
        private Logging logit = new Logging("orders");
        public void callMe()
        {
            logit.Info("Just placed an order");
        }
    }
}

When I set a break point to look at the log object I can see managed color is there as a root appender and the others added when first created. there is not a lot of info on using log4net programmatically, but I am hoping someone got this to work.

j.hull
  • 321
  • 3
  • 15

1 Answers1

0

As I was reading more I discovered how to turn on internal logging for log4net. Put that in the app.config file and yes, it helps for it showed me how to fix my issue though why it does not work dynamically still alludes me.

<appSettings>
    <add key="log4net.Internal.Debug" value="true"/>
</appSettings>

What I found was a few things:

Log4net does not need a config file to work if you are setting things up programmatically. Found that out because I had not set the 'copy to output directory' to other then 'do not copy' so no config file was being put in the the exe folder. This showed me you don't need a config file to do logging, but it still did not answer why no color.

If you decide to use a config file, but don't put in a appender that is referenced in the root, log4net logs the error, but keeps working. I had this

<appender-ref ref="ManagedColoredConsoleAppender" />

but no appender in the file. I added the ManagedColorConsole Appender and now I am getting both colored console messages AND logging into multiple files. This is a solution, but does not explain why I could add the color appender dynamically, but not have it work. If there is an answer please post. In the mean time this is a solved question.

<log4net>
  <root>
    <level value="ALL" />
    <appender-ref ref="ManagedColoredConsoleAppender" />
  </root>
  <appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
    <mapping>
      <level value="INFO" />
      <foreColor value="Green, HighIntensity" />
    </mapping>
    <mapping>
      <level value="DEBUG" />
      <foreColor value="Green" />
    </mapping>
    <mapping>
      <level value="ERROR" />
      <foreColor value="Yellow, HighIntensity" />
    </mapping>
    <mapping>
      <level value="FATAL" />
      <foreColor value="Red, HighIntensity" />
    </mapping>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
  </appender>
</log4net>
j.hull
  • 321
  • 3
  • 15