|
From: Geoghegan, W. A (Willie) <wil...@in...> - 2010-09-21 21:30:53
|
Part 2
Finally, FWIW, I think the Castle approach of having the logging context
interfaces available from their logger interface is reasonable, given
that users of Castle probably only have access to a logger interface
(probably no LogManager).
Given that Common.Logging exposes LogManager, it seems reasonable that
the logging context properties might be available through LogManager
(and provided, ultimately, by the implementation of
ILoggerFactoryAdapter). It seems like it would be ok to expose the
properties via the ILog interface as well, but probably not necessary if
already exposed via LogManager. Any logging system that is exposed
through Common.Logging (either implemented by Common.Logging or by
someone else and plugged into Common.Logging) should expose at least a
"do nothing" implemention (like NullLogger) so that code that requests
to set/get a logging context gets an actual object rather than a null.
LogManager could expose something like this:
IContextProperties GlobalContextProperties
{
get
{
IContextProperties prop = _adapter.GlobalContextProperties;
if (prop == null)
{
return new NullContextProperties(); //Maybe cache this or have a
single static version
}
else
{
return prop;
}
}
}
Similarly for ThreadContextProperties and ThreadContextStack.
The AbstractSimpleFactoryAdapter or AbstractCachingFactoryAdapter can
provide default implementations of these properties. The default
implementation just returns an implementation of the interface that does
not actually allow for setting/getting properties. This solves the
problem of getting a null object if an adapter does not support these
properties. Log4net and NLog factory adapters would return
implementations of the interfaces that actually delegate down to the
corresponding log4net or NLog context properties (a la Castle). If
someone wanted to write a TraceSource-based abstraction, they could
provide an implementation of the ThreadContextStack that delegates to
Trace.CorrelationManager.StartLogicalOperation/StopLogicalOperation
(maybe that would work, maybe not), but might choose to not implement
either of the context properties interfaces since System.Diagnostics
does not necessarily have functionality that corresponds directly.
By providing default (if dumb) implementations of these properties in
AbstractSimpleFactoryAdapter and/or AbstractCachingFactoryAdapter,
Common.Logging allows existing Common.Logging plugins to still work
without any code modification.
Finally, regarding Silverlight support ... Will the Common.Logging
codebase be modified such that LogManager can be created and used within
a Silverlight app? Will I able to add a reference to Common.Logging (or
maybe to something like Common.Logging.Silverlight) to a Silverlight
project, configure it (programmatically), and then log? Something like
this:
LogManager.Adapter = new
SilverlightDebuggerLoggerFactoryAdapter(LogLevel.Info);
ILog logger = LogManager.GetCurrentClassLogger();
logger.Info("Hello from Silverlight!");
Or like this:
//LoggingService could be a WCF service implemented by me, along with
corresponding adapter and logger
LogManager.Adapter = new
LoggingServiceLoggerFactoryAdapter(LogLevel.Info, <parameters to connect
to LoggingService>);
ILog logger = LogManager.GetCurrentClassLogger();
logger.Info("Hello from Silverlight via LoggingService!");
If possible, could someone from Common.Logging respond to this email
with some information as to how and when you expect to support logging
contexts and Silverlight? I don't think that it is critical for our
project that we have logging context support NOW, but it would be useful
to have some timeframe and some idea of your approach so that, if we
need it and it won't be available in our timeframe, that we could
implement something that would at least be close to the expected
Common.Logging implementation. We will be doing a lot of Silverlight,
so Silverlight support will be important.
Note that I added an issue to the tracker regarding adding a "Log"
method (maybe overloaded, maybe not) to the ILog interface. The method
should be similar to the Log method provided by log4net and NLog in that
it would accept a "LogEvent" structure, similar to LogEventInfo or
LoggingEvent. The usage that I had in mind for this would be the
implementation of a LoggingService (WCF or other similar service) that
would accept fully formed logging events from some remote client or
service. So, a client-based logger (say a
LoggingServiceLoggerFactoryAdapter/LoggingServiceLogger) would construct
LogEvent classes/structures in the WriteInternal method:
protected override void WriteInternal(LogLevel level, object message,
Exception ex)
{
//Create a LoggingServiceEvent to send to the LoggingService
LoggingServiceEvent lse = new LoggingServiceEvent(DateTime.Now, level,
LoggerName(), message, ex, <maybe some context info in a dictionary>);
_loggingService.SendLogMessage(lse); //Send via WCF to LoggingService
}
(Note that in order to create a "LoggingServiceEvent" the Name of the
logger instance is probably useful, if no required. Therefore, could
Name be available either from ILog interface or could the logger name be
made available for logger implementers via the AbstractLogger and/or
AbstractSimpleLogger.)
Inside of a LoggingService (that is implemented in terms of
Common.Logging):
public void SendLogMessage(LoggingServiceEvent lse)
{
//Take LoggingServiceEvent, convert to Common.Logging.LogEvent, log
via Common.Logging.ILog
ILog logger = LogManager.GetLogger(le.LoggerName);
LogEvent le = ConvertLoggingServiceEventToCommonLoggingLogEvent(lse);
logger.Log(le);
}
Thanks.
Looking forward to a response.
Willie Geoghegan.
|