Thursday, March 22, 2012

Text written to StreamWriter disappears when it is closed

Hi, I wrote my own logger class to log any errors in my program to a file. The idea is simply to provide a wrapper for the TextWriter or StreamWriter class that adds the ability to write strings, exceptions and to move the file. However when I run a very simple test program, closing the stream erases the contents of the file. My code is below:

First the class:

public class Logger
{
private System.IO.StreamtWriter sw_log;
private string log_path;

public Logger(string fpath,bool append)
{
GIM.Utility.ensure_path_exists(fpath);
sw_log =new System.IO.StreamWriter(fpath, append);
log_path = fpath;
}

public void Log(string s)
{
GIM.Utility.ensure_path_exists(log_path);
sw_log.WriteLine(s);
}

public void Log(Exception e)
{
if(e.InnerException !=null)
Log(e.InnerException);
Log("Error: "+e.Message);
}

public void MoveFile(string destination_path)
{
sw_log.Close();
System.IO.File.Move(log_path, destination_path);
sw_log =new System.IO.StreamWriter(destination_path,true);
log_path = destination_path;
}

public string GetLogContents()
{
sw_log.Close();

string s = String.Empty;
System.IO.StreamReader sr =new System.IO.StreamReader(log_path);
s = sr.ReadToEnd();
sr.Close();

sw_log =new System.IO.StreamWriter(log_path);
return s;
}

public void Close() {sw_log.Close();}


Now the test program:

using System;
namespace LoggerTest
{
class Class1
{

[STAThread]
static void Main(string[] args)
{
string path ="C:\\test\\other_deployment.log";
Logger L =new Logger(path,true);
L.Log("test test test");
L.Close();

Console.WriteLine(L.GetLogContents());
L.Close();
Console.ReadLine();

Console.WriteLine("----------");
System.IO.StreamReader sr =new System.IO.StreamReader(path);
Console.WriteLine(sr.ReadToEnd());
sr.Close();
Console.ReadLine();
}
}
}

The result is:

test test test

--------

(blank line because nothing is read in)

And an empty file

Does anyone have any idea what might be going on?

Try calling .Flush() before you close the stream.


I would suggest that you simplify the process. Write to the log file and see if that works. Then read from the log file. Then when both are working try moving the file.

Better yet, write the log file to where you want it and don't waste time with the move.

Your code looks overly complicated and you are opening and closing the file rather frequently. Is that really needed?

Personally I use:

Public sLogasString

Public wAs StreamWriter = File.AppendText("C:\path\error.log")

sLog = ControlChars.CrLf &"Started: " & Now

sLog = sLog & ControlChars.CrLf &"###################"

'add details as needed

sLog = sLog & ControlChars.CrLf &"Ended: " & Now

sLog = sLog & ControlChars.CrLf &"###################"

w.Write(sLog)

w.Flush

w.Close

w =Nothing

and it works fine.


rewrote the close method as:

public void Close() {sw_log.Flush();sw_log.Close();}

Still getting the same result


kraznodar,

I had something to that extent before, I just had a simple function doing logging and it worked. However it has become prudent to move the logging responsibilities to a separate object since I am now writing to multiple logs and specifically because I would like to keep from opening and closing the file too much.

If you look at the code in the Logger class it actually opens and closes the file only when absolutely necessary (when opening it the first time, when close is called, and when moving)


First of all, why do you not have a "new" sub? Instead of a sub called logger try calling it new so it complies with OOP standards.


Comment out the move and see if the file is still empty.


No clue what you're talking about, please explain. Are you confused about why I do not have the keyword 'sub' in there anywhere? It is because this is c# not vb


What the hell are you talking about? The move never runs, I don't call it at any point.


kraznodar:

First of all, why do you not have a "new" sub? Instead of a sub called logger try calling it new so it complies with OOP standards.

I don't make sense here! Ignore that post.


Are you actually going into "My Computer" and manually opening the file to check it's content? If not, then try that and see if the file is actually empty or if it has content but isn't reading correctly. I think I'm not helping here so hopefully a C# person can step in and do a better job. Sorry I'm not more benefit to you.


Yes, the file is actually empty, 0 bytes and opening it in notepad shows it being empty. I feel like this might be a matter of using the wrong keyword in instantiating the sw_log variable?


Umm...bump.

Lots of posts, no solution


Here is a logger that I wrote. I am not sure what it wrong with yours, but it does do everything that yours should do. The difference is it uses the same stream for reading / writing, and it supports a couple of other operations. It also implements IDisposable:

1public class Logger : IDisposable2{3public const string DEFAULT_LOG_PATH = @."C:\logs\mylog.log";4private readonly string _logPath;5private readonly bool _append;6private readonly OpenBehavior _openBehavior;7const int BUFFER_SIZE = 0x1000;8private FileStream _writer;9private readonly byte[] _newLine;10private bool _hasWrittenOnce =false;1112public Logger(string logPath,bool append, OpenBehavior openBehavior)13{14_newLine = Encoding.Default.GetBytes(Environment.NewLine);15_logPath = logPath;16_append = append;17_openBehavior = openBehavior;18InitialFileSystem();19InitializeStream();20}212223public Logger(bool append)24:this(DEFAULT_LOG_PATH, append, OpenBehavior.AutoCreate)25{ }2627public Logger(OpenBehavior openBehavior)28:this(DEFAULT_LOG_PATH,true, openBehavior)29{ }3031public Logger()32:this(true)33{ }3435private void InitialFileSystem()36{37string directory =new FileInfo(_logPath).Directory.FullName;38bool doesPathExist = Directory.Exists(directory);39bool doesFileExist = File.Exists(_logPath);40if (!doesPathExist || !doesFileExist)41{42if (_openBehavior == OpenBehavior.ThrowIfDoesNotExist)43throw new Exception("The logging file \"" + _logPath + "does not exist.");44if (!doesPathExist)45Directory.CreateDirectory(directory);46}47}4849private void InitializeStream()50{51_writer =new FileStream(_logPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, BUFFER_SIZE, FileOptions.WriteThrough);52}5354private void WriteLine(string line)55{56if (!_hasWrittenOnce && !_append)57{58_writer.SetLength(0);59}60else if (!_hasWrittenOnce && _append)61{62_writer.Position = _writer.Length;63}64int dataLength = Encoding.Default.GetByteCount(line);65byte[] data =new byte[dataLength + _newLine.Length];66Buffer.BlockCopy(Encoding.Default.GetBytes(line), 0, data, 0, dataLength);67Buffer.BlockCopy(_newLine,0,data,dataLength,_newLine.Length);68_writer.Write(data, 0, data.Length);69_hasWrittenOnce =true;70}7172public void Log(string message)73{74WriteLine(message);75}7677public void Log(Exception exception)78{79if (exception.InnerException !=null)80Log(exception.InnerException);81Log(exception.Message);82}8384public void MoveLog(string newPath)85{86if(!Directory.Exists(newPath))87Directory.CreateDirectory(newPath);88string fileName = Path.GetFileName(_logPath);89string newPathWithFile = Path.Combine(newPath, fileName);90_writer.Flush();91_writer.Dispose();92File.Move(_logPath, newPathWithFile);93_writer =new FileStream(newPathWithFile, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, BUFFER_SIZE, FileOptions.WriteThrough);94}9596public string ReadLog()97{98StringBuilder log =new StringBuilder((int)_writer.Length);99long previousPos = _writer.Position;100_writer.Position = 0;101int bytesRead;102byte[] buffer =new byte[BUFFER_SIZE];103while ((bytesRead = _writer.Read(buffer, 0, BUFFER_SIZE)) != 0)104{105string data = Encoding.Default.GetString(buffer,0, bytesRead);106log.Append(data);107}108_writer.Position = previousPos;109return log.ToString();110}111112public void TruncateLog()113{114_writer.SetLength(0L);115}116117public void CopyLogToStream(Stream stream)118{119long previousPos = _writer.Position;120_writer.Position = 0;121BlockCopy(_writer, stream);122_writer.Position = previousPos;123}124125private void BlockCopy(Stream input, Stream output)126{127byte[] buffer =new byte[BUFFER_SIZE];128int bytesRead;129while ((bytesRead = input.Read(buffer, 0, BUFFER_SIZE)) != 0)130{131output.Write(buffer, 0, bytesRead);132output.Flush();133}134}135136public void Dispose()137{138_writer.Flush();139_writer.Dispose();140GC.WaitForPendingFinalizers();141GC.SuppressFinalize(this);142}143144~Logger()145{146Dispose();147}148}149150public enum OpenBehavior151{152ThrowIfDoesNotExist,153AutoCreate154}

You would use it like this:

static void Main(){using (Logger logger =new Logger()){try{logger.Log("Log message!");throw new Exception("TEST Exception");}catch (Exception e){logger.Log(e);}logger.CopyLogToStream(Console.OpenStandardOutput());Console.WriteLine(new string('-', Console.BufferWidth-1));Console.Write(logger.ReadLog());Console.ReadKey(true);}}

Today,I just registered.
But I hnow a little English.
I hope everyone can help me more.
hard study and study with you.

0 comments:

Post a Comment