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.
Related
The controller has no dependency injection here is the code.
public class AccountingController : BaseApiController
{
[HttpGet]
[Route("Accounting/Currency/{code}")]
public HttpResponseMessage GetCurrencyCode(String code)
{
Log.Info($"GET Accounting/Currency/{code}"); //how to run this static method
arguments.Add("code", code);
return GetResult<Int16?, String>(code, m => new
Models.AccountsModels.AccountModel().CurrencySearchByCode(code)); //how to run this method
}
}
The method mentioned inside it is Log.Info(static), arguments and GetResult the BaseApiController have
public abstract class BaseApiController : ApiController
{
public BaseApiController();
protected Dictionary<string, object> arguments { get; set; }
protected HttpResponseMessage GetResult<T, U>(U args, Func<U, T> doWork, long?
partialContentCount = null);
}
Now I want to understand that how can I mock a controller with various methods running as I tried this way.
[Fact]
public void GetCurrency_ActionExecutes_ReturnsHttpResponseMessage()
{
var controller = new AccountingController();
var data = controller.GetCurrencyCode(currency) as
HttpResponseMessage;
Assert.True(data != null);
}
It ran but failed on Log.Info and I suppose will not work on arguments and GetResult as well
'Could not load file or assembly 'Microsoft.Practices.EnterpriseLibrary.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.'
This would run only on API but I want to directly access the controller and run these methods inside it.
I'm using xUnit but cannot find a way to run on these so called controller methods. I've read some place that MS Moles and Typemock can help but don't know how that can mock these internal methods of a controller.
You can do some hand-made workaround...
If you can modify and extend behaviors of the Log class you can try something like this:
public static class Log
{
private static ILogger instance { get; set; }
static Log()
{
bool isTesting = /* Find a way here to tell at runtime if you're
* testing or not.
* At very last option, for example, in your test's
* arrange-code, BEFORE any call to Log class,
* writes a txt file or whatever and read it
* here to determine if this is true or false.
* (obviously perform a proper cleanup)
* Use app configuration or a method that suits
* your architecture...
* * The key point here is that the Log static ctor
* must be able to know if it's testing time at
* runtime, since you can't pass variables to
* static ctors.
*/
if (isTesting)
{
instance = new LoggerStub();
}
instance = new Logger();
}
public static void Info(string message)
{
instance.Write("INFO", message);
}
public static void Warning(string message)
{
instance.Write("WARNING", message);
}
/* if you are not able to use the ctor-trick
* and you're allowed to do so, you can also perform a
* instance switch
*/
public static void InstanceSwitch(LoggerStub stub)
{
instance = stub;
}
}
public interface ILogger
{
void Write(string logLevel, string message);
}
internal class Logger : ILogger
{
public void Write(string logLevel, string message)
{
//writes, access file system,
//whatever
}
}
internal class LoggerStub : ILogger
{
public void Write(string logLevel, string message)
{
//do nothing
//or whatever you wish
}
}
About "arguments" and "GetResult()" you can work some hand-made tricks as well, (again assuming you can modify these classes):
public abstract class BaseApiController : ApiController
{
public BaseApiController();
protected Dictionary<string, object> arguments { get; set; }
/* virtual if it has body which you use in other subclasses
* abstract otherwise
*/
protected virtual HttpResponseMessage GetResult<T, U>(U args, Func<U, T> doWork, long?
partialContentCount = null);
}
public class AccountingController : BaseApiController
{
protected virtual Models Models { get; set; }
[HttpGet]
[Route("Accounting/Currency/{code}")]
public HttpResponseMessage GetCurrencyCode(string code)
{
Log.Info($"GET Accounting/Currency/{code}");
arguments.Add("code", code);
return GetResult<Int16?, string>(code, m =>
Models.AccountsModels.AccountModel().CurrencySearchByCode(code));
}
}
internal class AccountingControllerMock : AccountingController
{
protected override Models Models { get; set; }
/*
* Use this to set up Models
*/
public void ModelsSetUp( /*any parameters you need for models*/)
{
//set up Models
}
/*
* Or use ModelsStub if you want to be more explicit building
* a class in your test
*/
public void ModelsSetUp(ModelsStub models)
{
Models = models;
}
/*
* Use this to set up the dictionary
*/
public void ArgumentsSetup(string key, object value)
{
arguments.Add(key, value);
}
protected override HttpResponseMessage GetResult()
{
//return whatever you wish
}
}
internal class ModelsStub : Models
{
/* override things here in order to
* have control on what is going on
* */
}
(I'm used to put stubs and mocks directly in testing project(s) and/or in a test-api project which extend internal visibility to testing project(s), that's why are them marked as internal. It also helps to avoid that someone (not intentionaly using autocompletion maybe) uses these fake classes in production's code).
Then use ApplicationControllerMock to test the behavior of GetCurrencyCode unit.
They are somewhat hard books to digest but:
"Working effectively with legacy code" by Micheal Feather
"The art of unit testing" by Roy Osherove
definitely, both, worth the reading!
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".
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've got a static class that I am using for logging:
public static class myLogger
{
public static ErrorLogging(string input)
{
//dostuff
}
}
The way I am using it is:
public class myClassthatDoesStuff
{
...
myLogger.ErrorLogging("some error ocurred");
...
}
How can I moq the myLogger class in order to be able to unit test it and ensure that the ErrorLogging method was executed? Is it possible to do this without setting any parameters in the constructor (constructor injection)? myClassthatDoesStuff requires that there are no parameters in the constructor.
This blog post describes the exact same scenario - you have an old static logging method and want to use it in testable code.
Wrap the static class in a non-static class - not just for testing, but for general use.
Extract the methods of your new non-static class into an interface.
Wherever you would have depended on the static class, depend on the interface instead. For example, if class DoesSomething requires the function in your static class, do this:
public interface ILogger
{
void ErrorLogging(string input);
}
public class MyClassthatDoesStuff
{
private readonly ILogger _logger;
public MyClassthatDoesStuff(ILogger logger)
{
_logger = logger;
}
}
This gives you two benefits:
You can unit test your old static class (assuming that it has no state and doesn't depend on anything that has any state) (although if that's the case I suppose you could unit test it anyway.)
You can unit test code that will use that static class (by removing the direct dependency on that static class.) You can replace ILogger with a mocked class, like one that adds your error messages to a list.
class StringLogger : List<string>, ILogger
{
public void ErrorLogging(string input)
{
Add(input);
}
}
var testSubject = new MyClassthatDoesStuff(new StringLogger());
A simpler option doesn't require creating an interface and an adapter class. You can create a delegate which is like an interface for just a method.
In the case of the logger, it would be
delegate void Logging ErrorLoggingMethod(string input);
Using it looks similar to using an interface:
public class MyClassthatDoesStuff
{
private readonly ErrorLoggingMethod _logger;
public MyClassthatDoesStuff(ILogger logger)
{
_logger = logger;
}
public void DoSomethingThatLogs()
{
// _logger is a method
_logger("Log something");
}
}
This is even easier to mock and test
string loggedMessage = null;
ErrorLoggingMethod fakeLogger = (input) => loggedMessage = input;
You can inject the fake logger into the class you're testing. If that class calls the logger, the method assigns whatever was logged to the variable. Then you can assert whatever was logged or just that anything was logged.
If your app uses a dependency injection/IoC container, you can register the delegate just like you would an interface. Here's an example.
If you can not change it from a static to a non-static class, wrap it with a non-static class...
void Test()
{
string testString = "Added log";
var logStore = new List<string>();
ILogger logger = new MyTestableLogger(logStore);
logger.ErrorLogging(testString);
Assert.That(logStore.Any(log => log==testString));
}
public interface ILogger
{
void ErrorLogging(string input);
}
public class MyTestableLogger : ILogger
{
public MyTestableLogger(ICollection<string> logStore)
{
this.logStore = logStore;
}
private ICollection<string> logStore;
public void ErrorLogging(string input)
{
logStore.Add(input);
MyLogger.ErrorLogging(input);
}
}
public static class MyLogger
{
public static void ErrorLogging(string input)
{
// Persist input string somewhere
}
}
You can do it using Microsoft's Shims
Assuming that Your Project is called ConsoleApplication1.
First of all go to your unit test project references, right click on assembly that contains myClassthatDoesStuff class and chose 'Add Fakes Assembly'.
Unit test with shims will look like:
[TestClass()]
public class MyClassthatDoesStuffTests
{
[TestMethod()]
public void ImportansStuffTest()
{
using (ShimsContext.Create())
{
bool logCalled = false;
ConsoleApplication1.Fakes.ShimmyLogger.ErrorLoggingString =
(message) => logCalled = true;
new myClassthatDoesStuff().ImportansStuff();
Assert.IsTrue(logCalled);
}
}
}
You can do it with Typemock Isolator.
It allows you to avoid all this amount of wrappers and interfaces and to do it that simple:
[TestMethod]
public void TestLogging()
{
//Arrange
Isolate.WhenCalled(() => myLogger.ErrorLogging("")).CallOriginal();
//Act
var foo = new myClassthatDoesStuff();
foo.DoStuff();
//Assert
Isolate.Verify.WasCalledWithAnyArguments(() => myLogger.ErrorLogging(""));
}
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);
}
}