I have written a wrapper (Custom Logger class) around TraceSource class to have more control over the way other developers will use this custom Logger and log data/messages at various levels.
Below is the code with implementation just for verbose, error and info levels.
public class Logger : ILogger
{
private const int DEF_ERROR_EVENT_ID = 2;
private const int DEF_INFORMATION_EVENT_ID = 4;
private const int DEF_DEBUG_EVENT_ID = 5;
private static TraceSource source = null;
public Logger(string nameOfComponent)
{
source = new TraceSource(nameOfComponent);
}
public void LogDebug(Type type, string methodName)
{
if (type!=null)
throw new ArgumentNullException(type.ToString());
source.TraceEvent(TraceEventType.Verbose, DEF_DEBUG_EVENT_ID, string.Format("{0}.{1}",type.ToString(),methodName));
}
public void LogError(string message, Exception ex)
{
if (String.IsNullOrEmpty(message) && ex == null)
throw new ArgumentNullException(message, ex.ToString());
source.TraceData(TraceEventType.Error, DEF_ERROR_EVENT_ID, message, ex);
}
public void LogInformation(string message)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentNullException(message);
source.TraceInformation(message);
}
}
I'm initializing a static variable "source" in the Logger class' non-default constructor (given the fact that this code is going to run in a multi-threaded environment) is this practice fine in terms of thread-safety ? Though MSDN documentation says that TraceSource is thread-safe and various methods such as TraceSource.TraceData(),TraceSource.TraceEvent() etc. also take thread-safety into consideration around all the trace listeners writing out trace logs.Since I'm planning to instantiate Logger class individually across each class in my web app as below.
private ILogger log = new Logger("name of the source/class");
What would the best way to do so in a multi-threaded environment? Will using a DI container like Ninject or Autofac make Logger class thread-safe or shall I create a singleton and use it or reuse it across the entire app to make it thread-safe. The problem that I'm facing if I create a singleton instance of Logger class is that I won't be able to pass a string as parameter to Logger class' non-default constructor and eventually the same string to TraceSource class to know the name of the source or component on the run or on the fly.
Some of you might say why am I re-inventing the wheels and creating a wrapper around TraceSource rather than using TraceSource directly as such. But as mentioned in the beginning of my question is that I want to have more control over what is being sent as a log to a file or database.
I can't comment yet- so would have asked why you're creating a custom logger rather than using NLog. If you did this then static log instances in NLog are threadsafe:
private static Logger logger = LogManager.GetLogger("MyClassName");
Because loggers are thread-safe, you can simply create the logger once and store it in a static variable.
See more here: https://github.com/NLog/NLog/wiki/Tutorial
Nlog is highly configurable, and appears to be fit for purpose for the use case you described.
HTH
Related
I am implementing a custom XML formatter for log4.net
public class ISDSApplicationEventsLayout : XmlLayoutBase
{
protected override void FormatXml(...)
{
//Location Info
writer.WriteStartElement("Method");
writer.WriteString(**loggingEvent.LocationInformation.MethodName * *);
writer.WriteEndElement();
}
}
The problem is ... now when I call log method from my log wrapper class... called logging
public static void logEvent(string message)
{
log.Info(isdsLog);
}
I get the output....
<Method>logEvent</Method>
How is it possible to have the method name that called logEvent, rather than logEvent as the method name?
Thank you
Question Update:
If this above seems a bit complicated - what I am really asking is : How do you keep the context of the method that called the wrapping logging function in log4net...
example... method doWork()... calls -> logging wrapper --> calls log4net....
How do you make the methodname = doWork and NOT logging wrapper function....
Actually, you can fix this easily with out-of-the-box log4net. Your wrapper can call Logger.Log and pass the type of your wrapper class as the first parameter. So, your wrapper might look something like this:
public class MyLog4NetWrapper
{
ILog log = LogManager.GetLogger("WhateverYourLoggerNameIs");
public void logEvent(string message)
{
log.Logger.Log(typeof(MyLog4NetWrapper), LogLevel.Info, message, null);
}
}
When log4net logs a message, it traverses up the call stack until it gets to the method whose declaring type is equal to the type passed in as the first parameter of the Log method. The next method up the stack is the actual call site.
As far as wrapping the log4net logger, I'm not sure that I would recommend creating a static wrapper class. The main problem with that is that you can only have a single configurable logger in your app.config file. In other words, you won't be able to independently control the logging from different parts of your code. If you have class A and class B and both use your static wrapped logger, then both classes will log at the same level. If you wanted to turn logging on for class A and off for class B, you would not be able to do so.
I don't think you can easily fix this with out-of-the-box log4net. If we take a look at the ILog.Info method in the LogImpl class, that you are calling:
virtual public void Info(object message)
{
Logger.Log(ThisDeclaringType, m_levelInfo, message, null);
}
When a message is logged, log4net will walk the stacktrace of the current call in order to find the method that initiated the log operation. To do this Log4net uses the "ThisDeclaringType" type as the boundary of the search, the first call "above" calls within that type is chosen as the initiating method.
In your case, the first method encountered is the logEvent method. If you dropped the logEvent wrapper and used the logging methods directly you will get the desired information.
Wraper for log4net logger in 3 steps:
Add reference to log4net package( NugetPackage)
add your wrapper class , ensure to call log4net.Config.XmlConfigurator.Configure(); in static constructor of your wrapper class. This loads all configuration from your app.config .
add log4net configuration in your app.config
See the sample wrapper class below below.
public class Logger : ILogger
{
private static readonly log4net.ILog log;
static Logger()
{
log = log4net.LogManager.GetLogger(System.Reflection.MethodInfo.GetCurrentMethod().DeclaringType);
log4net.Config.XmlConfigurator.Configure();
}
public void Log(LogLevel logLevel, string message, params object[] args)
{
switch (logLevel)
{
case LogLevel.DEBUG: {
// log.Logger.Log helps logging actual method and the class which has called this method (Log(LogLevel logLevel, string message, params object[] args))
log.Logger.Log(typeof(Logger), log4net.Core.Level.Debug, string.Format(message, args), null);
break;
}
case LogLevel.INFO:
{
log.Logger.Log(typeof(Logger), log4net.Core.Level.Info, string.Format( message, args) , null);
break;
}
case LogLevel.ERROR:
{
log.Logger.Log(typeof(Logger), log4net.Core.Level.Error, string.Format(message, args), null);
break;
}
case LogLevel.WARN:
{
log.Logger.Log(typeof(Logger), log4net.Core.Level.Warn, string.Format(message, args), null);
break;
}
}
}
public void LogException(LogLevel logLevel, Exception exception)
{
Log(logLevel, exception.ToString());
}
}
I have a class named MyClass, which uses two different loggers named Logger1 and Logger2. I use log4net for logging, and want to use StructureMap for DI.
Without StructureMap, my class would look like this:
public class MyClass
{
private static readonly ILog Logger1 = LogManager.GetLogger("Logger1"); // Loggers are configured in a config file
private static readonly ILog Logger2 = LogManager.GetLogger("Logger2");
public void DoSomething()
{
...
Logger1.Info("did something");
...
Logger2.Info("need to log this elsewhere");
}
}
Introducing DI, with StructureMap (using v3.0.3), I would make the loggers instance members, and inject them into the constructor, like this:
public class MyClass
{
private readonly ILog Logger1;
private readonly ILog Logger2;
myClass(ILog logger1, ILog logger2)
{
this.Logger1 = logger1;
this.Logger2 = logger2;
}
public void DoSomething()
{
...
Logger1.Info("did something");
...
Logger2.Info("need to log this elsewhere");
}
}
The thing is, I cannot get StructureMap to wire this up for me properly. I tried wiring the loggers like this:
For<ILog>.Use(()=> LogManager.GetLogger("Logger1")).Named("Logger1");
For<ILog>.Use(()=> LogManager.GetLogger("Logger2")).Named("Logger2");
Doing this Gets me empty (unconfigured) loggers). Replacing Use() with Add() gives my an exception due to not having a default instance registered for ILog.
Does anybody know how I can do this?
If the loggers perform different roles then I would create two interfaces inheriting from ILog to reflect this. That way you would have no problem configuring StructureMap to handle them.
I ended up doing the following: I created two interfaces as per Rob's advice: ILogger1 and ILogger2. Since the both have the same API, as I need the same kind of functionality from them, they both inherit from the same interface - though not log4net.ILog as per Steven's advice:
interface IMyLog
{
void Info(object message);
void Info(string format, params object[] args);
}
interface ILogger1 : IMyLog { }
interface ILogger2 : IMyLog { }
Also, since the implementation of this API is the same for my needs, I have one concrete class MyLogger, implementing both ILogger1 and ILogger2. If I ever need the implementations to be different it will be easy for me to have explicit interface implementation, or separate classes. Only My Logger takes a dependency on log4net, as it uses it for its implementation:
enum LoggerType { Logger1, Logger2 }
internal class MyLogger : ILogger1, ILogger2
{
private readonly ILog _log;
public MyLogger(LoggerType loggerName)
{
switch (loggerName)
{
case LoggerType.Logger1:
_log = LogManager.GetLogger("first-log");
break;
case LoggerType.Logger2:
_log = LogManager.GetLogger("second-log");
break;
default:
throw new ArgumentException("Invalid logger name", "loggerName");
}
}
public void Info(object message)
{
_log.Info(message);
}
public void Info(string format, params object[] args)
{
_log.InfoFormat(format, args);
}
}
In order to register it with StructureMap, I used the following code in the registry:
For<ILogger1>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger1).Singleton(); // I want only one logger per type
For<ILogger2>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger2).Singleton();
It all works wonderfully. So, thanks to Steven and Rob for their advice. I really learned something. I wish I could upvote an answer and a response more than once.
So, to summarize, I:
Created a separate interface for each kind of logger (even saying it now sounds intuitive).
Created a base interface for the logger interfaces, because for my needs they have the same API (YMMV)
Created one concrete logger adapter that implements both interfaces because that suits my needs (YMMV again)
Share the implementation of the interfaces' API, for the above reasons
Registered each interface to create a concrete logger with a different type passed in the constructor
configured the concrete logger with log4net using a Factory Method to determine which logger to use
As an alterative to the answers above, this can be solved exclusively in StructureMap (and I believe works for the SM version used in the question). You can tell StructureMap exactly how to build MyClass by also including the following in a Registry.
For<MyClass>().Use(x => new MyClass(x.GetInstance<ILog>("Logger1"), x.GetInstance<ILog>("Logger2")));
I have done a lot of reading on instance vs. static classes and have not found an answer to my question. Are there any perils to instancing a different class in a static class that was referenced by an instance class?
The current design I am working with is one in which instance classes call a static "Logger" method (passing a series of parameters) to log errors to a text file in the file system. I am refactoring the static "Logger" method to instantiate a parameter class (which is just a series of properties and a few helper methods to return itself as XML or a string) and a DBLogger class to log the error to the database rather than the file system, passing the parameter class as the sole parameter.
This model worked well in my legacy VB6 code, in which the Logger class was instanced, not static.
But now in the .NET code I am not sure if I should make my 2 new classes (parameter and DBLogger) static, or just make the DBLogger static and instance the parameter class. I am concerned about the potential for concurrency/multi-thread data issues with (or without) instances being created from a static class. Am I right to be concerned or am I worrying about nothing?
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
// all code truncated for illustration purposes
namespace ThisIs.A.Test
{
//INSTANCE
public class ErrorLogParameters
{
private int mThreadId = 0;
private int mErrorNumber = 0;
private string mServerDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
public int ThreadId
{
get { return mThreadId; }
set { mThreadId = value; }
}
public int ErrorNumber
{
get { return mErrorNumber; }
set { mErrorNumber = value; }
}
public string ServerDate
{
get { return mServerDate; }
}
}
//INSTANCE
public class ErrorLog
{
public void LogErrorToDatabase(ErrorLogParameters criteria)
{
//Log error to database here
}
}
//STATIC - Instantiates INSTANCE of ErrorLogParameters and ErrorLog
public class Logger
{
public static void WriteLog(string pstrObjectName, string pstrProcedureName, int plngErrNumber, string pstrErrDescription)
{
// create a new parameter object
ErrorLogParameters objParameters = new ErrorLogParameters();
// populate object properties
objParameters.ErrorNumber = mlngErrNumber;
objParameters.ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
ErrorLog objErrorLog = new ErrorLog();
objErrorLog.LogErrorToDatabase(objParameters);
}
}
//INSTANCE - Invokes STATIC method
public class SomeInstance
{
private void ErrorHandler_Log(Exception exception, string procedureName, string additonalDescription, string stackTrace)
{
// call from instance class to static class
Logger.WriteLog(mstrObjectName, procedureName, mlngErrNumber, mstrErrDescription);
}
}
}
No, that's absolutely fine - if you're creating an instance of any class within a method, it doesn't matter whether the class declaring that method is a static class or not.
Furthermore, unless you've got something "special" (e.g. a static variable counting the number of instances created) you're less likely to run into concurrency issues when creating new objects than when using existing objects. Basically, the tricky part of almost all concurrency is working out where mutable data is shared - it doesn't sound like you've got any here (although sample code would help to clarify that).
I would use a combination of the provider and singleton pattern for this.
Create an abstract class called Logger.
The Logger class contains abstract methods for writing to log. For example:
abstract void LogInfo(LogInfo info);
abstract void LogError(Exception exception);
etc
The Logger class contains a private instance of Logger object.
The Logger class contains a static property that returns the private instance.
The Logger class contains a static constructor that instantiate the private instance of Logger object. You would probably use Reflection and instantiate the object based on the configuration.
Implement a FileLogger that inherits from the Logger object. This logger writes to a file.
Implement a SQLLogger that inherits from the Logger object. This logger writes to a database.
Call the logger like so:
Logger.Instance.WriteInfo(info);
Logger.Instance.WriteError(exception);
There are a few advantages of using this design:
Your logging functionality is fully abstracted. This completely decouple the logging callers from the code that writes the logs. This allows you to write the log to any data stores.
You can change which logger to use without compiling the code. Just update the config file.
Singleton guarantees thread-safety
Testability. You can write Mock tests against abstract classes.
Hope this helps.
There are no concurrency issues with static methods.
Static variables are a different matter.
I currently have a class written in C# which does some simple error logging stuff. It's been used quite extensively throughout my project.
class LogError
{
//constructor
public LogError() { }
//public methods
public void saveToTextFile() { }
//other similar methods...
}
But, it doesn't seems a good design of this class, as every time I have to create an instance of LogError class before saveToTextFile() method can be used.
So I am thinking of re-designing this class. Would this be a good case to apply Singleton pattern? What about making it static class instead? Any suggestions? Thanks.
The problem with Singleton is that it's hard to use different logging behaviour. Image you want to introduce a "Send an email instead of write to text file" later. It's basically the same if you have
new LogError().DoSomething();
or
LogError.Instance.DoSomething();
except for performance and/or implementation of the LogError class itself.
If you want to add flexibility, you'd better use Dependency Injection (which makes your code clearer than with the Singleton, in addition) or Dependency Lookup (which is somewhere in between).
I would look at Apache log4net. You don't have to worry about anything. You can configure it to log to multiple targets from your configuration file (or in code). The log message template is fully customizable. You can filter and route different log levels (debug/info/warning/error). It's really not worth reinventing the wheel here.
Yes make it singleton and also thread safe
If you are using , any container ( Autofac, Unity etc) then you can make use of the container.
Singleton can be broken ( By using Reflection so be informed )
one of the implementation would be ( this would not required explicit locking )
public class MySingleton
{
private static readonly MySingleton _singtonInstance = new MySingleton();
private MySingleton()
{
}
public static MySingleton SingtonInstance
{
get { return _singtonInstance; }
}
}
You can use interface as your log system facade, like
interface ILoggerFacade{
void Error(Exception e);
void Warning(Exception e);
....
}
after that you need to make interface implementation
class SimpleLogger:ILoggerFacade{
void Error(Exception e){//logging error};
...
}
and finnaly you need enter point to your logger. I ussually use static class but singleton is variant also.
static class sample:
class StaticLogger{
private ILoggerFacade _logger;
StaticLogger(){
//choose ILoggerFacade implementation
_logger=new SimpleLogger();
}
public static ILoggerFacade Logger{
get{ return _logger;}
}
}
If you will use facade interface you can easy change loggers in your project if it will be need.
There is a solution where you have a logging method that is being called once there are exceptions happen anywhere in your application. All you need to have is a general or common exception handler. Here's how.
On your Program.cs (inside your Main() method before the Application.Run) add this code.
Application.ThreadException += CommonExceptionHandler;
Create CommonExceptionHandler event on your Program.cs file let's say next to Main method.
private static void CommonExceptionHandler(object sender, ThreadExceptionEventArgs t)
{
LogError(t.Exception);
}
Create LogError Method on your Program.cs
public static void LogError(Exception ex)
{
var errMsg = ex.Message;
errMsg += ex.InnerException != null ? ex.InnerException.Message : string.Empty;
//TODO: Do what you want if an error occurs
}
This will catch all exceptions occur in your application. You don't need to worry anymore whether you would call your error log class for every catch block in all of your methods
I have integrated log4net in my app. I have a few helper methods to assist in logging which call log4net. When refactoring, I plan to move these methods to base class so that the code is not repeated in other derived classes.
Without the inheritance model, following worked correctly in each class
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Placing the above in the base class will return the declaring type as base class and not derived class.
What is an optimal way to move this declaration to the base class?
At present, I can think of a few ways to achieve this but don't find them optimal.
I think I would do this:
LogManager.GetLogger(this.GetType());
Based on Sefan's answer here's how I declared it in the base class
/// <summary>
/// This is delay loaded to allow us to capture the class type of the inherited class on request
/// </summary>
private ILog log = null;
protected ILog Log
{
get
{
if (log == null)
{
log = LogManager.GetLogger(this.GetType());
}
return log;
}
}
We just redeclare it in each class that needs a logger (the point of it being a private static) and use a code snippet to make that as simple as typing log<tab><tab> if you wanted to get extra fancy though you could do something like:
public class Loggable<T> where T : Loggable<T>
{
private static readonly ILog log = LogManager.GetLogger(typeof(T));
protected static ILog Log
{
get
{
return log;
}
}
}
And punch T through your inheritance hierarchy so that it is the most derived class.
The problem with all of the answers here is that you lose information about where log messages are coming from, so I would personally stick to your original code despite the added boilerplate.