Closed steveharter closed 2 years ago
Tagging subscribers to this area: @tommcdon See info in area-owners.md if you want to be subscribed.
Author: | steveharter |
---|---|
Assignees: | steveharter |
Labels: | `area-System.Diagnostics`, `api-ready-for-review` |
Milestone: | 7.0.0 |
Naming nit: the verb 'Register' wasn't intuitive for me in this context. As an application author I'd be more inclined to think of it as Apply()ing or Load()ing the Trace configuration.
I imagine Register makes sense in the context of registering for configuration callbacks from System.Diagnostics.TraceSource, but if the application author isn't aware of what the new TraceSource API looks like or how the Register() function is implemented then the meaning may not land for them.
Naming nit: the verb 'Register' wasn't intuitive for me in this context.
Hmm:
IMO all of those are an improvement over Register, EnableAppConfig() sounds the best to me out of the group but I know naming is a very subjective topic : ) Thanks!
app.config
which we don't do in .NET Core because we treat app.config as legacy API that sits on top of everything else.EventArgs
and just require handlers to cast sender
Could we make this API shape work?
namespace System.Diagnostics
{
public abstract class Switch
{
- protected string Value { get; set; }
+ public string Value { get; set; }
+ public void Refresh();
+ public static event EventHandler? Initializing { add; remove; }
}
public sealed class Trace
{
+ public static event EventHandler? Refreshing { add; remove; }
}
public class TraceSource
{
+ public SourceLevels DefaultLevel { get; }
+ public static event EventHandler<ConfigureTraceSourceEventArgs>? Initializing { add; remove; }
}
+ public sealed class ConfigureTraceSourceEventArgs : EventArgs
+ {
+ public ConfigureTraceSourceEventArgs();
+ public bool WasConfigured { get; set; }
+ }
}
By moving the events to the corresponding types we might be able to get rid of the EventArgs and just require handlers to cast sender
Since these are static events, the guidelines state: _DO pass null as the sender when raising a static event.
This implies bringing back ConfigureSwitchEventArgs
and ConfigureTraceSourceEventArgs.TraceSource
.
Why do we need to expose the defaults? This wasn't necessary on .NET Framework.
These are needed in case a TraceSource
or Switch
is removed from a config file and Trace.Refresh()
is called which re-reads from the config file. The .NET Framework behavior is to reset these back to the default specified in the TraceSource(...)
and Switch(...)
` constructors. The .NET Framework reference source: TraceSource and Switch.
As for removing the setters for public System.Collections.Specialized.StringDictionary Attributes
, we can avoid adding a setter although it is not as performant since a Clear()
followed by manual copy from the underlying config's internal collection:
internal static void CopyStringDictionary(StringDictionary source, StringDictionary dest)
{
dest.Clear();
foreach (string key in source)
{
dest[key] = source[key];
}
}
On naming, "InitializingTraceSourceEventArgs" seems more appropriate than "ConfigureTraceSourceEventArgs" and "WasInitialized" instead of "WasConfigured".
We did a review update via email and agreed changed the API shape to this:
namespace System.Diagnostics
{
public abstract class Switch
{
+ public string DefaultValue { get { throw null; } }
- protected string Value { get; set; }
+ public string Value { get; set; }
+ public void Refresh();
+ public static event EventHandler<InitializingSwitchEventArgs>? Initializing { add; remove; }
}
public sealed class Trace
{
+ public static event EventHandler? Refreshing { add; remove; }
}
public class TraceSource
{
+ public SourceLevels DefaultLevel { get; }
+ public static event EventHandler<InitializingTraceSourceEventArgs>? Initializing { add; remove; }
}
+ public sealed class InitializingSwitchEventArgs : EventArgs
+ {
+ public InitializingSwitchEventArgs(Switch @switch);
+ public System.Diagnostics.Switch Switch { get; }
+ }
+ public sealed class InitializingTraceSourceEventArgs : EventArgs
+ {
+ public InitializingTraceSourceEventArgs(TraceSource traceSource) { }
+ public System.Diagnostics.TraceSource TraceSource { get; }
+ public bool WasInitialized { get; set; }
+ }
+ public static class TraceConfiguration
+ {
+ public static void Register();
+ }
}
Reasons given by @steveharter:
Switch.DefaultValue
andTraceSource.DefaulLevel
are required for reasons mentioned here.- Static events should pass
null
forsender
, so adding backInitializingSwitchEventArgs
andInitializingTraceSourceEventArgs.TraceSource
. If we want to go against the guidelines here, I'm open to that.- Rename
InitializingTraceSourceEventArgs.WasConfigured
toWasInitialized
.- Rename
ConfigureTraceSourceEventArgs
toInitializingTraceSourceEventArgs
- The approved API did not include
TraceConfiguration.Register()
. Note that we did not discuss naming of this and are some community comments about it; essentially it tells the config system to subscribe and handle the 3 events.
- Note that this API lives in the config assembly, not the diagnostics assembly.
If we're using "initializing" may be the method should as well be called Initialize()
as opposed to Register()
?
I may be wrong, but I think the main ask came from Windows Forms users, and those users would likely be the main audience for this API. Windows Forms SDK has another API that is run at the start of the app - the same place where this API will be run as well - which is called AppConfiguration.Initialize()
. Aligning the vocabulary would be great.
Background and motivation
Original issue: https://github.com/dotnet/runtime/issues/23937
This helps adoption from those moving from .NET Framework who use
TraceSource
for logging. There is currently no support for automatically reading theapp.config
and applying those settings toTraceSource
and associatedTraceFilter
andTraceSwitch
instances. Support forTrace.Refresh()
based on .NET Framework is also added which allows the application to update existingTraceSource
andSwitch
instances when the config file changes.The
TraceSource
code lives inSystem.Diagnostics.TraceSource.dll
which is shipped inbox but the processing of theapp.config
is done inSystem.Configuration.ConfigurationManager.dll
which is OOB.The proposed APIs essentially allow interaction between these two separate assemblies and these APIs are used internally and not intended for general use. The one exception is the
TraceConfiguration.Register()
method to light-up the config side.Although not a stated goal in the issue above, these new APIs make it possible to support reading from another format, such as a JSON file, by using a similar approach as done in
System.Configuration.ConfigurationManager.dll
which reads from theapp.config
XML file.API Proposal
These live in System.Diagnostics.TraceSource.dll:
These live in System.Configuration.ConfigurationManager.dll:
API Usage
Given the
app.config
file:Then code using
TraceSource
will be initialized to the values in theapp.config
:Alternative Designs
No response
Risks
No response