locked
WCF Logging in code RRS feed

  • Question

  • I'm wondering why I can't start logging WCF in code.

    This configuration works fine in my App.config (or any config):

    <system.diagnostics>
        <sources>
          <source
            name="System.ServiceModel"
            switchValue="All"
            propagateActivity="true">
            <listeners>
              <add
                  name="TraceInXml"
                  type="System.Diagnostics.XmlWriterTraceListener"
                  initializeData="c:\logs\wcf_trace.xml" />
            </listeners>
          </source>
        </sources>
        <trace autoflush="true" />
      </system.diagnostics>

    But the "equivalent" in code doesn't work when placed in the entry point of application:

    XmlWriterTraceListener x = new XmlWriterTraceListener(@"c:\logs\wcf_trace.xml");
    x.TraceOutputOptions = TraceOptions.Timestamp;

    TraceSource ts = new TraceSource("System.ServiceModel", SourceLevels.All);
    ts.Attributes["propagateActivity"] = "true";
    ts.Listeners.Add(x);

    Trace.AutoFlush = true;

    Wednesday, October 8, 2008 7:50 PM

Answers

  • The major tracing features in the System.ServiceModel namespace are implemented by internal classes such as DiagnosticUtility (static class)  and DiagnosticsTrace.

    As the following code snippet  shows, the DiagnosticTrace is created only for existing listener:
        private static DiagnosticTrace InitializeTracing()  
        {  
            InitDiagnosticTraceImpl(TraceSourceKind.DiagnosticTraceSource, "System.ServiceModel");  
            if (!diagnosticTrace.HaveListeners)  
            {  
                diagnosticTrace = null;  
            }  
            return diagnosticTrace;  
        }  
     


    The short answer to your question is, that there is no support for creating a trace configuration programmatically.

    However, there is some workaround for that.

    1.       Create dummy (temporary) source with default listener in the config file, for example:  

                    <system.diagnostics>

           <sources>

             <source name="System.ServiceModel" >

               <listeners>

                 <add type="System.Diagnostics.DefaultTraceListener" name="dummy"/>

               </listeners>

             </source>

           </sources>

    </system.diagnostics>

    2. Implement the following workaround:

    BindingFlags privateMember = BindingFlags.NonPublic | BindingFlags.Instance;  
    BindingFlags privateStaticMember = privateMember | BindingFlags.Static;  
     
    Type type = Type.GetType("System.ServiceModel.DiagnosticUtility, System.ServiceModel, Version=3.0.0.0, Culture=neutralPublicKeyToken=b77a5c561934e089");  
    MethodInfo[] mi = type.GetMethods(privateStaticMember);  
     
    // invoke InitializeTracing  
    object diagnosticTrace = mi.FirstOrDefault(e=>e.Name=="InitializeTracing").Invoke(null, null);  
    if (diagnosticTrace != null)  
    {  
       // get TraceSource  
       Type type2 = Type.GetType("System.ServiceModel.Diagnostics.DiagnosticTrace, SMDiagnostics, Version=3.0.0.0, Culture=neutralPublicKeyToken=b77a5c561934e089");  
       PropertyInfo pi = type2.GetProperty("TraceSource", privateMember);  
       traceSource = pi.GetValue(diagnosticTrace, null) as TraceSource;  
                          
       // clear all listeners in the trace source  
       traceSource.Listeners.Clear();  
     
       // add listener to trace source  
       XmlWriterTraceListener listener = new XmlWriterTraceListener(@"c:\logs\wcf_trace.svclog");  
       listener.TraceOutputOptions = TraceOptions.Timestamp | TraceOptions.Callstack;  
       traceSource.Attributes["propagateActivity"] = "true";  
       traceSource.Switch.ShouldTrace(TraceEventType.Verbose | TraceEventType.Start);  
       traceSource.Listeners.Add(listener);  
     
       // enable tracing  
       type.GetProperty("Level", privateStaticMember).SetValue(null, SourceLevels.All, null);  
     
       Trace.AutoFlush = true;                    
     } 


    Thanks

    Roman


    Roman Kiss, MVP Connected System Developer
    • Edited by Roman Kiss Sunday, October 12, 2008 7:16 PM
    • Marked as answer by edhickey Thursday, October 16, 2008 3:30 PM
    Sunday, October 12, 2008 7:11 PM

