71

How would I write a log file in c#?

Currently i have a timer with this statement which ticks every 20 secs:

File.WriteAllText(filePath+"log.txt", log);

For everything that i want logged i do this:

log += "stringToBeLogged";

As you can assume the string log just grows and grows as the program runs. (I don't even know if there is a maximum chars per string?)

I assume that there must be better ways of doing this. i just thought that it would be heavy to write the whole file again and again for every time something is added to the log.

demonplus
  • 5,613
  • 12
  • 49
  • 68
user2725580
  • 1,293
  • 2
  • 17
  • 21

12 Answers12

77

From the performance point of view your solution is not optimal. Every time you add another log entry with +=, the whole string is copied to another place in memory. I would recommend using StringBuilder instead:

StringBuilder sb = new StringBuilder();
...
sb.Append("log something");

...
// flush every 20 seconds as you do it
File.AppendAllText(filePath+"log.txt", sb.ToString());
sb.Clear();

By the way your timer event is probably executed on another thread. So you may want to use a mutex when accessing your sb object.

Another thing to consider is what happens to the log entries that were added within the last 20 seconds of the execution. You probably want to flush your string to the file right before the app exits.

Karan Raiyani
  • 883
  • 6
  • 13
evpo
  • 2,436
  • 16
  • 23
  • 2
    [Here](http://www.aspsnippets.com/Articles/Create-simple-Error-Log-Text-File-in-ASPNet-using-C-and-VBNet.aspx) and [here](http://stackoverflow.com/a/2991300/2218697) is another **solution**. hope helps. – Shaiju T Dec 21 '16 at 12:43
  • 1
    It will throw exception if file is in used by multiple process parallelly. also it was not a thread safe. – Hiren Patel May 02 '22 at 06:04
  • 1
    This seems to only work once. If you run the program again it will not append or overwrite the file. –  Feb 09 '23 at 19:27
70

create a class create a object globally and call this

using System.IO;
using System.Reflection;


   public class LogWriter
{
    private string m_exePath = string.Empty;
    public LogWriter(string logMessage)
    {
        LogWrite(logMessage);
    }
    public void LogWrite(string logMessage)
    {
        m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        try
        {
            using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"))
            {
                Log(logMessage, w);
            }
        }
        catch (Exception ex)
        {
        }
    }

    public void Log(string logMessage, TextWriter txtWriter)
    {
        try
        {
            txtWriter.Write("\r\nLog Entry : ");
            txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                DateTime.Now.ToLongDateString());
            txtWriter.WriteLine("  :");
            txtWriter.WriteLine("  :{0}", logMessage);
            txtWriter.WriteLine("-------------------------------");
        }
        catch (Exception ex)
        {
        }
    }
}
BenKoshy
  • 33,477
  • 14
  • 111
  • 80
Aravind
  • 1,521
  • 2
  • 12
  • 23
  • 2
    This is a fantastic solution that worked gracefully! – Merin Nakarmi May 08 '18 at 18:34
  • 2
    Good, but with a static class and method, it would have been even cleaner. – Loïc Sombart Feb 22 '19 at 10:20
  • 1
    Just works like a charm. Straight Forward copy paste worked. – Siva Makani Apr 06 '22 at 10:25
  • It will throw exception if file is in used by multiple process parallelly. also it was not a thread safe. – Hiren Patel May 02 '22 at 06:05
  • 1
    Awesome solution! Simple to change it to a static class for .net 6 by just removing the constructor (public LogWriter...) section and adding the static keyword to the class description (public static void LogWrite). Then the class becomes globally available without having to construct it each time you want to log something. – Thumper33 Sep 16 '22 at 16:54
  • How are you supposed to call this? `LogWriter.LogWrite("test")`? –  Feb 09 '23 at 19:14
25

Use File.AppendAllText instead:

File.AppendAllText(filePath + "log.txt", log);
matth
  • 6,112
  • 4
  • 37
  • 43
  • 3
    +1 Just a small node: Make sure your filePath ends with a slash or add it. You should also add a new line like `File.AppendAllText(filePath + "\" + "log.txt", log + Environment.NewLine);` – nixda Nov 04 '16 at 21:08
  • given that in the question he specified `log += "stringToBeLogged";` this will not work properly because of incrementally adding the same information. The should be something like `File.AppendAllText(filePath + "log.txt", 'stringToBeLogged');` – Alex P. Dec 16 '16 at 14:47
  • @AlexPandrea right, so if he's logging the same `log` each time, `File.WriteAllText` would suite it better, even though that is a bit much. This solution suggests to log only specific information each time (appending), not writing the full `log` variable. – matth Dec 16 '16 at 16:20
  • 2
    @nixda, better use `Path.DirectorySeparatorChar` instead of hardcoded `\ char`. – Artfaith Jun 17 '20 at 04:01
  • 1
    @Angel instead of `Path.DirectorySeparatorChar` one can simply use `Path.Combine` method. e.g. `Path.Combine(filePath, "log.txt")` – polfosol ఠ_ఠ Feb 07 '22 at 18:52
  • It will throw exception if file is in used by multiple process parallelly. also it was not a thread safe. – Hiren Patel May 02 '22 at 06:05
17
public static void WriteLog(string strLog)
    {
        StreamWriter log;
        FileStream fileStream = null;
        DirectoryInfo logDirInfo = null;
        FileInfo logFileInfo;

        string logFilePath = "C:\\Logs\\";
        logFilePath = logFilePath + "Log-" + System.DateTime.Today.ToString("MM-dd-yyyy") + "." + "txt";           
        logFileInfo = new FileInfo(logFilePath);
        logDirInfo = new DirectoryInfo(logFileInfo.DirectoryName);
        if (!logDirInfo.Exists) logDirInfo.Create();
        if (!logFileInfo.Exists)
        {
            fileStream = logFileInfo.Create();
        }
        else
        {
            fileStream = new FileStream(logFilePath, FileMode.Append);
        }
        log = new StreamWriter(fileStream);
        log.WriteLine(strLog);
        log.Close();
    }   

Refer Link: blogspot.in

Mohan Kumar
  • 647
  • 7
  • 8
10

as posted by @randymohan, with using statements instead

public static void WriteLog(string strLog)
{
    string logFilePath = @"C:\Logs\Log-" + System.DateTime.Today.ToString("MM-dd-yyyy") + "." + "txt";
    FileInfo logFileInfo = new FileInfo(logFilePath);
    DirectoryInfo logDirInfo = new DirectoryInfo(logFileInfo.DirectoryName);
    if (!logDirInfo.Exists) logDirInfo.Create();
    using (FileStream fileStream = new FileStream(logFilePath, FileMode.Append))
    {
        using (StreamWriter log = new StreamWriter(fileStream))
        {
            log.WriteLine(strLog);
        }
    }
}
moldypenguins
  • 450
  • 5
  • 8
7

Very convenient tool for logging is http://logging.apache.org/log4net/

You can also make something of themselves less (more) powerful. You can use http://msdn.microsoft.com/ru-ru/library/system.io.filestream (v = vs.110). Aspx

  • 2
    There are heaps of good tutorials out there on Log4net. This one is where I got my start with Log4net: http://www.codeproject.com/Articles/140911/log4net-Tutorial – Jastill Nov 25 '13 at 05:27
7

Add log to file with Static Class

 public static class LogWriter
        {
            private static string m_exePath = string.Empty;
            public static void LogWrite(string logMessage)
            {
                m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                if (!File.Exists(m_exePath + "\\" + "log.txt"))
                    File.Create(m_exePath + "\\" + "log.txt");

                try
                {
                    using (StreamWriter w = File.AppendText(m_exePath + "\\" + "log.txt"))
                        AppendLog(logMessage, w);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            }

            private static void AppendLog(string logMessage, TextWriter txtWriter)
            {
                try
                {
                    txtWriter.Write("\r\nLog Entry : ");
                    txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),DateTime.Now.ToLongDateString());
                    txtWriter.WriteLine("  :");
                    txtWriter.WriteLine("  :{0}", logMessage);
                    txtWriter.WriteLine("-------------------------------");
                }
                catch (Exception ex)
                {
                }
            }
        }
