Search code examples
c#dockermonolog4netstdout

Docker missing log4net ConsoleAppender logs


I've got a simple C# program with the following log4net configuration:

<log4net>
    <appender name="stdout" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%%-5level - %message%newline" />
    </layout>
    </appender>

    <root>
        <level value="DEBUG" />
        <appender-ref ref="stdout" />
    </root>
</log4net>

And the following code (abbreviated for clarity):

public static void Main(String[] args)
{
    var log = LogManager.GetLogger("Logger");
    log.Info("Hello From Logger");
    Console.WriteLine("Hello From Console");
}

I'm compiling and running this using .NET 4.5 mono on an Ubuntu 16.04 system. When I run the program using the console the output is as expected:

$ mono Program.exe
INFO - Hello From Logger
Hello From Console

However, when I run this same program in a Docker container in detached mode (i.e, "docker run -d") and then check the logs, I only get the log from the Console.WriteLine:

$ docker logs <container_id>
Hello From Console

While trying to track this down, I tried running the program using the daemonize tool (more info here) and it illustrated the same behavior, leading me to believe it was an issue with log4net instead of docker. I also wrote a custom appender for log4net that only does Console.Write (I believe that's the same functionality as ConsoleAppender, but I wanted to eliminate any other possible variables):

public class CustomAppender: AppenderSkeleton
{
    protected override void Append(LoggingEvent loggingEvent)
    {
        Console.Write(RenderLoggingEvent(loggingEvent));
    }
} 

But no luck. Can anyone with a deep knowledge of log4net point me to where I could be doing something wrong, or explain what log4net could be doing to stdout such that other programs that should be capturing that stream don't?

UPDATE: The plot thickens! I wrote a quick and dirty executable that uses the Process class to execute my example program. It then grabs the stdout from the example program and writes it with Console.WriteLine, like so:

Process proc = new Process();
proc.StartInfo.FileName = "/path/to/example.exe";
proc.StartInfo.UseShellExecute = false;
proc.StartInto.RedirectStandardOutput = true;
proc.Start();
Thread.Sleep(1000);
Console.WriteLine(proc.StandardOutput.ReadToEnd());

This works fine when I run it directly from the console, but has the same problem when I run it from docker / daemonize. So now I'm really confused.


Solution

  • It's not much of an answer, but in case someone else runs into this problem, I was able to get logging to work by using the NLog library here.