Reputation: 294
In the examples I can find the tracing is enabled via config file, for example
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.diagnostics>
<sources>
<source name="System.Net" tracemode="includehex" maxdatasize="1024">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
</sources>
<switches>
<add name="System.Net" value="Verbose"/>
</switches>
<sharedListeners>
<add name="System.Net"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="network.log"
/>
</sharedListeners>
<trace autoflush="true" indentsize="4" />
</system.diagnostics>
</configuration>
But I don't want config file to be shipped with my dll. Moreover I need to be able to enable/disable tracing and change log name "on the fly" in my code. What I came up with:
FileStream stream = new FileStream("D:\\network1.log", FileMode.OpenOrCreate);
TextWriterTraceListener listener = new TextWriterTraceListener(stream);
Trace.Listeners.Add(listener);
Trace.AutoFlush = true;
TraceSwitch ts = new TraceSwitch("System.Net", ".Net");
ts.Level = TraceLevel.Verbose;
and it is not logging anything, and I don't know where to add the switch, and if that is correct at all. The listener works but it don't fetch any data.
I've been reading msdn and this blog post http://www.codeguru.com/csharp/.net/article.php/c19405/Tracing-in-NET-and-Implementing-Your-Own-Trace-Listeners.htm and from the way I understand it, once added to the Trace.Listeners
a listener should log all thace info in the current exe, but that's obvioustly not the case.
So how to achieve that?
Edit: I've managed to hack around this limitation by dissasembling the TextWriterTraceListener and implementing my own TraceListener with the dissasembled code, adding if staatements in Write and WriteLine methods that check some static fields of another class, and adding my type in the config.
Upvotes: 4
Views: 2445
Reputation: 905
For readers that are in .NET Core and beyond, you can achieve this by making a class that inherits from System.Diagnostics.Tracing.EventListener
See https://github.com/dotnet/runtime/issues/64977 for details + original suggestion.
Example:
private class SystemNetEventListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
// take anything from System.Net
if (eventSource.Name?.StartsWith("Private.InternalDiagnostics.System.Net.") == true)
{
EnableEvents(eventSource, EventLevel.LogAlways);
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
try
{
// produce a string that can be logged
var sb = new StringBuilder().Append($"{eventData.TimeStamp:HH:mm:ss.fffffff}[{eventData.EventName}] ");
for (int i = 0; i < eventData.Payload?.Count; i++)
{
if (i > 0)
sb.Append(", ");
sb.Append(eventData.PayloadNames?[i]).Append(": ").Append(eventData.Payload[i]);
}
Console.WriteLine(sb.ToString().Trim());
}
catch
{
// on failure... well... we are the logger, so there's nobody to tell we failed
}
}
}
Usage:
var listener = new SystemNetEventListener(); // start logging
... // do HTTP/Websocket stuff
listener.Dispose(); // stop logging
Upvotes: 0
Reputation: 42434
You can't enable the tracing of System.Net
from code, at least not in a supported way.
First let me point out that you mixed up a TraceSwitch
and a TraceSource
. The TraceSource
is the one that gets used to trace messages to. The TraceSwitch only controls what gets logged.
When you instantiate a TraceSource
it initializes itself by checking the <sources>
collection of the system.diagnostics setting for a <source>
with the same name. When there is one, the instance is build-up with the settings provided. Your program will then use that specific TraceSource
instance to log its data by calling TraceEvent
or any of the other methods.
If there is no config found, the TraceSource
is configured with the DefaultTraceListener
with the SwitchLevel set to Off.
What I described above is also done by the internal System.Net.Logging
class in its InitializeLogging
method. It creates its own instance of a TraceSource
for System.Net that once created, either is configured as defined in the config file or with the Defaults. All the logging that is done by the classes in the System.Net
namespace use that private/internal TraceSource
.
There is no public interface that allows you to insert or intercept TraceSource
construction so you can't control which listener to connect or set Switch levels on a shared/singleton like TraceSource. Nor is there an option to get to the internal System.Diagnostics.DiagnosticsConfiguration
class instance.
I did venture a bit in System.Configuration.Internal but I gave-up on that.
If you do fancy reflection you can grab the internal static type System.Net.Logging
and get a reference to the TraceSource
from the static property Web
. Once you have the reference, I imagine you can set the listeners and switchlevel. That is an internal implementation detail and might change without notice so I don't recommend this.
To get control over logging, create overloads for the classes in System.Net
and add your own TraceSource
instance and log info to that instance.
Upvotes: 7