.netloggingdllnlogconsole-redirect

.NET external DLL log redirection


The case is this:

Is there a way to prefetch the logs from the dll when executing its methods and redirect them to a file or so?

I can redirect the app's console output to a file without a problem - but the DLL calls remain hidden (i only see them in the actual console).

Thank you!


Solution

  • For whomever this might help, here is the solution for this:

    #region thanks
    /////////////////////////////////////////////////////////////////
    // With thanks to nobugz                                       //
    // MVP, Moderator on the MSDN C# general forums                //
    // http://social.msdn.microsoft.com/Profile/en-US/?user=nobugz //
    ///////////////////////////////////////////////////////////////// 
    #endregion
    
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.IO.Pipes;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    
    namespace miniws
    {
        internal sealed class ConsoleRedirector : IDisposable
        {
            private static ConsoleRedirector _instance;
    
            public static void attach(ILogListener listener)
            {
                Debug.Assert(null == _instance);
                _instance = new ConsoleRedirector(listener);
            }
    
            public static void detatch()
            {
                _instance.Dispose();
                _instance = null;
            }
    
            public static bool isAttached
            {
                get
                {
                    return null != _instance;
                }
            }
    
            //----------------------------------------------------------------------
    
            private const int PERIOD = 500;
            private const int BUFFER_SIZE = 4096;
            private volatile bool _isDisposed;
            private readonly ILogListener _logListener;
            private readonly IntPtr _stdout;
            private readonly IntPtr _stderr;
            private readonly Mutex _sync;
            private readonly Timer _timer;
            private readonly char[] _buffer;
            private readonly AnonymousPipeServerStream _outServer;
            private readonly AnonymousPipeServerStream _errServer;
            private readonly TextReader _outClient;
            private readonly TextReader _errClient;
    
            // ReSharper disable UseObjectOrCollectionInitializer
            private ConsoleRedirector(ILogListener logListener)
            {
                bool ret;
                AnonymousPipeClientStream client;
    
                _logListener = logListener;
                _stdout = GetStdHandle(STD_OUTPUT_HANDLE);
                _stderr = GetStdHandle(STD_ERROR_HANDLE);
                _sync = new Mutex();
                _buffer = new char[BUFFER_SIZE];
    
                _outServer = new AnonymousPipeServerStream(PipeDirection.Out);
                client = new AnonymousPipeClientStream(PipeDirection.In,
    _outServer.ClientSafePipeHandle);
                //client.ReadTimeout = 0;
                Debug.Assert(_outServer.IsConnected);
                _outClient = new StreamReader(client, Encoding.Default);
                ret = SetStdHandle(STD_OUTPUT_HANDLE, _outServer.SafePipeHandle.DangerousGetHandle());
                Debug.Assert(ret);
    
                _errServer = new AnonymousPipeServerStream(PipeDirection.Out);
                client = new AnonymousPipeClientStream(PipeDirection.In,
    _errServer.ClientSafePipeHandle);
                //client.ReadTimeout = 0;
                Debug.Assert(_errServer.IsConnected);
                _errClient = new StreamReader(client, Encoding.Default);
                ret = SetStdHandle(STD_ERROR_HANDLE, _errServer.SafePipeHandle.DangerousGetHandle());
                Debug.Assert(ret);
    
                Thread outThread = new Thread(doRead);
                Thread errThread = new Thread(doRead);
                outThread.Name = "stdout logger";
                errThread.Name = "stderr logger";
                outThread.Start(_outClient);
                errThread.Start(_errClient);
                _timer = new Timer(flush, null, PERIOD, PERIOD);
            }
            // ReSharper restore UseObjectOrCollectionInitializer
    
            private void flush(object state)
            {
                _outServer.Flush();
                _errServer.Flush();
            }
    
            private void doRead(object clientObj)
            {
                TextReader client = (TextReader)clientObj;
                try
                {
                    while (true)
                    {
                        int read = client.Read(_buffer, 0, BUFFER_SIZE);
                        if (read > 0)
                            //Console.WriteLine(" log :"+_buffer.ToString()+read);
                            _logListener.writeChars(_buffer, 0, read);
                    }
                }
                catch (ObjectDisposedException)
                {
                    // Pipe was closed... terminate
                }
            }
    
            public void Dispose()
            {
                Dispose(true);
            }
    
            ~ConsoleRedirector()
            {
                Dispose(false);
            }
    
            // ReSharper disable InconsistentNaming
            // ReSharper disable UnusedParameter.Local
            // ReSharper disable EmptyGeneralCatchClause
            private void Dispose(bool disposing)
            {
                if (!_isDisposed)
                {
                    lock (_sync)
                    {
                        if (!_isDisposed)
                        {
                            _isDisposed = true;
                            _timer.Change(Timeout.Infinite, Timeout.Infinite);
                            _timer.Dispose();
                            flush(null);
    
                            try { SetStdHandle(STD_OUTPUT_HANDLE, _stdout); }
                            catch (Exception) { }
                            _outClient.Dispose();
                            _outServer.Dispose();
    
                            try { SetStdHandle(STD_ERROR_HANDLE, _stderr); }
                            catch (Exception) { }
                            _errClient.Dispose();
                            _errServer.Dispose();
                        }
                    }
                }
            }
            // ReSharper restore EmptyGeneralCatchClause
            // ReSharper restore UnusedParameter.Local
            // ReSharper restore InconsistentNaming
    
            // ReSharper disable InconsistentNaming
            private const int STD_OUTPUT_HANDLE = -11;
            private const int STD_ERROR_HANDLE = -12;
    
            [DllImport("kernel32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
    
            [DllImport("kernel32.dll")]
            private static extern IntPtr GetStdHandle(int nStdHandle);
            // ReSharper restore InconsistentNaming
        }
    
    
    }