|
From: Geoghegan, W. A (Willie) <wil...@in...> - 2010-09-21 21:22:28
|
Msg was too long. Posting in two parts. Part 1. Hello, On the Common.Logging website, the "Release Schedule" note near the bottom lists some features planned for the next release. These features include: Partial Trust compliance (already in trunk) Support for Windows Azure Support for Silverlight Logging Context support (in progress) It also says the next release is scheduled to be in "June". I asked in an earlier message about what the expected timeframe is for the release, so I won't ask again here. I do want to ask about the Logging Context support and Silverlight support (Silverlight towards the end of this mail). I think that logging context will be a useful addition. I have some questions about how you are planning to implement it: 1. Do you plan to expose context information via the ILog interface (similar to the Castle approach - see their git repository)? 2. Do you plan to expose context information via the LogManager? 3. Do you plan to provide a default implementation for abstractions that don't natively support logging context, at least a "NullContext" context provider that provides an object (rather than null) that does not actually do anything. 4. What will the exposed interface/programming model look like? Castle has implemented an abstraction of Logging Context, at least for their log4net and NLog logging implementations. It appears, from looking at their git repository, that they have defined some interfaces: IGlobalContextProperties, IThreadContextProperties, IThreadContextStacks, and IThreadContextStack. It is easy enough to look in the Castle git repository at how these interfaces were implemented for log4net and NLog to see exactly how the interfaces relate to the various logging contexts. The interfaces themselves are exposed from the loggers. So, if you have a Castle NLog logger you could get/set a GlobalContextProperties value something like this: ILogger logger = <I guess in Castle the logger is probably injected rather than retrieved via a LogManager>; Logger.GlobalContextProperties["MyProperty"] = 12345; That's pretty good. Anywhere you have access to a logger (ILogger implementation), you can get/set any of the logging context properties/stacks. On the other hand, it seems that you HAVE to have a logger to do this (in the absence of a LogManager). One other shortcoming (at least to me) in Castle's implementation is that it looks like the logging context interfaces are only implemented on the "IExtendedLogger" interface, which I think is only implemented on the log4net and NLog abstractions. If you (as a user of Castle) should choose to inject IExtendedLogger, you are in good shape. You can have access to context info. If you inject ILogger, you don't have access to context info. If the only abstractions that implement IExtendedLogger are the log4net and NLog abstractions, then you can only use those abstractions if you inject IExtendedLogger. Maybe you want to use one of their other built-in abstractions (like Console) or the one that is based on TraceSources (which, BTW, provides some hierarchical logger capability). However, since none of these logging abstractions support IExtendedLogger (only log4net and NLog abstractions support it), you cannot use any of them (without changing your app code to depend on ILogger rather than IExtendedLogger). Anyway, that may or may not be that important. So, if at the beginning of your program you want to set some global properties (like product version, app start time, whatever), you probably cannot set them without first getting (or having injected) a logger. Maybe this is not a big deal, maybe it is. With log4net you could do something like this: log4net.GlobalContextProperties["Version"] = GetProductVersion(); log4net.GlobalContextProperties["StartTime"] = DateTime.Now; With Castle, assuming you have a logger handy, you could do something like this: logger.GlobalContextProperties["Version"] = GetProductVersion(); logger.GlobalContextProperties["StartTime"] = DateTime.Now(); It seems useful to me to be able to set the various context properties without first getting a logger. Maybe something like this: LogManager.GlobalContextProperties["Version"] = GetProductVersion(); LogManager.GlobalContextProperties["StartTime"] = DateTime.Now(); Since the LogManager.Adapter IS the implementation of the logging abstraction over a specific logging framework, the Common.Logging LogManager could delegate to the ILoggerFactoryAdapter to do the work. This is nice because the LogManager is always available so it would be easy for anyone to set logging context information at any time. On the other hand, does this make it awkward for people that want to implement Adapters and Loggers but might not have the concept of logging context? What if someone wants to make a logging abstraction over System.Diagnostics (using TraceSources)? System.Diagnostics has the Trace.CorrelationManager.LogicalOperationStack that seems to correspond pretty well to ThreadContextStack, but it does not have things that correspond very well to GlobalContextProperties or ThreadContextProperties (at least not explicitly exposed as such from Trace). Does it matter? If someone writes a logging abstraction that can be plugged into Common.Logging and the logging system that they are abstracting does not have context information, they could just not implement any or all of the context interfaces. The default implementation (provided by Common.Logging) could just return a "do nothing" implementation (like NullLogger), so that any code written against Common.Logging interfaces does not have to worry that "GlobalContextProperties" might be null. Alternatively (and obviously more work), Common.Logging could provide an implementation of each type of context (global properties, thread local properties, thread local stack). Might be nice, but probably overkill unless there is a demand for it. It seems like it wouldn't be that hard to implement if someone really wanted to do it. |