Mike Rinos
Mike Rinos

Reputation: 43

Setting up a tracelister to a tracesource defined in assembly in a config

What I'm trying to accomplish is setting a TraceListener for a TraceSource in a referenced .dll using only the config file.

Specifically I have solution Robot which has an app.config that looks like this:

<system.diagnostics>
<sources>
  <source name="RobotModel" switchValue="All">
    <listeners>
      <add name="RobotModelConsole" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{DateTime}::{EventType}::{Message}"/>
    </listeners>
  </source>
</sources/

and a ExtendedSource (from the Ukadc.Diagnostics.dll) initialized like this:

public static ExtendedSource robotSourceEx = new ExtendedSource( "RobotModel", SourceLevels.All );

Then I export the .dll and import it to the UI component and have a similar app.config:

 <system.diagnostics>
<sources>

  <source name="Temp" switchValue="All">
    <listeners>
      <!--<add name="console1" type="System.Diagnostics.ConsoleTraceListener" /> -->
      <add name="console" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{DateTime}::{EventType}::{Message}" />
    </listeners>
  </source>

  <source name="RobotModel" switchValue="All">
    <listeners>
      <add name="console1" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{DateTime}::{EventType}::{Message}" />
    </listeners>
  </source>

</sources>

When I run the UI component I get an empty console (Console.WriteLine and the trace information is missing), but if i comment out the TraceListener for the RobotModel, then the console has the example trace messages (as well as the Console.WriteLine message).

  1. Do I somehow need to specify the .dll or namespace for the RobotModel TraceListener
  2. I know I can do this dynamically as I have a winform component TraceListener that gets the trace messages, but want to configure this from the app.config assuming this is at all possible

Note: the gui is a Winforms/Windows Application while the Robot class is a console application. I don't think this would make a huge difference but maybe its noteworthy. I do manually allocate a console on the Windows Application so that I can ensure the trace works before routing it to a File.

Upvotes: 0

Views: 480

Answers (2)

Saurav Babu
Saurav Babu

Reputation: 111

To Setup TraceListener to a TraceSource defined in assembly as well as application using just config file we can use sharedListeners as shown below:

Application code:

using System;
using System.Diagnostics;
using TestLibrary;

namespace TraceSourceTest
{
    class Program
    {
        static TraceSource source = new TraceSource("TraceSourceTest");
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            source.TraceEvent(TraceEventType.Information, 101, "Hello World");
            Class1 test = new Class1();
            Console.WriteLine(test.add(5, 10));
            Console.ReadKey();
        }
    }
}

TestLibrary Code:

using System.Diagnostics;
namespace TestLibrary
{
    public class Class1
    {
        static TraceSource source = new TraceSource("TestLibrary");
        public int add(int a, int b)
        {
            source.TraceEvent(TraceEventType.Information, 101, "Add " + a + " and " + b);
            source.TraceEvent(TraceEventType.Information, 102, "Result " + (a + b));
            return a + b;
        }
    }
}

Appexe.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.diagnostics>    
        <trace autoflush="true" indentsize="4" />
        <sources>
            <source name ="TestLibrary" switchValue="All">
                <listeners>    
                    <add name="testListener" />    
                </listeners>
            </source>
            <source name ="TraceSourceTest" switchValue="All">
                <listeners>    
                    <add name="testListener" />
                </listeners>
            </source>
        </sources>
        <sharedListeners>
            <add name="testListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="TraceSourceTest.log">
                <filter initializeData="All" type="System.Diagnostics.EventTypeFilter"/>
            </add>
        </sharedListeners>
    </system.diagnostics>
</configuration>

This will create a TraceSourceTest.log file in the directory from where app is running with below logs:

TraceSourceTest Information: 101 : Hello World
TestLibrary Information: 101 : Add 5 and 10
TestLibrary Information: 102 : Result 15

and Console would be printing below output:

Hello World!
15

Upvotes: 0

Mike Rinos
Mike Rinos

Reputation: 43

To answer my own questions:

  1. No you don't need to specify the .dll or namespace when referring to a TraceSource in an assembly, you just need to know the name of the source
  2. Yes it is possible to do it strictly through app config as shown below

In terms of what was causing my problem it seems it had something to do with when I allocated the console in the WinForms. After changing the location of where I called AllocConsole the cmd window showed the trace information for both sources.

For posterity here is the code I used to test this:

public class Person {
    public int Age { get; set; }
    public string Name { get; set; }
    public static TraceSource source = new TraceSource( "[Source]" );
    public static ExtendedSource exSource = new ExtendedSource( "[SourceEx]" );
    public Person ( int age, string name ) {
        source.TraceInformation( "Creating a person named: {0}", name );
        exSource.TraceInformation( "{0} is alive!", name );
        Age = age;
        Name = name;
    }

    public int DateOfBirth () {
        return 2018 - Age;
    }
}

Then exported this as an assembly imported it to a winform:

namespace TestForm {
public partial class Form1 : Form {
    public static TraceSource source = new TraceSource( "[FormSource]" );
    public static ExtendedSource exSource = new ExtendedSource( "[FormSourceEx]", SourceLevels.All);
    public static int age;
    private int count = 0;

    [DllImport( "kernel32.dll", SetLastError = true )]
    [return: MarshalAs( UnmanagedType.Bool )]
    static extern bool AllocConsole ();

    public Form1 () {
        InitializeComponent();
    }

    private void button1_Click ( object sender, EventArgs e ) {
        source.TraceInformation( "Button Clicked" );
        exSource.TraceInformation( "Click count: {0}" ,count++ );
        Person p = new Person( age++, "Jordo" );
    }

    private void Form1_Load ( object sender, EventArgs e ) {
        AllocConsole();
    }
}
}

And the app config which I used:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
  <source name="[Source]" switchValue="All">
    <listeners>
      <add name="console" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{Source}::{Hour}:{Minute}:{Second}:{Millisecond}::{EventType}::{Message}" />
    </listeners>
  </source>
  <source name="[SourceEx]" switchValue="All">
    <listeners>
      <add name="console" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{Source}::{Hour}:{Minute}:{Second}:{Millisecond}::{EventType}::{Message}" />
    </listeners>
  </source>
  <source name="[FormSource]" switchValue="All">
    <listeners>
      <add name="console1" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{Source}::{Hour}:{Minute}:{Second}:{Millisecond}::{EventType}::{Message}" />
    </listeners>
  </source>
  <source name="[FormSourceEx]" switchValue="All">
    <listeners>
      <add name="console2" type="Ukadc.Diagnostics.Listeners.ConsoleTraceListener, Ukadc.Diagnostics" initializeData="{Source}::{Hour}:{Minute}:{Second}:{Millisecond}::{EventType}::{Message}" />
    </listeners>
  </source>
</sources>
</system.diagnostics>
<startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

Upvotes: 0

Related Questions