I think we have done what you want, plus a little bit. I have an
Interface
public interface IKmsTraceLog: ILog
{
void Alert (System.Exception ex);
void Alert (string message);
void Alert (string message, System.Exception ex);
void Alert (object target);
void Alert (object target, System.Exception ex);
void Alert (object target, string message);
void Alert (object target, string message,
System.Exception ex);
void Alert (object target, string format, object
param1);
void Alert (object target, string format, params
object[] paramList);
bool IsAlertEnabled
{
get;
}
.... repeat above for each 'level' of trace wanted such as trace,
debug, warn etc)
}
It is implemented as
public class KmsTraceLogImpl: log4net.Core.LogImpl, IKmsTraceLog
{
public void Alert (System.Exception ex)
{
LogItWithCheck(Level.Alert, null, ex, null);
} /* method KmsTraceLogImpl Alert */
public void Alert (string message)
{
LogItWithCheck(Level.Alert, message, null,
null);
} /* method KmsTraceLogImpl Alert */
public void Alert (string message, System.Exception ex)
{
LogItWithCheck(Level.Alert, message, ex, null);
} /* method KmsTraceLogImpl Alert */
public void Alert (object target)
{
LogItWithCheck(Level.Alert, null, null, target);
} /* method KmsTraceLogImpl Alert */
public void Alert (object target, System.Exception ex)
{
LogItWithCheck(Level.Alert, null, ex, target);
} /* method KmsTraceLogImpl Alert */
public void Alert (object target, string message)
{
LogItWithCheck(Level.Alert, message, null,
target);
} /* method KmsTraceLogImpl Alert */
public void Alert (object target, string message,
System.Exception ex)
{
LogItWithCheck(Level.Alert, message, ex,
target);
} /* method KmsTraceLogImpl Alert */
public void Alert (object target, string format, object
param1)
{
if (IsAlertEnabled)
LogItNoCheck(Level.Alert,
string.Format(FormatterInstance, format, param1), null, target);
} /* method KmsTraceLogImpl Alert */
public void Alert (object target, string format, params
object[] paramList)
{
if (IsAlertEnabled)
LogItNoCheck(Level.Alert,
string.Format(FormatterInstance, format, paramList), null, target);
} /* method KmsTraceLogImpl Alert */
public bool IsAlertEnabled
{
get
{
return
Logger.IsEnabledFor(log4net.Core.Level.Alert);
}
} /* property KmsTraceLogImpl
IsAlertEnabled */}
... repeats for other levels
/// two helper methods used by each of the above routines.
private void LogItNoCheck (Level logLevel, object
message, Exception ex, object target)
{
LoggingEvent le;
le = new LoggingEvent(my_type,
this.Logger.Repository, this.Logger.Name, logLevel, message, ex);
if (target != null)
le.Properties["instance"] =
target.ToString();
Logger.Log(le);
} /* method KmsTraceLogUtil LogItNoCheck
*/
/// <summary>
/// Internal log method. All externally visible trace/verbose should go
through here.
/// </summary>
/// <param name="level">The level of the message to be logged.</param>
/// <param name="message">The message object to log.</param>
/// <param name="t">the exception to log, including its stack trace.
Pass <c>null</c> to not log an exception.</param>
/// <remarks>
/// Generates a logging event for the specified <paramref name="level"/>
using
/// the <paramref name="message"/> and <paramref name="t"/>.
/// <para>Code is duplicated from LogItNoCheck for performance
reasons</para>
/// </remarks>
private void LogItWithCheck (Level level, object message, Exception ex,
object target)
{
LoggingEvent le;
if (Logger.IsEnabledFor(level))
{
le = new LoggingEvent(my_type, this.Logger.Repository,
this.Logger.Name, level, message, ex);
if (target != null)
le.Properties["instance"] = target.ToString();
Logger.Log(le);
}
}
}
Then to use this each class that need unique trace info has a static
member such as
static private KMS.Core.Log4Net.KmsLogger LogTrace =
KMS.Core.Log4Net.LoggerManager.GetLogger(System.Reflection.MethodBase.Ge
tCurrentMethod().DeclaringType);
Sometime I even define a virtual method called LogTrace with a get
accessor in a base class that has overriding classes. Then each class
in the tree gets its own static instance of KmsLogger that is returned
by the property so that the correct class, not the base class shows in
the trace.
Then the calls to log4Net are done as
LogrTrace.Alert(this,"string and format info",p1,p2,p3...):
Where of course Alert could be Trace, Debug Warn etc.
This results in an output that looks like with the Full Qualified class
name and method name inserted into the trace. In the example below, I
have the Day, Time Threadid class name and finally my text "- Entered".
Of couse the formatting is done via the config as normal.
27 14:11:57.916 [ServiceThread]
KMS.CertMinder.Service.CertMinderService::OnStart - Entered
One note, is that doing all this does not meet your 2nd requirement of
removing the references to log4Net from the calling projects. They
still care.
----------------------------------------------------------------------
Roy Chastain
-----Original Message-----
From: xalex [mailto:[email protected]]
Sent: Tuesday, July 21, 2009 1:40 AM
To: [email protected]
Subject: RE: Wrapping Log4Net
Hi James,
yes, this works of course, but there are 2 drawbacks: you need to
request the logger to the type for every single call. Instead of doing
so, i would like to instanciate as static variable per type only once
like this:
private static readonly ILog logger =
LogManager.GetLogger(typeof(Program));
The second (little) drawback is, that you have to provide the type for
every call.
I have a question: the call to the logger itself is done by your wrapper
code. How did you solve the problem, that the log4net.LocationInfo is
wrong in the logfile? I think also in your case the class, sourcefile
and line will be printed out of your wrapper and not the location of the
application code, right?
best regards
Alex
James Green-5 wrote:
>
> Hi,
>
> Despite what you have been told already I have wrapped log4net, if you
> do it right it is fine imho.
>
> I wrapped log4net since we need to consume it in scenarios where we
> absoloutely cannot have a plethora of config files kicking around all
> the time simply to enable some logging in the consuming components.
>
> For instance, what if you want to log from an SSIS pipeline? You
> absolutely do not want to generate dependencies on config files in
> such situations. This is also why I had a nightmare of a time getting
> log4net configured using pure C# because it just doesn't seem to be
> done all that often so isn't documented (I'm working on some docs for
> that scenario to share).
>
> The way I got around the log source problem was to use method
> signatures like this on my wrapper class:
>
> Log.Debug(Type sender, string message)
>
> Then inside the wrapper it is a simple task to request the ILog from
> log4net using the Type parameter, no need to walk the stack.
>
> Works for us anyway ...
>
> Cheers,
>
> James.
>
> -----Original Message-----
> From: xalex [mailto:[email protected]]
> Sent: 18 July 2009 21:54
> To: [email protected]
> Subject: Wrapping Log4Net
>
>
> Hi forum,
>
> I would like to use log4net in a large .net development. because i
> have the requirement to prepare a potential replacement of the log4net
> framework e.g.
> against ms-enterprise library or against a newer version of log4net, i
> would like to wrap this. My way to do it is straight forward:
> A single assembly references the log4net framework, offes the ILog and
> LogManager classes, and all other projects reference only this wrapper
> (see below).
>
> This wrapper allows me to restrict the users on only the main
> functions which are really needed and allows me to replace this
> framework, potentially.
>
> Now my question: When the ILog.Debug() Method is called, the output in
> the logfile is wrong, because the LocationInfo used for this output
> corresponds to the Wrapper and not to the code from which it is really
> called :-(
>
> A: Is there an easy way to fix this problem?
> B: Is there a better idea to wrap log4net
> C: Is it true, that logging is only possible in DEBUG-Builds? When
> using the release build, i dont get any output
>
> Thanks
> Alex
>
>
>
> Wrapper:
> ------------
> public interface ILog
> {
> bool IsDebugEnabled { get; }
> bool IsErrorEnabled { get; }
> bool IsFatalEnabled { get; }
> bool IsInfoEnabled { get; }
> bool IsWarnEnabled { get; }
>
> void Debug(object message);
> void Error(object message);
> void Fatal(object message);
> void Info(object message);
> void Warn(object message);
> }
>
> public static class LogManager
> {
> static LogManager()
> {
> XmlConfigurator.Configure( new
> System.IO.FileInfo("c:/logger.xml")) ;
> }
>
> public static ILog GetLogger(Type type)
> {
> MyLog log = new MyLog(log4net.LogManager.GetLogger(type)
);
> return log;
> }
> }
>
> public class MyLog :ILog
> {
> private log4net.ILog _log;
>
> public MyLog(log4net.ILog log)
> {
> _log = log;
> }
>
> #region ILog Members
>
> public bool IsDebugEnabled
> {
> get { return _log.IsDebugEnabled; }
> }
>
>
> public void Debug(object message)
> {
> _log.Debug(message);
> }
>
> ...
> }
>
> --
> View this message in context:
> http://www.nabble.com/Wrapping-Log4Net-tp24551728p24551728.html
> Sent from the Log4net - Users mailing list archive at Nabble.com.
>
>
> scanned by MessageLabs [www.messagelabs.com]
>
>
>
>
--
View this message in context:
http://www.nabble.com/Wrapping-Log4Net-tp24551728p24581996.html
Sent from the Log4net - Users mailing list archive at Nabble.com.