Answered by:
WCF Logging in code

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=neutral, PublicKeyToken=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=neutral, PublicKeyToken=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=neutral, PublicKeyToken=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=neutral, PublicKeyToken=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 lineobject 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
needbrewWednesday, 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.aspxThursday, November 12, 2009 11:13 AM