Debug|Trace.WriteLine from C# plugin in Visual Studio - display via ConsoleTraceListener

4

I've modified a C# plugin that's part of Python Tools for Visual Studio 2.0, and want to see the output from Debug.WriteLine and Trace.WriteLine statements in the code. Note that the plugin is used in Visual Studio 2013 itself, modifying debugging of python processes....

I'm hoping I can add a trace listener in devenv.exe.config as suggested by pminaev on the PTVS discussion forum here (attaching another VS to VS itself seems clumsy so I'm hoping to avoid that).

What I believe to be correct config for other .NET applications doesn't seem to work for VS2013 itself. My efforts are documented below.

If anyone's managed to redirect plugin debug/trace output to the Visual Studio Console (or anywhere else more convenient than another attached VS instance), tips greatly appreciated....


My Google-fu turned up a couple examples, based on which I've tried adding...

<system.diagnostics>
    <trace autoflush="true" />
        <listeners>
            <add name="myConsoleTraceListener" type="System.Diagnostics.ConsoleTraceListener" />
        </listeners>
    </trace>
</system.diagnostics>

...and...

<system.diagnostics>
    <source name="System.ServiceModel.MessageLogging" switchValue="Verbose, ActivityTracing">
        <listeners>
            <add name="myTraceListener" />
        </listeners>
    </source>
    <sharedListeners>
        <add name="myTraceListener" type="System.Diagnostics.ConsoleTraceListener" />
    </sharedListeners>
</system.diagnostics>

Starting PTVS afterwards, nothing's usable. With either config I get a popup:

The `Python Tools Package' package id not load correctly.

The problem may have been caused by a configuration change or by
the installation of another extension.  You can get more information by
examining the file
'C:\Users\XXX\AppData\Roaming\Microsoft\VisualStudio\12.0\Acti
vityLog.xml'.

The ActivityLog doesn't mean much to me:

<entry>
    <record>41</record>
    <time>2014/05/12 07:52:47.851</time>
    <type>Error</type>
    <source>VisualStudio</source>
    <description>CreateInstance failed for package [Python Tools Package]</description>
    <guid>{6DBD7C1E-1F1B-496D-AC7C-C55DAE66C783}</guid>
    <hr>80131604</hr>
    <errorinfo>Exception has been thrown by the target of an invocation.</errorinfo>
</entry>
<entry>
    <record>42</record>
    <time>2014/05/12 07:52:47.851</time>
    <type>Error</type>
    <source>VisualStudio</source>
    <description>End package load [Python Tools Package]</description>
    <guid>{6DBD7C1E-1F1B-496D-AC7C-C55DAE66C783}</guid>
    <hr>80004005 - E_FAIL</hr>
    <errorinfo>Exception has been thrown by the target of an invocation.</errorinfo>
</entry>

When I try to attach to the remote python process I get another popup:

Unable to connect to 'secret@server'.  Operation not supported.
Unknown error: 0x80131902.

Google-foo suggests this is some failure to load a .NET version...?

c#
.net
visual-studio
listeners
devenv
asked on Stack Overflow May 12, 2014 by Tony Delroy • edited May 12, 2014 by Tony Delroy

1 Answer

1

I wanted to do something similar for a plugin I wrote: pMixins. I used log4net instead of System.Diagnostics, but wanted to route log messages to the Visual Studio Output window.

I never got a config based approach to work and ended up doing the wiring programmatically. Additionally, I had to create a custom log writer to write to the Visual Studio Output Window.

In my Package file (https://github.com/ppittle/pMixins/blob/master/pMixins.VSPackage/pMixinsVisualStudioCodeGenerateInitializer.cs):

protected override void Initialize()
{

      //Create a Visual Studio Writer
       _visualStudioWriter = new VisualStudioWriter(dte, this);

      //Initialize Logging
      Log4NetInitializer.Initialize(_visualStudioWriter, this);
 }

VisualStudioWriter (summary) (https://github.com/ppittle/pMixins/blob/master/pMixins.VSPackage/Infrastructure/VisualStudioWriter.cs):

public class VisualStudioWriter : IVisualStudioWriter
{  
    private EnvDTE.OutputWindowPane _outputWindowPane;

    public VisualStudioWriter(DTE dte, System.IServiceProvider serviceProvider)
    {                      
        _outputWindowPane = LoadOutputWindowPane(dte);
    }

    private EnvDTE.OutputWindowPane LoadOutputWindowPane(DTE dte)
    {
        const string windowName = "pMixins Code Generator";
        EnvDTE.OutputWindowPane pane = null;
        EnvDTE.Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
        if (window != null)
        {
            EnvDTE.OutputWindow output = window.Object as EnvDTE.OutputWindow;
            if (output != null)
            {
                pane = output.ActivePane;
                if (pane == null || pane.Name != windowName)
                {
                    for (int ix = output.OutputWindowPanes.Count; ix > 0; ix--)
                    {
                        pane = output.OutputWindowPanes.Item(ix);
                        if (pane.Name == windowName)
                            break;
                    }
                    if (pane == null || pane.Name != windowName)
                        pane = output.OutputWindowPanes.Add(windowName);
                    if (pane != null)
                        pane.Activate();
                }
            }
        }
        return pane;
    }

    public void OutputString(string s)
    {
        _outputWindowPane.OutputString(s);
    }
 }

Log4NetInitializer (Summary) https://github.com/ppittle/pMixins/blob/master/CopaceticSoftware.CodeGenerator.StarterKit/Logging/Log4NetInitializer.cs

public static class Log4NetInitializer
{
    public static void Initialize(IVisualStudioWriter visualStudioWriter,
                       IServiceProvider serviceProvider)
    {
       //http://stackoverflow.com/questions/650694/changing-the-log-level-programmaticaly-in-log4net
       var outputWindowAppender =
           new VisualStudioOutputWindowAppender(visualStudioWriter)
           {
               Layout =
                       new PatternLayout(@"%date{HH:mm:ss,fff} %thread% %-5level [%logger{2}] %message%newline"),
                    Threshold =
                    #if DEBUG
                     Level.Debug
                     #else
                    Level.Info
                        #endif
           };


       log4net.Config.BasicConfigurator.Configure(
                outputWindowAppender);                

    }
}

Finally, VisualStudioOutputWindowAppender (https://github.com/ppittle/pMixins/blob/master/CopaceticSoftware.CodeGenerator.StarterKit/Logging/VisualStudioOutputWindowAppender.cs)

public class VisualStudioOutputWindowAppender : AppenderSkeleton
{
    public IVisualStudioWriter OutputWindow { get; set; }

    public VisualStudioOutputWindowAppender(IVisualStudioWriter outputWindow)
    {
        OutputWindow = outputWindow;

        Layout = new PatternLayout("%-5level %logger - %message%newline");
    }

    protected override void Append(LoggingEvent loggingEvent)
    {
        if (null == OutputWindow)
            return;

        if (null == loggingEvent)
            return;

        OutputWindow.OutputString(RenderLoggingEvent(loggingEvent));
    }
}

Hope That Helps

answered on Stack Overflow Jun 26, 2014 by Philip Pittle

User contributions licensed under CC BY-SA 3.0