I'm writing a console application which is looking up information about SSIS packages in SQL Server. I have it working and writing to a .csv file. I just added in the ability to pass command line switches for servername, foldername and outputfile. If an output file is not specified, I'd just like to output to the console, which I'm already doing.
The way I've handled the file writing seems awkward, and is probably wrong.
In my main method I create a StreamWriter. I need to write the entire output of the program to this file. I explore folders under my specified folder by recursively calling a function.
I pass the StreamWriter object along in all calls - it is a parameter in functions which don't use it, so it can be passed to the one that does. It seems like I should be able to make it a global variable, but I see that c# doesn't have globals and "if you are using a global, you are probably doing it wrong".
I'd planned on revisiting this issue eventually after plugging away at this little utility for a while, but I now have the problem that all the functions want the StreamWriter object - and if I make it optional, then it won't be there for the functions. And it also seems c# doesn't do optional arguments.
I'm sure you can tell I'm no c# expert and only dabble when I need to. Thanks for your assistance.
You want to use a singleton pattern to refer to the StreamWriter you're using. The singleton is a way to "simulate" the functionality of global variables, without having the problems of them.
Essentially, what the singleton provides is a class-specific instance of a resource you want to be shared among many different parts in your application. The resource is accessed through the a static class instance.
Effectively, what you'll want to do is to define a class which has as a public static member the StreamWriter that you'll want to use; in that way, any method that you use in the rest of your code can get access to that SAME instance of the StreamWriter by accessing it from the containing class (without needing to create an instance of the class, because it's static).
Something like
public static class CsvWriter
{
private static StreamWriter _writer = new StreamWriter(...);
public static StreamWriter Writer
{
get { return _writer; }
}
}
Some variation is possible, the main item is the static property here. It's like a global but not (entirely) as bad.
Are all the functions of the same class? You can make a class variable (a field) and access it from all the methods of the class. If not you can always create a new public class with a static field.
I you can use Console.SetOut for this:
static void Main(string[] args)
{
StreamWriter writer = new StreamWriter(#"c:\path\file.ext");
try
{
Console.SetOut(writer);
Console.WriteLine("One");
Console.WriteLine("Two");
Console.WriteLine("Three");
}
catch (Exception ex)
{
Console.WriteLine("That went wrong.");
}
finally
{
writer.Dispose();
}
}
Related
I have a very simple logging mechanism in my application which periodically writes a line to a file (a logging library would be overkill for my needs) which looks something like this:
private string logfile = #"C:\whatever.log";
public void WriteLine(string line)
{
using(FileStream fs = File.Open(logfile, FileMode.Append))
{
// Log Stuff
}
}
So any time I call that method, a new FileStream is created and disposed after logging is finished. So I considered using an already instantiated object to prevent the continuous creation of new objects:
private string logfile = #"C:\whatever.log";
private FileStream myStream = File.Open(logfile, FileMode.Append);
public void WriteLine(string line)
{
using(myStream)
{
// Log Stuff
}
}
However, the MSDN reference discourages this (last example), due to scope issues.
What does one do in that case? Is the overhead in my first example negligible?
The using statement doesn't do anything else than calling the Dispose() method of the object.
So considering your second example, after the first call to the WriteLine(string) method the filestream is disposed. So any other call, after the first one, to this Method will result in an exception.
Using the File.AppendText() method like Chris had suggested in the comment would be a way to go. But keep in mind, that using this or any other File... method will also open a stream and close and dispose it afterwards.
It will just result in less code.
The second approach does also dispose the stream every time you call WriteLine since you are also using the using-statement. MSDN discourages from this approach because the variable myStream does still "exist" even if the object is disposed. So that is more error-prone.
If you often need to use this method you should cosider to use the using "outside" or use a try-catch-finally:
var myLogger = new MyLogger();
try
{
// here is your app which calls myLogger.WriteLine(...) often
}
catch(Exception ex)
{
// log it
}
finally
{
myLogger.Dispose(); // myLogger is your Log class, dispose should call myStream.Dispose();
}
The overhead might not be negligible, but that might be beside the point.
When you are using using, the creation, acquisition of resource and the disposing of the used resources is nicely scoped. You know where it starts, where it's used, and where it's finished.
If you go for the second scenario, you know where it starts (it's when the containing class is created), but after that, you have no platform-guaranteed way to control where it's used, and where (if at all) the resources are disposed.
You can do this yourself if this is critical code, and your containing class implements the IDisposable pattern properly, but this can be tricky and not for the faint of heart :)
However, you stated in the question "a logging library would be overkill for my needs", so I think you are fine with the minimal overhead. IMHO, you should be fine with one of the ready-made File methods, like File.AppendAllText:
public void WriteLine(string line)
{
//add an enter to the end
line += Environment.NewLine;
File.AppendAllText(logfile, line);
}
or File.AppendAllLines:
public void WriteLine(string line)
{
File.AppendAllLines(logfile, new []{line});
}
I am using an XML file to store the values. This XML file can be accessed from multiple methods.
Private object lockObject = new object()
Method1
{
Lock(this.lockObject)
{
MyCommonMethod()
}
}
Timer.ElapseEvent
{
Lock(this.lockObject)
{
MyCommonMethod()
}
}
MyCommonMethod()
{
// Read/Write to XML file.
var element = XElement.Load(path);
// some operations
element.save(path)
}
Now, this class is been used by multiple projects(Services) which in turn are combined in to a single project.
Can i use STATIC lock object in a class and will it work in this case of different processes??
So there are possibility that they use the file at same time and at times it gives me the error that different thread owns the file although i've kept the LOCK.
what could be the best solution in this senario?
Please guide.
How about this link ...
Is there a way to check if a file is in use?
is this the best way to go for or i should go with Mutex??
Please guide..
It looks like it's not the "different app domains" problem but "different processes" problem. Anyway, you could apply stricted syncrhonizations solutions like mutex:
mutex.WaitOne();
MyCommonMethod();
mutex.ReleaseMutex();
Also, if you're using C# 4.0, you could use Memory-Mapped I/O for this purposes.
A static variable will not be shared among difference processes.
You can either:
lock the file itself (pass the FileShare.None to FileStream constructor, then use that stream for reading XML), or
use a global mutex (pass the non-empty name to Mutex constructor).
The option (1) will not block in case file is already locked (it'll just throw the exception immediately) - you'll have to "poll" the file repeatedly if you want to emulate the blocking behavior. On the other hand, the option (2) will work only as long as your application is the only one accessing the file. Pick your poison.
public class SimpleLogger
{
static readonly string logFile = ConfigurationManager.AppSettings["LogFile"];
static StreamWriter GetStream()
{
return File.Exists(logFile) ?
File.AppendText(logFile) : File.CreateText(logFile);
}
public static void Write(string msg)
{
using (var sw = GetStream())
{
sw.Write(msg);
}
}
}
The above code fails in use as it doesn't appear to be closing/disposing of the stream correctly. Subsequent writes give a 'file in use' IOException.
If the class is modified to use non-static methods, it appears to work correctly.
I don't understand why there would be any behavioural difference?
The disposal is fine; GetStream delivers an open writer; Write closes/disposes it - sorted. if I had to guess, though, the issue is concurrent use - i.e. multiple threads (in particular in a web application) accessing the file at the same time. If that is the case, options:
make Write (and any other access to the file) synchronized, so only one caller can possibly try to have the file open at once
use a pre-canned logging framework that will already handle this scenario (common approaches here include synchronization, but also: buffering the data locally and then pushing the data down periodically - avoids opening the file over and over and over and over)
In particular; your only static state is the file path itself. There will therefore be no significant difference between using this as a static versus instance method.
As a side-note, File.AppendAllText may be useful here, but does not avoid the issue of concurrency.
I don't think changing from a static to an instance would fix the problem since they're all ultimately contending over a static resource (the file). This answer might help you. Perhaps if you left both methods static and declared a static synchronisation object for calling threads to lock with (since the resource is static itself) would help?, e.g.:
private static object _objectLock = new object();
for synchronising access to the file from multiple threads, hence:
public static void Write(string msg)
{
lock(_objectLock)
{
using (var sw = GetStream())
{
sw.Write(msg);
}
}
}
I am trying to figure out the best strategy for logging on the async-IO web server I am working on. I thought the easiest way was to have a singleton class that keeps Filestreams open for the appropriate log files so I could just do something like:
Util.Logger.GetInstance().LogAccess(str);
Or something like that.
My class looks like this:
public sealed class Logger {
private static StreamWriter sw;
private static readonly Logger instance = new Logger();
private Logger() {
sw = new StreamWriter(logfile);
}
public static Logger GetInstance() {
return instance;
}
public void LogAccess(string str) {
sw.WriteLine(str);
}
}
This is all just in my head really, and I'm looking for suggestions on how to make it better and also make sure I'm doing it properly. The biggest thing is I need it to be thread safe, which obviously it is not in its current state. Not sure of the best way to do that.
This is taken care of for you automatically if you use NLog - you define all of your loggers in a .config file and then you access all of them via the static LogManager class, which is a Singleton.
Here's an example which illustrates the thread-safe nature of NLog:
https://github.com/nlog/nlog/wiki/Tutorial#Adding_NLog_to_an_application
There's a method TextWriter.Synchronized which produces a thread-safe version of TextWriter. Try that.
a) Do not include "Log" in method names. It obvious that a logger logs. .Warning, .Error, etc are better method names since they describe which level the log entry has.
b) Create a background thread that writes to the log.
c) Enqueue entries from the logging methods and signal the worker thread.
d) Use (I don't know if I remember the method names correctly)
var methodInfo = new StackFrame(1).GetMethod();
var classAndMethod = methodInfo.DeclaringType.Name + "." + methodInfo.Name;
to get the calling method.
Doing that will give you only one thread that access the file.
Maybe you should try NLog or Log4net. Both of them are wonderful log framework.
But if you do want to write your own log component, Lock is a must when you output log messages.
It's common that buffering log messages in memory and write them to file once in a time.
Another framework that addreses these issues for you is the Object Guy's logging framework. It can optionally log in the background. Multiple threads can log to the same file. And multiple processes can log to the same file.
I don't think there's any simple way around locking if you want to write to the same file from multiple threads.
So the simple solution is to add a lock around any calls to the StreamWriter. Alternatively you could buffer the output in memory and only write it to the file once in a while which still requires locking, but the lock contention would be a lot lower. If you go to that length, though, you might as well go with a proper logging framework like log4net, which is thread-safe.
Or you could use a class with only shared methods..
Imports System.Threading
Public Class Logger
Private Shared ReadOnly syncroot As New Object
Public Shared Sub log(ByVal vInt As Integer)
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf logThread), CStr(vInt))
End Sub
Public Shared Sub log(ByVal vStr As String)
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf logThread), vStr)
End Sub
Private Shared Sub logThread(ByVal o As Object)
Dim str As String = CStr(o)
SyncLock syncroot
Using objWriter As New System.IO.StreamWriter(GetLogPath, True)
objWriter.WriteLine(str)
objWriter.Close()
End Using
End SyncLock
End Sub
Private Shared Function GetLogPath() As String
Return "logs.txt"
End Function
End Class
I found it more usable this way than using a singleton :
Logger.log("Something to log")
Cheers
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.