title: Archiving Log Files
body: <p>I have just rewritten a windows service  process that outputs important info debug to a log file in the /programdata/myservice/ folder.</p>
  
  <p>However at night at midnight I have a job that is supposed to take the current days log file and remove it's contents and then create an archived logfile with the date in the name for 3 days e.g LogfileArchived15092014.log.</p>
  
  <p>Some code then runs to delete log files older than this date so I only ever have todays current log file and 2 archived ones for debugging older issues etc.</p>
  
  <p>Now I have copied the code that does this from an old service that is working and it archives the log files and deletes old ones. However for some reason when this new job runs I get I/O errors such as this (from the event viewer)</p>
  
  <p>Error Running System Jobs: I/O Error archiving log file: C:\ProgramData\Brainiac\LogfileArchived; The process cannot access the file 'C:\ProgramData\Brainiac\Logfile.log' because it is being used by another process.</p>
  
  <p>Now the reason the first path doesn't have an extension on it e.g C:\ProgramData\Brainiac\LogfileArchived is because it's obviously thrown an error before it's got to the part where the file date is created to be appended to the filename e.g</p>
  
  <pre><code>// set a lock up to prevent other processes locking
  this.Locked = true;
  
  // wrap in try as it keeps failing!!!!
  try
  {
      // take contents of current log file - the daily one I have been logging to all day      
      // I guess this is where the error is being raised due to the absence 
      // of a .log extension in the error message when mentioning the filename
      string content = this.ReadFileString(this.logFilePath);
  
      // for some reason todays log file was empty 
      // why would this be unless loggging was disabled?
      if (!String.IsNullOrEmpty(content))
      {
          // create a new log file with date stamp of yesterday added to the filename and guff removed to make it valid
          string file_date = DateTime.Now.Date.AddDays(-1).ToString().Replace("/", "").Replace("-", "");
  
          // remove time part - should be done at midnight but if not ensure colons and spaces are removed
          file_date = file_date.Replace("00:00:00", "").Replace(":", "").Replace(" ", "");
  
          // append .log to it
          this.logfilearchivepath += file_date + ".log";
  
          //Append all the contents of my daily log file to this new file 
          File.AppendAllText(this.logfilearchivepath, content, Encoding.UTF8);
  </code></pre>
  
  <p>So I suspect it is bombing out on this line  </p>
  
  <pre><code>string content = this.ReadFileString(this.logFilePath);
  </code></pre>
  
  <p>Due to no extension being in the error message. So maybe I need a different way of accessing the contents?</p>
  
  <p>Now I don't know what other process has it locked (can I find out somehow?) but I have tried the following.</p>
  
  <ol>
  <li>Ensuring I don't have the file open on my own computer.</li>
  <li><p>Adding a flag in which is supposed to prevent ANY logging to the log file. As you can see at the top I go</p>
  
  <p>// set a lock up to prevent other processes locking
  this.Locked = true;</p></li>
  </ol>
  
  <p>and in my method that does the logging I have a check for it to exit ASAP e.g</p>
  
  <pre><code>// log to our application data folder - unless locked for some reason
  public void LogMsg(string msg, string debugLevel = "HIGH")
  {
     // we are prevented from logging at this point in time
     if (this.Locked) return;
  </code></pre>
  
  <ol start="3">
  <li><p>I also have wrapped the call to the ArchiveLogFile() method in 3 try/catch statements, each with a Thread.Sleep in between of longer and longer gaps in case something was still logging.</p></li>
  <li><p>I have also tried using DB locks. </p></li>
  </ol>
  
  <p>So I have a table called LOCKS and methods to insert/remove a lock record and also a method to check one doesn't exist. </p>
  
  <p>So if multiple processes tried running the same code at the same time from different apps then it shouldn't be able to as a lock record would exist in the database which gets inserted before the job starts running and is removed after the job has completed (a RUNNING lock) </p>
  
  <p>Also once completed a LOGFILE_ARCHIVED lock record is inserted so that the same OR a different job knows the log file has been archived and doesn't try to archive it again. </p>
  
  <p>I use the computers name in the lock files as the process could run on multiple servers/computers at any one time.</p>
  
  <p>So what other solutions could I do to get round this problem?</p>
  
  <p>Should I use a different method for obtaining the log file contents that wouldn't be blocked by something locking the file (I don't know what is doing the locking but the this.Locked = True should prevent anything being logged to the file during the archive job) but obviously the "lock" on the file is higher up than my code.</p>
  
  <p>This is a windows service written in C# .NET 4.5 on a Win 7 machine.</p>
  
  <p>Thanks for your help.</p>