c# static object reference - c#

I have a class like so
public class FileLogger
{
public FileLogger(string typeOfLog)
{
//implementation
}
public void LogError(string err)
{
//implementation
}
public void LogMessage(string err)
{
//implementation
}
}
Since this is a logging class for an application to log its output to a file, one would have expected it to be a static class. However as you can see it is not. It is however used in the application like this:
public class BugetApplication
{
private static FileLogger logger;
//constructor
public BugetApplicationClass()
{
logger = new FileLogger("some-constructor-parameter");
}
//a method that uses the FileLogger class for logging
public string Classify()
{
try
{
//start multiple threads for classification
Classification clsf = new Classification();
clsf.handleEvent += clsf_handleEvent;
clsf.Classify();
}
catch (Exception exp)
{
logger.LogError(exp.Message);
}
}
private static void clsf_handleEvent(string errString)
{
if(errString.Contains("error"))
{
logger.LogError(errString);
}
}
}
Multiple threads are started by the BugetApplication class's classify method. Any errors in that class fire an event which is handled in the BugetApplication class's clsf_handleEvent method. So multiple threads could each fire their own event. Would creating the instance variable as a static variable in the BugetApplication class have any effect here or would keeping it non static have the same effect? I don't want any one thread to overwrite the error message of another thread.
Edit
Just to clear things out, the BugetApplication class which will be created only once has a static variable 'static FileLogger logger; ' it creates an instance once in its constructor, passing in some values to the constructor of the FileLogger class. In the BugetApplication class, there is a method which calls the Classification class's classify method. The Classify method starts the various threads and on any error fires an event which is handled back in the BugetApplication class so this clsf_handleEvent method can have multiple calls on it.

Why do you think it would overwrite the error message of another thread? The logger should just append the messages, so there shouldn't be any overwriting (depends how you handle the logging though). There is a potential problem however - depending on your logging function you might be blocking access to the file. Because the method works on an external file, you should probably use lock in the function.
It really doesn't matter if the class is static or not, the problem is concurrent access to external resources which needs to be synchronized for multiple threads to become thread-safe.
lock documentation on msdn

It really depends on the actual implementation of the logger.
Static classes are now frowned upon as they make unit testing more difficult. Many facilities which conventionally were implemented as static or singleton (loggers, e-mailers, etc.) now provide unit test/IoC friendly alternatives (e.g. a factory and an interface or virtual class).
The design of these facilities is usually a front end class which the client application uses to interact and an asynchronous back end which takes care of the synchronization and actual logging (or emailing, or whatever).
The crux is whether the front ends are multi-threaded or not.
If they are not; you should create a new one per thread. In this case the logger would probably have to be a local variable or parameter of the method using it.
Usually, however, they are multi-threaded and re-entrant, as all they do is pass along the log message to the back-end and have no state of their own. In this case they can be saved as a static variable or application wide singleton, but it is better to instantiate them in an IoC container as singleton and inject it to the classes using them. Doing so makes writing unit tests with mock loggers a lot easier.

Related

using(), access data from parent callee for logging purposes

