class LogUtil<T> : ILogUtility
{
log4net.ILog log;
public LogUtil()
{
log = log4net.LogManager.GetLogger(typeof(T).FullName);
}
public void Log(LogType logtype, string message)
{
Console.WriteLine("logging coming from class {0} - message {1} " , typeof(T).FullName, message);
}
}
public class Logger
{
ILogUtility _logutility;
public Logger(ILogUtility logutility)
{
_logutility = logutility;
}
public void Log(LogType logtype, string message)
{
_logutility.Log(logtype, message);
}
}
I need to have the functionality to be flexible and have the ability to remove the LogUtil class in the future and use some thing else.
So I write LoggerUtility wrapper class as follows:
class LoggerUtility<T>
{
Logger logger;
public LoggerUtility()
{
LogUtil<T> logutil = new LogUtil<T>();
logger = new Logger(logutil);
}
public void Log(LogType logtype, string message)
{
logger.Log(logtype, message);
}
}
My client code as follows:
public class TestCode
{
public void test()
{
new LoggerUtility<TestCode>().Log(LogType.Info, "hello world");
}
}
To get loose coupling from LogUtil, I end up writing 2 wrapper classes Logger and LoggerUtility. So in the future, if I have to add another method
in the ILogUtility, I would have to add that method to Logger class and then LoggerUtility.
What is the best way to write LoggerUtility so that I could write the client code as follows:
new LoggerUtility<TestCode>().Log(LogType.Info, "hello world");
Please let me know.
Thanks
It looks like you're adding a level of abstraction where there really doesn't need to be one.
If we start with your end result, LoggerUtility just needs to have an interface that it can use to log things based on the LogType parameter.
Your Logger class, as its currently written, is just a thin wrapper around the ILogUtility interface. So why bother adding that layer? Why can't the Logger class use an ILogUtility instance directly? You could even go one step further and define your interface as ILogUtility<T> and know that when you create a LoggerUtility<Foo> that the instance of the logger it will use will be based on the Foo class.
But honestly, I think you may just be reinventing the wheel here. Take a look at Common Logging for .NET. It will probably ease what you're trying to do and make more sense in the long run.
You don't need a second wrapper, you need either a factory or to use a dependency injection framework to construct an appropriate wrapper around log4net.
Using Ninject, and modifying your interface, you can do
kernel.Bind(typeof(ILogUtility<>)).To(typeof(Log4NetUtil<>);
and instantiate it as
var logger = kernel.Get<ILogUtility<MyClass>>();
where the logger interface/class are:
public interface ILogUtility<T> where T : class
{
void Log(LogType logtype, string message);
}
public class Log4NetUtil<T> : ILogUtility<T> where T : class
{
log4net.ILog log;
public LogUtil()
{
log = log4net.LogManager.GetLogger(typeof(T).FullName);
}
public void Log(LogType logtype, string message)
{
Console.WriteLine("logging coming from class {0} - message {1} " , typeof(T).FullName, message);
}
}
Related
I'm trying to learn and understand interfaces, adapters, and dependency injection and how they can be used to achieve abstraction.
TLDR: How to change the way function\class uses the interface without changing said class\function's code?
I would also like it if you could point out errors in my thinking.
The Example:
Let's say I need to develop a logging mechanism (implement an ILogger interface) for some class (MoneyAdder) that I'm not allowed to modify. I also need to implement usage (please give me a correct term for this) of some other loggers via an adapter so we could choose the best way.
class MoneyAdder
{
private ILogger logger;
private Customer customer;
public MoneyAdder(ILogger logger, Customer customer)
{
this.logger = logger;
}
public void AddMoney(int amount)
{
logger.log("Doing work!");
customer.balance+=amount;
logger.log("I'm done!");
}
}
This is what I did at first:
public interface ILogger
{
void log(string str);
}
public class MyLogger : ILogger
{
public void log(string str)
{
Console.WriteLine($"LOG - {str}");
}
}
In this case, I have complete control over the interface definition, the class that implements it, and is able to use the log string that is given any way I want.
We know that OtherLogger requires a string and it's length to write a log. To use it I wrote an adapter like this:
public class OtherLogger
{
//We know it needs a string and its length for some reason.
public void log2(string str, int i);
}
public class OtherLoggerAdapter : ILogger
{
private OtherLogger ol = new OtherLogger();
public void log(string str)
{
ol.log2(str, str.Length);
}
}
This way I adapt the other dll to my interface. When the adapter is called I, in turn, call the different method name. I'm also able to provide an int it needs because it's computable from the input.
Now I need to add another logger that needs a log string and an assembly from which it was referenced. I'm able to provide it as well. It is not computable from the log string, but I'm able to give it any common information, like the environment variables or the program name because it is common for the program, MoneyAdder class, and StrangeLoggerAdapter.
public class StrangeLogger
{
public void logS(string str, System.Reflection.Assembly assembly);
}
public class StrangeLoggerAdapter : ILogger
{
private StrangeLogger sl = new StrangeLogger();
public void log(string str)
{
sl.logS(str, System.Reflection.Assembly.GetExecutingAssembly());
}
}
The final logger is an old mechanism that was used before. It was directly referenced and called inside MoneyAdder's other methods. (Tightly coupled, is this the correct term?). The logging method definition is as follows:
public class OldLogger
{
public void log(string str, string customerName);
}
It needs a customer name, but it is neither computable from the log string, nor it can be accessed from any adapter I can write. The only way to use it is to "inject" a customer name into a logger like this:
public interface ILogger
{
void log(string str);
void injectCustomer(string customerName);
}
And then to implement it in an adapter like this:
public class OldLoggerAdapter
{
private string customerName;
private OldLogger ol = new OldLogger();
public void injectCustomer(string customerName)
{
this.customerName = customerName;
}
public void log(string str)
{
ol.log(str, this.customerName);
}
}
However, to use the implementation I still need to modify (which I'm not allowed to do) either the MoneyAdder class or AddMoney method to use the injection function.
class MoneyAdder
{
private ILogger logger;
private Customer customer;
public MoneyAdder(ILogger logger, Customer customer)
{
this.logger = logger;
this.logger.injectCustomer(customer.Name);
}
public void AddMoney(int amount)
{
logger.log("Doing work!");
customer.balance+=amount;
logger.log("I'm done!");
}
}
The question:
To implement a logging function I can only use the information, that is either provided to the function via a method or can be computed from that information, or is global to the entire program.
There is no way to directly provide or inject information without modifying the calling function.
Or is there?
Is there a way, using some System\Reflexion\DI\IOC magic, to write something like:
Hey, MoneyAdder, It's an OldLogger that is currently used as ILogger. Whenever you call log(string str) you should actually call my method log(string str, string customerName). I know for sure you have a private property Customer that has a Customer.Name, use that in my log method as a "customerName".
I'm trying to write a logging class that would work like this:
Log.Info("Something happened");
Log.Error("Something else happened");
Log.Debug("Yet another thing happened!");
It should be accessible from every part of the namespace and quick to write, so I thought it'd be best to make it static. That way one can avoid having to create an object just to log a message.
At this point it is sort of like Console.WriteLine();
However, I wanted it also to be able to have two different modes: LogToConsole and LogToFile.
Thus the following syntax would be the most convenient:
LogConsole.Info("This will display in the console");
LogFile.Debug("This will be saved to a file");
LogAll.Error("This will be saved to a file AND displayed in a console");
However, I realized that there could be an large amount of "modes" multiplied by a very large amount of "logtypes".
How could I do this efficiently, in a way that I only have to write each logtype method once and depending on the derived class that calls the method, action a happens or action b happens?
Ideally I would like to define all methods once, and then create the classes that inherit them. But, since they are static methods their behavior is always the same. I can't tell them: "Find out what your superclass is and execute that class' SaveLog() method".
I realize that this would all be very very easy with abstract classes, but then I'd have to create objects.
Is there any way I could do this in C#?
Thanks!
Like Boo, would also recommend a logger like log4net.
If you do want to write it yourself, I would recommend against static methods as they would inhibit your ability to test the classes / methods that call it. Instead, inject your ILogger interface to all classes that might need logging. Then separate the "mode" from the target, so you can inject a list of targets to your logger.
public interface ILogTarget
{
void Save(string message);
}
public class LogToFile : ILogTarget
{
public void Save(string message)
{
//
}
}
public class LogToConsole : ILogTarget
{
public void Save(string message)
{
//
}
}
public interface ILogger
{
void Debug(string message);
}
public class Logger : ILogger
{
private readonly List<ILogTarget> _targets;
private static Logger _logger;
public Logger(List<ILogTarget> targets)
{
_targets = targets;
}
public void Debug(string message)
{
foreach (var target in _targets)
target.Save($"Debug: {message}");
}
}
public class TheClassThatMakesTheCall
{
private readonly ILogger _logger;
public TheClassThatMakesTheCall(ILogger logger)
{
_logger = logger;
}
public void AMethod()
{
_logger.Debug("some message");
}
}
//In your IoC, register Logger as a type of ILogger, and pass in the targets that you want
//If your target vary per situation, you'll need a ILogTarget factory that returns a different list of loggers based on the situation
You cannot inherit from static classes. But you can get away with making only the functions static. don't make the classes as static. Just make the functions as static, then you can use the "new" keyword in the derived class. It would be something like this
// IF this is your base class
public class Log
{
public static bool Info(string Message)
{
Console.WriteLine(Message + " From Log");
return true;
}
public static bool Success(string Message)
{
return true;
}
public static bool Error(string Message)
{
return true;
}
}
//Then this can be your derived class
public class LogFile : Log
{
public static new bool Info(string Message)
{
Console.WriteLine(Message + " From LogFile");
return true;
}
public static new bool Success(string Message)
{
return true;
}
public static new bool Error(string Message)
{
return true;
}
}
Hope this helps.
Using ASP.NET Core and implementing my own console logging provider with ILogging and ILoggingProvider as I want to pass the name of the calling function to the logger as part of the log record as well as date/time stamp.
The best way to retrieve the name of the calling function is to use [CallerMemberName] attribute in the function parameters, however as I'm trying to keep to the standard logging pattern and inheriting the ILogger interface I can't work out how to overload any of the Log method calls to use an additional function parameter to add the CallerMemberName attribute.
Here is the code in Main:
public class Program
{
static ILogger Logger { get; } = ApplicationLogging.CreateLogger<Program>();
public static void Main(string[] args)
{
ApplicationLogging.Logger.AddMyLogger();
Program.Logger.LogInformation("Test log");
...
}
}
Here is my custom logging provider
// Setup logging for all classes to use
public static class ApplicationLogging
{
public static ILoggerFactory Logger { get; } = new LoggerFactory();
public static ILogger CreateLogger<T>() =>
Logger.CreateLogger<T>();
}
public static class MyLoggerProviderExtensions
{
public static ILoggerFactory AddMyLogger(this ILoggerFactory loggerFactory)
{
loggerFactory.AddProvider(new MyLoggerProvider());
return loggerFactory;
}
}
public class MyLoggerProvider : ILoggerProvider
{
public MyLoggerProvider()
{
}
public ILogger CreateLogger(string categoryName)
{
return new MyLogger();
}
public void Dispose()
{
}
void IDisposable.Dispose()
{
throw new NotImplementedException();
}
}
public class MyLogger : ILogger
{
public MyLogger()
{
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
Console.WriteLine("{0,-12} {1,-20} {2}", DateTime.Now.ToString("HH:mm:ss.fff"), " [NEED_CALLING_METHOD_NAME_HERE]", state);
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
If I add CallerMemberName to the Log method call then I'm not implementing as per the interface and it won't compile (as expected). I tried adding a class scoped variable and to set up the calling member name when instantiating the logger but that won't capture correct calling member.
I'm fairly new to C# so I might be missing the best way to do this - the way I see it I have to overload the Log function to add the [CallerMemberName] attribute but the standard logging call semantics (eg. LogCritical) won't use my overloaded function.
Of course I could just ditch my custom logging provider and write my own logging function which would be simpler but won't leverage the logging infrastructure provided by Microsoft. I know I can use Reflection but I'd prefer not to take the extra CPU hit as this software will run on very low end hardware.
In the Log function:
public void Log()
{
var stackTrace = new System.Diagnostics.StackTrace(1); // skip one frame as this is the Log function frame
var name = stackTrace.GetFrame(0).GetMethod().Name;
}
EDIT:
If you want to avoid reflection maybe:
using (_logger.BeginScope("name of method"))
{
// log the stuff
}
Not sure about .Net Core but in normal .Net you could add this by using Aspect Oriented Programming to multiple methods fairly easy.
I am trying to break away direct dependency of NLog from my code. So if in the future i decided to use another logging library, it will be painless.
What I did is as following,
internal class Logger
{
private NLog.Logger _NLogInstance;
internal static Logger Instance
{
get
{
return new Logger();
}
}
public Logger()
{
LogManager.ReconfigExistingLoggers();
_NLogInstance = LogManager.GetCurrentClassLogger();
}
public void Trace(string message)
{
_NLogInstance.Trace(message);
}
public void Debug(string message)
{
_NLogInstance.Debug(message);
}
public void Info(string message)
{
_NLogInstance.Info(message);
}
public void Warn(string message)
{
_NLogInstance.Warn(message);
}
public void Error(Exception ex, string message)
{
_NLogInstance.Error(ex, message);
}
public void Fatal(Exception ex, string message)
{
_NLogInstance.Fatal(ex, message);
}
}
As you can see, to use my Logger one only need to do so,
Logger.Instance.Fatal(ex, ex.Message);
So, the real implementation of NLog is somehow hidden from the user of Logger. If tomorrow I need to use Log4net, i will only need to change my implementation in Logger class.
Is there any potential problem of doing so? Because I don't see people doing this anywhere. Or are there any better way?
I totally agree with the comments. You probably won't need to switch to another logging library and if you do, it's because the new library is so clever and works in another way, why you will need to change your abstraction anyway.
If you insist on wrapping you Common Logging .NET instead. It's an abstraction on top of pretty much all of the major logging frameworks. This way you don't need to write the abstraction yourself.
I have to use these two different class files across my application. How do I inherit those two class files in another class file?
This class file to writes an information log
Public class Log
{
Public void createLog()
{
}
}
This class file gets connection string
public class DataConnector
{
public void Connection()
{
}
}
I want to Inherit from those two classes in this class:
Public class FileOperation
{
public void FileWiter
{
}
}
Are there any different ways to access the class files across my project?
What I have tried:
Public class FileOperation
{
Log oLog=new Log();
DataConnector oDataconn=new DataConnector();
public void FileWiter
{
oLog.createLog();
}
}
Yes, I can use that method, but I'm looking for any other best ways to do this?
Basically, there is nothing wrong with your approach. There is even an OOP Design Principle called composition over inheritance, which calls for this way of doing it.
Think about DataConnector, does you FileWriter really specialize some kind of DataConnector?
What I would recommend though would be hiding your dependencies behind interfaces and injecting them via the constructor of FileOperation like so:
public class FileOperation
{
ILog log;
IDataConnector dataConnector;
public FileOperation(ILog log, IDataConnector dataConnector)
{
this.log = log;
this.dataConnector = dataConncetor;
}
public void FileWiter
{
this.log.createLog();
}
}
This way you could easily swap one or both of those dependecies by simply passing another object which implements the right interface. For example, you could create a MongoDbDataConnector which implements IDataConnector and pass this one instead of a MsSqlDataConnector or a PostgreSqlDataConnector.
There is no reason why your FileOperation should inherit from either Log nor DataConnector. Your FileOperation uses the Log and the DataConnector, but it shouldn't change how you Log or how you connect to your Data.
You could however prepare for the future, and create an interface for your Log class and for your DataConnector, so that at any time in the future you could easily swap those classes for another implementation, like so:
public interface ILogger
{
void Log(string message);
}
public interface IDataConnector<T>
{
IList<T> ReadList(Predicate<T> matches);
T ReadItem(Predicate<T> match);
}
and implement your classes for these interface.
In your FileOperation class, you can then set these over interfaces, and potentially later fill them using dependency injection, like so:
public class FileOperation
{
public ILogger Log { get; set; }
public IDataConnector DataConnector { get; set; }
public FileOperation()
: this(new Logger(), new DataConnector<string>())
{
}
public FileOperation(ILogger log, IDataConnector dataConnector) {
Log = log;
DataConnector = dataConnector;
}
}