Masoud Siahkali
  • 5,100
  • 1
  • 29
  • 18
  • This class needs little bit modification: m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!File.Exists(m_exePath + "\\" + "log.txt")){ string s = ""; s = DateTime.Now.ToString("h:mm:ss tt"); FileStream fs = File.Create(m_exePath + "\\" + "log.txt"); Byte[] info = new UTF8Encoding(true).GetBytes("File Created:"+s+"\r\n"); fs.Write(info, 0, info.Length);fs.Close(); }Otherwise at first program start you gonna have exception – Jevgenij Kononov Dec 19 '16 at 13:11
  • or simple close file immediately after creating – Jevgenij Kononov Dec 19 '16 at 13:12
4
if(!File.Exists(filename)) //No File? Create
{
    fs = File.Create(filename);
    fs.Close();
}
if(File.ReadAllBytes().Length >= 100*1024*1024) // (100mB) File to big? Create new
{
    string filenamebase = "myLogFile"; //Insert the base form of the log file, the same as the 1st filename without .log at the end
    if(filename.contains("-")) //Check if older log contained -x
    {
         int lognumber = Int32.Parse(filename.substring(filename.lastIndexOf("-")+1, filename.Length-4); //Get old number, Can cause exception if the last digits aren't numbers
         lognumber++; //Increment lognumber by 1
         filename = filenamebase + "-" + lognumber + ".log"; //Override filename
    }
    else 
    {
         filename = filenamebase + "-1.log"; //Override filename
    }
    fs = File.Create(filename);
    fs.Close();
}

Refer link:

http://www.codeproject.com/Questions/163337/How-to-write-in-log-Files-in-C

Monika
  • 2,172
  • 15
  • 24
2

This is add new string in the file

using (var file = new StreamWriter(filePath + "log.txt", true))
        {
            file.WriteLine(log);
            file.Close();
        }
Ilya
  • 48
  • 5
1

There are 2 easy ways

Dinesh Kumar P
  • 1,128
  • 2
  • 18
  • 32
0

If your application is multithreaded then in some environments file.appendalltext could give error like file already in use and if you skip that then you could lose important logs . For that you can use Lock object technique with file.append.. in that case it will wait for existing process to close and the write your log

This can also save you from adding other libraries in your source

0

Above code will throw: Process can't access the file because it is being used by another process error because of File.Create(m_exePath + "\" + "log.txt"); if you will comment out this it will work as expected

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SolutionLogWriter
{
    public static class LogWriterClass
    {
        private static string m_exePath = string.Empty;
        public static void LogWrite(string logMessage)
        {
            m_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            string fullpath = m_exePath + "\\" + "log.txt";
            
            if (File.Exists(fullpath))
            {
                File.Delete(fullpath);
            }
           // File.Create(fullpath);
            try
            {
                FileStream fs = new FileStream(fullpath, FileMode.OpenOrCreate);
                using (StreamWriter w = new StreamWriter(fs))
                    AppendLog(logMessage, w);
            }
            catch (Exception ex)
            {
                AppendLog(ex.ToString());
            }

        }

        private static void AppendLog(string logMessage, TextWriter txtWriter=null)
        {
            try
            {
                txtWriter.Write("\r\nLog Entry : ");
                txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
                txtWriter.WriteLine("  :");
                txtWriter.WriteLine("  :{0}", logMessage);
                txtWriter.WriteLine("-------------------------------");
            }
            catch (Exception ex)
            {
                txtWriter.Write(ex.Message);
            }
        }
    }
}