dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.27k stars 4.73k forks source link

TraceSource indent bug #25714

Closed ghost closed 2 weeks ago

ghost commented 6 years ago

TraceSource is affected by the indent set before the calling output methods for the first time. After that changing the indent doesn't affect the TraceSource output.

var mySource = new TraceSource("Test", SourceLevels.All);
Trace.IndentLevel = 2;
mySource.TraceEvent(TraceEventType.Error, 1, "TraceSource1");
Trace.WriteLine("Trace1");
Trace.IndentLevel = 1;
mySource.TraceEvent(TraceEventType.Error, 2, "TraceSource2");
Trace.WriteLine("Trace2");
mySource.TraceEvent(TraceEventType.Error, 3, "TraceSource3");

This is the output:

    Test Error: 1 : TraceSource1
    Trace1
    Test Error: 2 : TraceSource2
Trace2
    Test Error: 3 : TraceSource3

The only way to solve this is to creat a new instance of the TraceSource class before changing the indent.. This code will work as expected:

var mySource = new TraceSource("Test", SourceLevels.All);
Trace.IndentLevel = 2;
mySource.TraceEvent(TraceEventType.Error, 1, "TraceSource1");
Trace.WriteLine("Trace1");
mySource = new TraceSource("Test", SourceLevels.All);
Trace.IndentLevel = 1;
mySource.TraceEvent(TraceEventType.Error, 2, "TraceSource2");
Trace.WriteLine("Trace2");
mySource.TraceEvent(TraceEventType.Error, 3, "TraceSource3");

This is the output:

   Test Error: 1 : TraceSource1
    Trace1
Test Error: 2 : TraceSource2
Trace2
Test Error: 3 : TraceSource3

Note: I reported another 2 bugs related to System.Diagnostics here: https://github.com/dotnet/corefx/issues/28697

MarcoRossignoli commented 6 years ago

If i understood well this behaviour seems by design. TraceSource create local instance of TraceListenerCollection on first TraceEvent call. In this phase it copies IndentSize and IndentLevel from global TraceInternal. After that every changes to TraceInternal values won't be reflected on local TraceSource listeners. Finally global listener and local listener are different instances.

Trace.Listeners.Clear();
Trace.Listeners.Add(new DefaultTraceListener());
var mySource = new TraceSource("Test", SourceLevels.All);
Trace.IndentLevel = 2;
mySource.TraceEvent(TraceEventType.Error, 1, "TraceSource1");            
Trace.WriteLine("Trace1");
Trace.IndentLevel = 1;            
foreach (var item in mySource.Listeners)
{
     ((DefaultTraceListener)item).IndentLevel = Trace.IndentLevel;
}
mySource.TraceEvent(TraceEventType.Error, 2, "TraceSource2");
Trace.WriteLine("Trace2");
mySource.TraceEvent(TraceEventType.Error, 3, "TraceSource3");

output

        Test Error: 1 : TraceSource1
        Trace1
    Test Error: 2 : TraceSource2
    Trace2
    Test Error: 3 : TraceSource3
ghost commented 6 years ago

@MarcoRossignoli Thanks for your explanation. I think you give a workarround, and mine in fact is shorter. I think the best way to deal with this issue, is to add TraceSource.IndentLevel property, or make the TraceSource.TraceX methods update the listeners indent at every call. I expect also this doesn't happen when adding new listeners, so the Listeners.Add methould should make the default indent (which is zero) equals to Trace.Indent, which can be updated by code latter if we need. I think this is what a consistent design should be. Thanks.

MarcoRossignoli commented 6 years ago

maybe another workaround could be add same new DefaultTraceListener() to global Trace.Listeners and to mySource.Listeners, but i didn't try. I'm only contributor, i don't know if this is expected behaviour, we've to ask to @brianrob i think.

ghost commented 6 years ago

I think they only focused on initializing the indent from the config file. But missing indent methouds and propertied can make TraceSource class behave oddly as it depends on another class to change the indent. This will be worest in multi-thread tasks beause the Trace.IndentLevel can affect different instances of the TraceSource class. So, I understand why they use this design to isolate TraceSources, but sure it is not a good design. Adding a TraceSource.IndentLevel can solve this issue in a consistence way. They can still take the trace.IndentLevel from config files as an initial value for backward compatibility.

dotnet-policy-service[bot] commented 1 month ago

Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.

This process is part of our issue cleanup automation.

dotnet-policy-service[bot] commented 2 weeks ago

This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.