I have a winforms application with lot's of classes, and in every class I need to write to a log if something goes wrong.
Today I made a logger function that I initialize in every class object for using it inside.
For example I have a main logic class that have log and one more class that's running different logic that should have a log.
Today I am using:
Initialize log object in class contractor for working with it.
passing log object to the contractor.
what will be the best architecture for initialize it one time and use it in every class (Not doing it static).
My logger class:
namespace MyLogger
{
public class Logger : IMessageLogger
{
IMessageLogger _messageLogger;
public Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
public interface IMessageLogger
{
void Log(string message);
}
public class FileLogger : IMessageLogger
{
string _filePath = Environment.CurrentDirectory;
public string filePath
{
get { return _filePath; }
set { _filePath = value; }
}
public FileLogger(string filePath)
{
_filePath = filePath;
}
public void Log(string message)
{
string strFileName = Path.Combine(_filePath, String.Format("{0}{1}.log", _filePath, DateTime.Now.ToString("yyyyMMdd")));
using (StreamWriter writer = new StreamWriter(strFileName, true))
{
writer.WriteLine(DateTime.Now.ToString("[dd/MM/yyyy hh:mm:ss]") + " -> " + message);
};
}
}
public class ConsoleLogger : IMessageLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
}
I believe the best way is to implement it via DependencyInjection, you should read about it online.
But if you want a quick and easy solution, simply implement a Singleton pattern for your logger, like such -
public class Logger : IMessageLogger
{
private IMessageLogger _messageLogger;
private static Logger _instance;
public static Logger Instance
{
get
{
if (_instance == null)
{
// Pick one:
_instance = new Logger(new FileLogger("SomePath"));
_instance = new Logger(new ConsoleLogger());
}
return _instance;
}
}
private Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
And to write a log use this line -
Logger.Instance.Log("This is a log message!");
There are two sides to my answer.
The first, to get the behavior you want, make the class and methods static. This creates one instance for the lifetime of your application and you can just use FileLogger.Log wherever you need it without having to new a new FileLogger up.I am not sure why you are adverse to using a static though, so you could get the same behavior with a singleton.
The second is that you should not be writing your own logger. There are so many good, open source options available. Look at log4net, nLog or even the built in TraceSource to save yourself the effort of re-inventing the wheel.
Related
I Know
IoC is a design principle which recommends the inversion of different kinds of controls in object-oriented design to achieve loose coupling between application classes.
But I have confilct with the following code:
static void Main(string[] args)
{
ProductService ProductService = new ProductService(new LogInDB());
ProductService.Log();
Console.ReadKey();
}
public class ProductService
{
private readonly Ilog log;
public ProductService(Ilog _log)
{
log = _log;
}
public void Log()
{
log.Log();
}
}
public interface Ilog
{
void Log();
}
public class LogInFile : Ilog
{
public void Log()
{
Console.WriteLine("Log Into File");
}
}
public class LogInDB : Ilog
{
public void Log()
{
Console.WriteLine("Log Into Data Base");
}
}
What is difference between previous and next code
In the first code I used IOC (and added product service) but next I'm using just late binding
but i see IOC not added any value
static void Main(string[] args)
{
Ilog logObj = new new LogInDB();
logObj.Log();
//I still able to using LogInDB
//Ilog logObj = new new LogInDB();
//logObj.Log();
Console.ReadKey();
}
public interface Ilog
{
void Log();
}
public class LogInFile : Ilog
{
public void Log()
{
Console.WriteLine("Log Into File");
}
}
public class LogInDB : Ilog
{
public void Log()
{
Console.WriteLine("Log Into Data Base");
}
}
This depends on your defintion of value. One advantage of IoC would be a better testability of your code, which many would argue adds a lot of value. You can easily inject mocked classes into your test code and only test the class you want to test.
By the way your example is not compileable because of the line Ilog logObj = new new LogInDB();
I want to have a logger which is "made available" to my application. My application logs interesting things, and subscribers subscribe to those messages. For example a subscriber might put message in a database, or the windows event log, or a message bus, etc.
A simplified reproduction of what I've written is below:
using System;
using System.Reactive.Subjects;
namespace ConsoleApplication17
{
internal interface ILogger
{
void Log(String message);
}
internal class Logger : ILogger
{
private readonly Subject<String> _logMessagesObservable = new Subject<string>();
public void Log(string json)
{
_logMessagesObservable.OnNext(json);
}
public IObservable<String> LogMessagesObservable { get { return _logMessagesObservable; } }
}
internal class ConsoleLogListener
{
public ConsoleLogListener(IObservable<String> messages)
{
messages.Subscribe(Console.WriteLine);
}
}
internal class WindowsEventListener
{
public WindowsEventListener(IObservable<String> messages)
{
messages.Subscribe(WriteToEventLog);
}
private void WriteToEventLog(String message)
{
//Write to event log
}
}
class Program
{
static void Main(string[] args)
{
Logger logger = new Logger();
//Link up any subscribers
new ConsoleLogListener(logger.LogMessagesObservable);
new WindowsEventListener(logger.LogMessagesObservable);
//... more listeners go here.
DoSomeWork(logger);
}
private static void DoSomeWork(ILogger logger)
{
logger.Log("Something interesting");
logger.Log("Something else interesting");
}
}
}
But I'm not happy about the code which looks like this:
//Link up any subscribers
new ConsoleLogListener(logger.LogMessagesObservable);
new WindowsEventListener(logger.LogMessagesObservable);
//... more listeners go here.
It irks me for some reason but I can't put my finger on it. I guess it just looks odd to new up a listener like that and not keep the reference to it.
Is there a better / more accepted pattern for what I'm trying to do?
I'd probably expect the listeners to implement IObserver<string>, then you'd connect the two like so:
logger.LogMessagesObservable.Subscribe(new ConsoleLogListener());
I'd like to write a logger that can be easily appended to any class in my current project. For development, it will be convenient to log messages to the console, whereas in the final release I'd like to log to a file or something. One should be able to change the behavior by editing just a few lines of code, or ideally a settings file.
What I have so far is this class structure:
public interface ILogger {
void LogMessage(String message);
// ... other logging functions (exceptions, time etc.) don't matter here
};
public interface ILoggable { };
public static class LoggingProvider {
private static ILogger logger = ConsoleLogger.handle;
public static void LogMessage(this ILoggable obj, String message) {
logger.LogMessage(message);
}
}
public sealed class NullLogger : ILogger {
// A logger that does nothing..
};
public sealed class FileLogger : ILogger {
// A logger that writes to a file..
};
public sealed class ConsoleLogger : ILogger {
#region Console Allocation
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
#endregion
#region Singleton implementation
private static Object cs = new Object();
private static ILogger instance = null;
private ConsoleLogger() {
AllocConsole();
}
~ConsoleLogger() {
FreeConsole();
}
public static ILogger handle {
get {
lock ( cs ) { if ( instance == null ) instance = new ConsoleLogger(); }
return instance;
}
}
#endregion
#region ILogger Member
public void LogMessage(string message) {
lock ( cs ) {
String logString = getTimeString();
logString += ( " -> \t " + message );
Console.WriteLine(logString);
}
}
#endregion
#region Helper functions
// ...
#endregion
};
Now, I can have any class I'd like to implement ILoggable, and via the Extension Method LogingProvider.LogMessage I can call this.LogMessage("...") within these classes. If it was C++, I'd just use private inheritance instead.
Is this now good or bad design? Anything I can improve? Is there a way to provide classes with logging functionality without the extension method, but with similarly few changes?
Your design seems a bit over-engineered at first sight. In this method:
public static void LogMessage(this ILoggable obj, String message) {
logger.LogMessage(message);
}
the ILoggable obj is not used at all. Why do you need it then? Why not just have:
public static void LogMessage(String message) {
logger.LogMessage(message);
}
and call it LoggingProvider.LogMessage(...)?
On a side note, take a look at Log4Net, this is the industry standard implementation of logging functionality.
I'm trying to put config data from host to plugins but I always get nulls at plugins. My code responsible for plugins is below:
Form:
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
DataStorage.Instance.LoadModes();
DataStorage.Instance.ActiveMode = "aaa";
DataStorage.Instance.RulesFile = "bbb";
DataStorage.Instance.SetProjectName("cccc");
DataStorage.Instance.LoadRules();
DataStorage.Instance.LoadPlugins();
}
}
DataStorage:
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(ConfigStorage))]
public class DataStorage: ConfigStorage
{
//fields and properties here
public string ActiveMode;
[ImportMany(typeof (IAPlugin))]
public IEnumerable<Lazy<IAPlugin, IAPluginData>> aPlugins;
[ImportMany(typeof (IBPlugin))]
public IEnumerable<Lazy<IBPlugin, IBPluginData>> bPlugins;
private CompositionContainer _container;
private static readonly DataStorage instance = new DataStorage();
static DataStorage()
{
}
private DataStorage()
{
Init();
}
public static DataStorage Instance
{
get { return instance; }
}
private void Init()
{
//code here
}
public void LoadPlugins()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(ConfigStorage).Assembly));
catalog.Catalogs.Add(new DirectoryCatalog(Settings.Default.GetPathFor("Plugins")));
_container = new CompositionContainer(catalog);
try
{
_container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
}
ConfigStorage:
public abstract class ConfigStorage
{
public string RulesFile;
public string ActiveMode;
//properties and methods
}
Plugin:
[Export(typeof (IAPlugin))]
[ExportMetadata("Name", "myNameIsBond")]
public class myNameIsBond : IAPlugin
{
protected readonly ConfigStorage configStorage;
[ImportingConstructor]
public myNameIsBond (ConfigStorage configStorage)
{
if (configStorage == null)
throw new ArgumentNullException("configStorage");
this.configStorage = configStorage;
}
public string DoStep(string url)
{
Console.WriteLine(configStorage.ActiveMode); //this is null - it should be "aaa"
return url;
}
}
When I run plugin.Value.DoStep("sth"); the Console.WriteLine(configStorage.ActiveMode); always print null - when I debugging: all fields from configStorage are nulls. What I'm doing wrong? How can I put DataStorage instance to my plugins?
I think the problem is that the ConfigStorage export is showing up in the catalog, so the imports are getting satisfied with a version created by the catalog instead of the singleton you have configured. Try putting a PartNotDiscoverableAttribute on the DataStorage class.
As an aside, your DataStorage constructor is private, but it looks like the catalog can still create a separate version of it because the constructor is invoked through reflection.
I typically don't use an instance variable at all and just let MEF create the singleton, but if you really want to have an instance property you can do something like
// note that there is no export attribute here
public class DataStorage: ConfigStorage
{
[Export(typeof(ConfigStorage))]
public static DataStorage instance { get; private set; }
}
So that MEF will export your singleton instance rather than creating a new object.
This is how I understand I can implement the singleton pattern in C#:
public class ChesneyHawkes{
private static ChesneyHawkes _instance = new ChesneyHawkes();
public ChesneyHawkes Instance {get{return _instance;}}
private ChesneyHawkes()
{
}
}
What if I want to provide a single instance of an object, so that there can only ever be one, make the access to it public, but only allow it to be created or replaced by another singleton.
// The PuppetMaster should be the only class that
// can create the only existing Puppet instance.
public class PuppetMaster{
private static PuppetMaster_instance = new PuppetMaster();
public static PuppetMaster Instance {get{return _instance;}}
// Like a singleton but can be replaced at the whim of PuppetMaster.Instance
public static Puppet PuppetInstance {get {return Puppet;}}
private PuppetMaster()
{
}
public class Puppet{
// Please excuse the pseudo-access-modifier
puppetmasteronly Puppet(){
}
}
}
// To be accessed like so.
PuppetMaster.Puppet puppet = PuppetMaster.Instance.PuppetInstance;
You don't really need more than one singleton for that. Look at this example:
using System;
// interface for the "inner singleton"
interface IPuppet {
void DoSomething();
}
class MasterOfPuppets {
// private class: only MasterOfPuppets can create
private class PuppetImpl : IPuppet {
public void DoSomething() {
}
}
static MasterOfPuppets _instance = new MasterOfPuppets();
public static MasterOfPuppets Instance {
get { return _instance; }
}
// private set accessor: only MasterOfPuppets can replace instance
public IPuppet Puppet {
get;
private set;
}
}
class Program {
public static void Main(params string[] args) {
// access singleton and then inner instance
MasterOfPuppets.Instance.Puppet.DoSomething();
}
}