I have a custom build log framework that logs to a database.
For example it can do
L.e("Error invalid password", userGuid);
This works fine for general use but the application is quite complex and there are a lot of different parts that are called from the main code. For example a login sequence could send an SMS for OTP which is handled by a completely other part of the system and it does not make sense to pass a lot of values thru just for logging purposes.
What I want to achieve is to tag the log with for example userGuid so that I can search for everything related to this specific user. I also want to tag any logging in the SMS module even though the SMS module does not know anything about the user concept.
So what I am thinking of is if it is possible to get the current threadid and store some things regarding the logging in a higher level. I wonder if this is at all possible.
Psuedo code:
void Login(UserName, Password) {
User user = UserManager.GetUser(UserName)
using(L.SetUser(user.ID)) { //Here I want to use user.ID later in code that dont know the context
SmsManager.SendOtp(user.Phonenumber)
}
}
public class SmsManager {
public static void SendOtp(string phonenumber) {
if (phonenumber == "") {
L.error("Phone number is empty"); //How can I use the value from L.SetUser above? Could I use a hash table of threadids in L or would that be a bad idea?
}
}
}
Kind regards
Jens
Can you show us some snippets from L? Is that a static class? Does SetUser set a static variable? You could use the using block the way you suggest. You'd want to implement IDisposable and clear the UserID value in the Dispose method. But if UserID is a static variable, then this solution will not work in a multi-threaded environment (without some other changes). And the design just seems odd to me.
Overall seems like you are using static a lot. That can get you into trouble.
There are lots of possible solutions. Tough to say what's best without seeing some more code. Here is one way using dependency injection to keep your modules separate, as you want.
Define an interface for your logger.
public interface ILogger
{
void Error(string message);
}
Implement with a class that adds the user information:
public class MessageWithUserLogger : ILogger
{
private readonly string _userId;
public MessageWithUserLogger(string userId)
{
_userId = userId;
}
public void Error(string message)
{
L.error(message, _userId);
}
}
Change SmsManager class to be non-static and depend on the ILogger abstraction rather than the L implementation:
public class SmsManager
{
private readonly ILogger _logger;
public SmsManager(ILogger logger)
{
_logger = logger;
}
public void SendOtp(string phonenumber)
{
if (phonenumber == "")
{
_logger.Error("Phone number is empty");
}
}
}
Inject the logger with userID when that information is available:
void Login(UserName, Password)
{
User user = UserManager.GetUser(UserName);
ILogger logger = new MessageWithUserLogger(user.ID);
SmsManager smsManager = new SmsManager(logger);
smsManager.SendOtp(user.Phonenumber);
}
The using statement is not intended to be used like this. The using statement was introduced to be able to define a limited scope, and at the same time make sure objects are disposed using the IDisposable interface (see also https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement).
The way you are using the using statement makes it seems as if the property is sent when you start the scope, and would somehow be "unset" afterwards, but this is not the case.
When working with loggers and starting from your pseudo code, I would say your logging framework should be extended to create a context specific logger when you go into the using, and then pass the logging context to the static function. it would look then as below:
void Login(UserName, Password) {
User user = UserManager.GetUser(UserName)
using(var logContext = L.CreateContext(user.ID)) { //Here I want to use user.ID later in code that dont know the context
SmsManager.SendOtp(logContext, user.Phonenumber)
}
}
public class SmsManager {
public static void SendOtp(LogContext logContext, string phonenumber) {
if (phonenumber == "") {
logContext.error("Phone number is empty"); //How can I use the value from L.SetUser above? Could I use a hash table of threadids in L or would that be a bad idea?
}
}
}
Instead of passing the log context, it is theoretically possible to store the context inside the L object and map it to a thread ID, and, later on in the functions check if there is a specific log context for that thread when you log something. In the IDisposable interface implementation of the LogContext object, you should then remove the context (which corresponds with the end of your using() scope). I would however not do this, because it "hides" a bunch of logic, but even more, it relies on the fact that every function will be executed in the same thread. This in combination with hiding this, makes it a possible source of errors (if the user of the code isn't aware that this is linked to the thread, and changes the thread, you might miss information, make wrong assumptions based on the logging, etc). I think it is not bad practice if you have functions like the SMS manager that has a number of helper functions, to pass in a context specific object.
Also, be aware that this is a concept that exists in most popular logging libraries such as Serilog, and, in almost all cases, writing your own logging libraries isn't the most profitable business (since most of these libraries also have extensions that allow you to write a custom sink, which for example would then write the log output to a database for your specific scenario (but you get all the rest for free).

How to call constructor of class which are instantiated through Structure Map in C#

I have an interface called ILogger which basically contains some methods for logging.
Ilogger.cs
public interface ILogger
{
void LogError(string message, Exception exception = null);
void LogMessage(string message);
void LogValidationError(UploadResult uploadResult);
void LogValidationError(ValidationResult validationResult);
void LogProcessingError(string processingError);
}
I have a LogHelper class which implements this interface. The LogHelper class is instantiated through StructureMap like
ObjectFactory.Initialize(
request =>
{
request.For<ILogger>().Singleton().Use<LogHelper>();
});
I have many classes in whose constructor I just instantiate this class and call methods to log the information.
For eg: I have a class say Dummy1 in whose constructor I instantiate the LogHelper as:
public Dummy1()
{
this.logger = ObjectFactory.GetInstance<ILogger>();
}
In LogHelper I have method which basically creates log file and writes the message passed as parameter to it.
public void LogMessage(string message)
{
using (var writer = this.GetTextWriter(this.messageFilename))
{
writer.WriteLine(message);
}
}
Currently the filename is hardcoded into a constant property of LogHelper class as private string messageFilename = "logs\\UserCreationResult.log";
But I want the Filename to be dynamically sent whenever the LogHelper is instantiated.
I thought of having a class property and define that property in the constructor whenever the class is instantiated. But since the LogHelper class is instantiated as ObjectFactory.GetInstance<ILogger>(). I am not able call the constructor in which I can pass the filename.
Unfortunately the way you are going about this is a little bit self-defeating. Your classes only know about ILogger, not any particular implementation of ILogger. That's good - it means that the implementation could write to a file, a SQL table, or anything.
But if your class only knows about ILogger, not the implementation, then how does your class know that the logger needs a file path? If you change your method signatures in ILogger to contain a file path, then two things happen.
It becomes impossible to have any implementation of ILogger that doesn't write to a file (unless it ignores the file path, which would be really weird.)
Now that class that calls the logger has to know a file path. Where will that class get a file path from? Will it be stored in the class? In that case you end up with a class that doesn't work unless it's part of an assembly executing on a computer where it can write to that exact file path.
Instead, the details of where and how to log should live somewhere in your ILogger implementation. That's closer to the Single Responsibility Principle. The class that calls ILogger isn't responsible for decisions about how ILogger works. It doesn't know and it doesn't want to know. It says "Here, take this and log it." The logger implementation is responsible for the rest.
I'd recommend scrapping the static ObjectFactory entirely and using the container to resolve and create all of your classes, including the logger and the classes that depend on it, but that's so broad that it's not really helpful. (It has been deprecated because it's a bad pattern. It's not even in the latest version of StructureMap.)
Everything above this is a recommendation. After this I'm offering an option that's not really recommendable, but requires less change and keeps your classes from knowing about file paths, because please don't do that ever.
One option - a halfway compromise - might be to register different named implementations of ILogger. You could modify your logger class to look like this:
public class FileLogger : ILogger
{
private readonly string _filePath;
public FileLogger(string filePath)
{
_filePath = filePath;
}
}
Now you can create multiple instances of that logger class, passing a different file path to each one. That way it's not a static property, which limits you to only having one file path.
Then you could register your implementations like this.
ObjectFactory.Initialize(
request =>
{
request.For<ILogger>().Singleton()
.Use<FileLogger>(() => new FileLogger("some path")).Name = "LoggerOne";
request.For<ILogger>().Singleton()
.Use<FileLogger>(() => new FileLogger("some other path")).Name = "LoggerTwo";
});
Now your class can say which logger it wants, like this:
var logger = ObjectFactory.GetNamedInstance<ILogger>("LoggerOne");
But please don't really do that either. It's more than I can really describe here in great detail, but take a look at dependency injection so that your classes really only know about ILogger and don't know or care which implementation they get and don't tell it anything about how to do its job.
You are using your logger as a singleton, so you are not creating an instance each time you call ObjectFactory.GetInstance<ILogger>();, you are simply getting a reference to the same logger instance all the time which is created once on first use.
If you want to write to a specific destination, then the best solution is to specify the destination in the Logging methods:
void LogError(string message,
Exception exception = null,
string destination = /*some adequate defualt value*/);
void LogMessage(string message,
string destination = /*some adequate defualt value*/);
Creating state information in your logger instance with a specific destination can be dangerous if you are using the logger concurrently from methods that are expecting and therefore setting different destinations; you can end up logging things where they are not supposed to.
Which brings up an important issue; because you are sharing the logger across your application (singleton) make sure its methods are safe to call concurrently if there is a possiblity that it will be called this way.

Log4Net message construction cost when not debugging

According to this log4net article you should check if debug is enabled prior to any Log.Debug statements to eliminiate the statement construction cost. Is there a better alternative to always having to check if(Log.IsDebugEnabled) prior to any log statements?
Log4Net example:
if (log.IsDebugEnabled)
{
log.Debug("This is entry number: " + i );
}
I don't want to pay the overhead cost of statement construction, but also don't want to check prior to every log statement.
#Grhm and #David have good ideas, but I don't think that David's wrapper is as good as it could be. Wrapping log4net that way. Simply implementing Debug, Info, etc on the wrapper and delegating those down to log4net's Debug, Info, etc methods break log4net's ability to log the call site information. If you wrap this way and tell log4net to log the call site info, log4net will write out the call site in the wrapper, not the call site in your actual code, which is what you want.
I personally don't like using a singleton logger as you lose the ability to tweak logging levels in different parts of your program. If you are working on several components, you might want Info level logging turned on for one component, but only Warn logging (or none at all) for other components. With a singleton logger, all logging in all of your application will be at the same level.
You are denying yourself a lot of log4net's built in (and powerful) capabilities when you wrap log4net incorrectly and when you use a single logger to cover your entire application.
I answered a similar question (about maintaining call site information) here:
how to log method name when using wrapper class with Log4net
To save time, I have included a code example here (uncompiled and untested, but should be close)...
public class MyLog4NetWrapper
{
ILog log;
public MyLog4NetWrapper(string loggerName)
{
log = LogManager.GetLogger(loggerName)
}
public MyLog4NetWrapper(type loggerType)
{
log = LogManager.GetLogger(loggerType)
}
public void Info(string message)
{
if (log.IsInfoEnabled) log.Logger.Log(typeof(MyLog4NetWrapper), LogLevel.Info, message, null);
}
//Defer expensive calculations unless logging is enabled - thanks Grhm for the example
public void Info(Func<string> formattingCallback )
{
if(log.IsInfoEnabled)
{
log.Logger.Log(typeof(MyLog4NetWrapper), LogLevel.Info, formattingCallback(), null);
}
}
//Debug, Warn, Trace, etc are left as an exercise.
}
You can create these loggers in your code like this:
public class MyClass
{
private static readonly ILog log = new MyLoggerWrapper(typeof(MyClass));
public void DoSomething()
{
log.Info("Hello world!");
}
}
The trick to writing a log4net wrapper that preserves the call site information is to use the Log method and to pass the type of your wrapper as the first parameter.
If you are going to write a wrapper in order to implement the functionality that you asked about (deferring execution of any expensive code in the logging call without explicitly checking to see if the desired logging level is enabled), then you might as well put that code in the wrapper rather than implement it as an extension method (which will also suffer from the same loss of call site problem I described above).
Good luck!
The easiest and cleanest way might be the use of the DebugFormat method which actually does the check if the debug level is enabled (see Github-Code of log4net).
but also don't want to check prior to every log statement
When you find yourself repeating the same code over and over, it sounds like a common abstraction may be in order. In this case you can, for example, create a custom wrapper for Log4Net. Something as simple as:
public static class Logger
{
private static ILog _log;
static Logger()
{
log4net.Config.XmlConfigurator.Configure();
_log = log4net.LogManager.GetLogger("Log4Net");
}
public static void Debug(string message)
{
if (_log.IsDebugEnabled)
_log.Debug(message);
}
public static void Info(string message)
{
_log.Info(message);
}
public static void Warn(string message)
{
_log.Warn(message);
}
public static void Error(string message)
{
_log.Error(message);
}
public static void Error(string message, Exception ex)
{
_log.Error(message, ex);
}
public static void Fatal(string message)
{
_log.Fatal(message);
}
public static void Fatal(string message, Exception ex)
{
_log.Fatal(message, ex);
}
}
In this case I made the logger instance static. I'm not 100% sure that will always work as expected. Normally I use this behind a dependency injection framework and configure the logger dependency to be a singleton, handled by the framework. You might instead make this an instance class with instance methods and put it behind a static factory class instead. Test and tweak as necessary.
There are a couple of added benefits here:
Your dependency in Log4Net is isolated to a single class. So if you ever want to use a different logger, you only have to change one class instead of everything in the entire project.
You can easily abstract this behind a dependency injector.
Any other common functionality you want to include in all logging statements can be easily and globally included here.
An example I commonly use for the third benefit might be something like this:
private static string GetLocation()
{
var frame = new StackTrace(1).GetFrame(1);
var method = frame.GetMethod();
return string.Format("{0}:{1}.{2}({3})", Environment.MachineName, method.ReflectedType.FullName, method.Name, frame.GetFileLineNumber().ToString());
}
This gets more meaningful debugging information from the runtime system (though there may be a performance hit, for high-volume systems it's worth testing). So my pass-through error logging function might look like this:
public void Error(string message, Exception ex)
{
_log.Error(string.Format("{0}:{1}", GetLocation(), message), ex);
}
You could use a lambda expression. Like:
log.Debug(() => "This is entry number:" + i);
That way the lambda is only evaluated after the .IsDebugEnabled call.
We have an extension class defined (taken from http://www.beefycode.com/post/Extension-Methods-for-Deferred-Message-Formatting-in-Log4Net.aspx) that has extension methods like:
public static class Log4NetExtensionMethods
{
public static void Debug( this ILog log, Func<string> formattingCallback )
{
if( log.IsDebugEnabled )
{
log.Debug( formattingCallback() );
}
}
// .. other methods as required...
}
I'm not sure if log4net have added lamda type support in more recent releases - but this has been working for me.
If you include the namespace log4net.Util, you are able to call the following extension methods on log4net ILog:
public static void ErrorExt(this ILog logger, Func<object> callback)
This will only call the lambda function when logging error level is enabled. No need to write your own extension methods. It also protects from creating an error while constructing the actual log message by wrapping the creation in a try catch method.
I would look at preprocessor (precompile?) directives.
#if DEBUG
{your logging code here}
#endif
Something like that should do it for you, and then the code only gets compiled in Debug Mode.
You can also use the the Conditional attribute on a method like this:
[System.Diagnostics.Conditional("DEBUG")]
private void YourMethodNameHere(YourMethodSignatureHere)
Take a look at this old question for more information on when/why/how you might use them.
http://stackoverflow.com/questions/3788605/if-debug-vs-conditionaldebug

Why use singleton for application logging?

I was reading about the disadvantages of singleton patterns. A valid use of singleton suggested in many forums is the Logging application. I was wondering why this is a valid use of the pattern. Aren't we maintaing the state information in memory throughout the application?
Why not just use a function:
class Logger
{
public static void Log(string message)
{
//Append to file
}
}
To answer "why not just use a function": this code works incorrectly in multi-thread logging. If two threads try to write the same file, an exception will be thrown. And this is why it's good to use singleton for logging. In this solution, we have a thread safe singleton container, other threads push messages(logs) into the container safely. And the container(always a thread-safe queue) writes the messages/logs into a file/db/etc one by one.
It is better to declare interface:
interface ILogger
{
public void Log(string message);
}
Then implement specific type of logger
class FileLogger : ILogger
{
public void Log(string message)
{
//Append to file
}
}
class EmptyLogger : ILogger
{
public void Log(string message)
{
//Do nothing
}
}
And inject where required. You will inject EmptyLogger in tests. Using singleton will make testing harder, because you'll have to save to file in tests too. If you want to test if class makes correct log entries, you can use mock and define expectations.
About injection:
public class ClassThatUsesLogger
{
private ILogger Logger { get; set; }
public ClassThatUsesLogger(ILogger logger) { Logger = logger }
}
ClassThatUsesLogger takes FileLogger in production code:
classThatUsesLogger = new ClassThatUsesLogger(new FileLogger());
In tests it takes EmptyLogger:
classThatUsesLogger = new ClassThatUsesLogger(new EmptyLogger());
You inject different loggers in different scenarios. There are better ways to handle injections, but you'll have to do some reading.
EDIT
Remember you can still use singleton in your code, as others suggested, but you should hide its usage behind interface to loosen dependency between a class and specific implementation of logging.
I'm not sure what you are referring to when you ask about state information remaining in memory, but one reason to favour singleton over static for logging is that singleton still allows you to both
(1) program to abstractions (ILogger) and
(2) adhere to the dependency inversion principle by practicing dependency injection.
You can't inject your static logging method as a dependency (unless you want to pass something like Action<string> everywhere), but you can pass a singleton object, and you can pass different implementations like NullLogger when writing unit tests.
A singleton logger implementation allows for you to control easily how often your logging is being flushed to disk or the db. If you have multiple instances of the logger then they could all be trying to write at the same time which could cause collisions or performance issues. The singleton allows this to be managed so that you only flush to the store during quiet times and all your messages are kept in order.
In most circumstances the Singleton design pattern is not recommended, because it is a kind of Global State, hides dependencies (making APIs less obvious) and also hard to test.
Logging is not one of those circumstances. This is because logging does not affect the execution of your code. That is, as explained here: http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html :
your application does not behave any different whether or not a given
logger is enabled. The information here flows one way: From your
application into the logger.
You probably still don't want to use Singleton pattern though. Not quite at least. This is because there's no reason to force a single instance of a logger. What if you wanted to have two log files, or two loggers that behaved differently and were used for different purposes?
So all you really want for logger is to make it easily accessible from everywhere when you need it. Basically, logging is a special circumstances where the best way to go is to have it globally accessible.
The easy way is to simply have a static field in your application that contains the instance of logger:
public final static LOGGER = new Logger();
Or if your logger is created by a Factory:
public final static LOGGER = new LoggerFactory().getLogger("myLogger");
Or if your logger is created by a DI container:
public final static LOGGER = Container.getInstance("myLogger");
You could make your logger implementation be configurable, either through a config file, that you can set to "mode = test" when you are doing testing, so that the logger in those cases can behave accordingly, either not logging, or logging to the console.
public final static LOGGER = new Logger("logConfig.cfg");
You could also make the logger's behavior be configurable at runtime. So when running tests you can simply set it up as such: LOGGER.setMode("test");
Or if you don't make the static final, you can simply replace the static LOGGER with a test logger or mocked logger in the setup of your test.
Something slightly fancier you can do that is close to a Singleton pattern but not quite is:
public class Logger
{
private static Logger default;
public static getDefault()
{
if(default == null)
{
throw new RuntimeException("No default logger was specified.");
}
return default;
}
public static void setDefault(Logger logger)
{
if(default != null)
{
throw new RuntimeException("Default logger already specified.");
}
default = logger;
}
public Logger()
{
}
}
public static void main(String [] args)
{
Logger.setDefault(new Logger());
}
#Test
public void myTest()
{
Logger.setDefault(new MockedLogger());
// ... test stuff
}

Multiple threads accessing singleton object in VS2010

I'm using Visual Studio 2010 to write a simple C#/.NET GUI app, wherein I use a Logger class to write tracing/debugging info to a single file from within all of the various classes of the project. (See source code below.)
Each class's constructor writes an entry to the log when one of its object types is instantiated. One of those classes is a custom GUI controller component (class FileAttributesCtl), which is contained in a couple of the GUI forms used by the program.
The problem I'm having is that two logfiles are created, about 200 msec apart. The first logfile contains (only) a message that a FileAttributesCtl object has been constructed, and the second contains all of the other messages written to the (supposedly) shared logfile output stream. So every time I execute my project code, I get two logfiles.
Stranger still, every time I rebuild my project (F6), a logfile is created for the FileAttributesCtl object, indicating that an control object of this type is actually instantiated during the build process.
This apparently has something to do with threading. If the logfile is not named uniquely (i.e., if I do not append a unique date/time string to the filename), I get an exception, indicating that more than one process (which is actually the VS2010 process itself) is currently using the file.
So my question is: How do I get the singleton object to actually be a single object?
A secondary question is: Why is VS2010 acting this way?
//----------------------------------------
// Logger.cs
class Logger
{
// Singleton object
private static Logger s_logger =
new Logger("C:/Temp/foo.log");
public static Logger Log
{
get { return s_logger; }
}
private TextWriter m_out;
private Logger(string fname)
{
// Add a date/time suffix to the filename
fname = ...;
// Open/create the logging output file
m_out = new StreamWriter(
new FileStream(fname, FileMode.Create, FileAccess.Write,
FileShare.Read));
m_out.WriteLine(DateTime.Now.ToString(
"'$ 'yyyy-MM-dd' 'HH:mm:ss.fff"));
}
...
}
//----------------------------------------
// FileAttributesCtl.cs
public partial class FileAttributesCtl: UserControl
{
private Logger m_log = Logger.Log;
public FileAttributesCtl()
{
m_log.WriteLine("FileAttributesCtl()"); //Written to first logfile
InitializeComponent();
}
...
}
//----------------------------------------
// FileCopyForm.cs
public partial class FileCopyForm: Form
{
private Logger m_log = Logger.Log;
public FileCopyForm()
{
// Setup
m_log.WriteLine("FileCopyForm()"); //Written to second logfile
// Initialize the GUI form
m_log.WriteLine("FileCopyGui.InitializeComponent()");
InitializeComponent();
...
}
...
}
Note: This is very similar to a question from Dec 2009:
Access to singleton object from another thread
but it does not have the answers to my question.
Update
Further investigation shows that the VS2010 is indeed instantiating the custom component during the build, probably so that it can render it in the Designer window.
Also, there are indeed two separate threads calling the Logger constructor (each having a different ManagedThreadID).
Using a static class initializer to construct the singleton object does not work; I still get two logfiles.
Resolution
Upon closer examination, I notice that the custom control is getting instantiated twice, and this is being shown in both logfiles.
Therefore I think the problem is entirely due to the fact that VS instantiates the custom control object prior to executing the program that results in the first logfile being created. The second logfile is then created after the program starts normal execution.
Thus the first logfile is simply a side effect of the build process, and does not really have anything to do with multiple threads executing during normal program operation.
The obvious solution is to remove all logfile side-effect code from the component constructors. Or simply just ignore the first logfile altogether.
It could very well be that Visual Studio is building your UI component (to display in the designer) and in the process, your constructor is getting called which is why you're seeing that log file during the build process.
Static data + threads = trouble
You need to synchronize access to the singleton (and initialization of the singleton).
A static constructor may help
class Logger
{
private static Logger
static Logger()
{
s_logger = new Logger("C:/Temp/foo.log");
}
// ...
or better yet use a logging library (log4net) that handles all this stuff for you.
As for VS builds causing a log to be created, I'm not surprised. It is probably instantiating the forms to discover information about your forms via reflection.
update per comments
#LoadMaster "The static class initializer does not
work. I added more info to the logfile
output to include the current thread's
ManagedThreadID, and sure enough,
there are two different thread IDs
creating the two logfiles."
That's strange. Per MSDN
The static constructor for a class
executes at most once in a given
application domain. The execution of a
static constructor is triggered by the
first of the following events to occur
within an application domain:
An instance of the class is created.
Any of the static members of the class
are referenced.
Your thread must have moved AppDomains or there is some code missing from your snippets.

Categories

Resources