All replies

  • The major tracing features in the System.ServiceModel namespace are implemented by internal classes such as DiagnosticUtility (static class)  and DiagnosticsTrace.

    As the following code snippet  shows, the DiagnosticTrace is created only for existing listener:
        private static DiagnosticTrace InitializeTracing()  
        {  
            InitDiagnosticTraceImpl(TraceSourceKind.DiagnosticTraceSource, "System.ServiceModel");  
            if (!diagnosticTrace.HaveListeners)  
            {  
                diagnosticTrace = null;  
            }  
            return diagnosticTrace;  
        }  
     


    The short answer to your question is, that there is no support for creating a trace configuration programmatically.

    However, there is some workaround for that.

    1.       Create dummy (temporary) source with default listener in the config file, for example:  

                    <system.diagnostics>

           <sources>

             <source name="System.ServiceModel" >

               <listeners>

                 <add type="System.Diagnostics.DefaultTraceListener" name="dummy"/>

               </listeners>

             </source>

           </sources>

    </system.diagnostics>

    2. Implement the following workaround:

    BindingFlags privateMember = BindingFlags.NonPublic | BindingFlags.Instance;  
    BindingFlags privateStaticMember = privateMember | BindingFlags.Static;  
     
    Type type = Type.GetType("System.ServiceModel.DiagnosticUtility, System.ServiceModel, Version=3.0.0.0, Culture=neutralPublicKeyToken=b77a5c561934e089");  
    MethodInfo[] mi = type.GetMethods(privateStaticMember);  
     
    // invoke InitializeTracing  
    object diagnosticTrace = mi.FirstOrDefault(e=>e.Name=="InitializeTracing").Invoke(null, null);  
    if (diagnosticTrace != null)  
    {  
       // get TraceSource  
       Type type2 = Type.GetType("System.ServiceModel.Diagnostics.DiagnosticTrace, SMDiagnostics, Version=3.0.0.0, Culture=neutralPublicKeyToken=b77a5c561934e089");  
       PropertyInfo pi = type2.GetProperty("TraceSource", privateMember);  
       traceSource = pi.GetValue(diagnosticTrace, null) as TraceSource;  
                          
       // clear all listeners in the trace source  
       traceSource.Listeners.Clear();  
     
       // add listener to trace source  
       XmlWriterTraceListener listener = new XmlWriterTraceListener(@"c:\logs\wcf_trace.svclog");  
       listener.TraceOutputOptions = TraceOptions.Timestamp | TraceOptions.Callstack;  
       traceSource.Attributes["propagateActivity"] = "true";  
       traceSource.Switch.ShouldTrace(TraceEventType.Verbose | TraceEventType.Start);  
       traceSource.Listeners.Add(listener);  
     
       // enable tracing  
       type.GetProperty("Level", privateStaticMember).SetValue(null, SourceLevels.All, null);  
     
       Trace.AutoFlush = true;                    
     } 


    Thanks

    Roman


    Roman Kiss, MVP Connected System Developer
    • Edited by Roman Kiss Sunday, October 12, 2008 7:16 PM
    • Marked as answer by edhickey Thursday, October 16, 2008 3:30 PM
    Sunday, October 12, 2008 7:11 PM
  • How would you use this code if the trace needed to be created in a seperate client DLL to hide some of the WCF related code from the client. Even with the dummy Trace stub in the applications config, the line

    object diagnosticTrace = mi.FirstOrDefault(e => e.Name == "InitializeTracing").Invoke(null, null);

    returns null.  in my client I create an instance of my CLientDLL which creates all my WCF in code using ChannelFactorys.  I would like to be able to turn a trace on and off by passing in a flag when I instantiate my object.  Can this be done?

    Thanks in advance



    needbrew
    Wednesday, April 22, 2009 4:42 PM
  • See this link for details on setting the filename of the log at runtime http://geekswithblogs.net/FlippinIT/archive/2009/11/12/wcf-tracing-in-code.aspx
    Thursday, November 12, 2009 11:13 AM