4

I have a Windows service application running under my username (installed via installutil).

Here are my start/stop event overloads:

protected override void OnStart(string[] args)
{
    try
    {
        Debugger.Launch();
    }
    catch (Exception ex)
    {
        logger.Fatal("...");
        throw;
    }
}

protected override void OnStop()
{
    logger.Trace("service stopped.");
}

logger is an NLog Logger instance, obtained like this:

private static Logger logger = LogManager.GetCurrentClassLogger();

Here is my NLog.config:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">

    <!-- 
  See http://nlog-project.org/wiki/Configuration_file 
  for information on customizing logging rules and outputs.
   -->
    <targets>
        <target xsi:type="Debugger" name="debugger_target" />
        <target xsi:type="Chainsaw" name="chainsaw_target" address="udp4://localhost:4141"/>
        <!--
        <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
        -->
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="chainsaw_target"/>
    </rules>
</nlog>

Then in a specific case I want to add a console log:

    private static void InitializeLogConfiguration()
    {
        var logConfig = LogManager.Configuration ?? new LoggingConfiguration();

        var consoleRule = new ColoredConsoleTarget("logConsole");
        consoleRule.Layout = Layout.FromString("${longdate}|${level:uppercase=true}|${logger}|${newline}${message:withexception=true}${newline}");
        logConfig.AddRule(LogLevel.Trace, LogLevel.Fatal, consoleRule);
        logConfig.DefaultCultureInfo = CultureInfo.InvariantCulture;

        LogManager.Configuration = logConfig;
    }

The service starts up just fine, and the debugger attaches as one would expect, and if I continue from there the service completes its start.

If I then stop the service, a breakpoint in OnStop hits, but when I try to continue over the logger.Trace call, it hangs indefinitely and becomes unresponsive to the service container.

HackSlash
  • 4,944
  • 2
  • 18
  • 44
Ben Collins
  • 20,538
  • 18
  • 127
  • 187

1 Answers1

1

I was seeing this happening due to a known issue with the blocking calls to StandardOutput.ReadToEnd() where combinations of reading and writing to redirected console can deadlock. If you are using NLog to write to a console and you need to read from that console in the same thread I recommend trying the AsyncTargetWrapper. This will run logging operations on a different thread so your application can move on with it's own life and not get stuck waiting around for a task that never returns.

You can add it to your nlog.config by adding async="true" to your targets section like this:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">

    <!-- 
  See http://nlog-project.org/wiki/Configuration_file 
  for information on customizing logging rules and outputs.
   -->
    <targets async="true">
        <target xsi:type="Debugger" name="debugger_target" />
        <target xsi:type="Chainsaw" name="chainsaw_target" address="udp4://localhost:4141"/>
        <!--
        <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
        -->
    </targets>

    <rules>
        <logger name="*" minlevel="Trace" writeTo="chainsaw_target"/>
    </rules>
</nlog>

Of if you are defining the console log in code, like I was, you can wrap the target like this:

LogManager.Setup().LoadConfiguration(c => c.ForLogger(LogLevel.Trace).WriteToConsole().WithAsync());

You still have to be careful to avoid the issues seen in process redirected console output.

Rolf Kristensen
  • 17,785
  • 1
  • 51
  • 70
HackSlash
  • 4,944
  • 2
  • 18
  • 44
  • 1
    If you have some callstacks from the experienced deadlock situation, then you are wellcome to open an issue at https://github.com/NLog/NLog/issues – Rolf Kristensen May 31 '23 at 18:19
  • Ok, thanks. For readers of the future, it happened here: https://github.com/NLog/NLog/issues/5236 – HackSlash May 31 '23 at 23:19