Search code examples
c#regexwpflogfile-analysis

Read log file from last read position


This is my working code, I have a filewatcher monitoring my log file, when the file updates (it updates a lot) it reads the log and outputs the lines that comply with the regex to a textbox. The problem with it is that it reads the file from the beginning and re-prints the regexed lines again so I get repeated data in the textbox. I also don't know if I have it setup correctly to run the file read from a separate thread so my program don't "freeze" while reading large log files.

private void btnStart_Click(object sender, EventArgs e)
{
    if ((Properties.Settings.Default.setting_logfile != "") && (Properties.Settings.Default.setting_logfolder != ""))
    {
        if (btnStart.Text == "Start Parsing")
        {
            // change text on button and switch status image
            btnStart.Text = "Stop Parsing";
            pbStatus.Image = Properties.Resources.online;

            new Thread(() => Run()).Start();
        }
        else
        {
            btnStart.Text = "Start Parsing";
            pbStatus.Image = Properties.Resources.offline;
            fsWatcher.EnableRaisingEvents = false;
        }
    }
    else
    {
        tbOutput.Text = "Please select a log file to parse.";
    }
}

private void Run()
{
    try
    {
        fsWatcher.Changed += new FileSystemEventHandler(OnChanged);
        fsWatcher.EnableRaisingEvents = true;
    }
    catch (Exception ex)
    {
        MessageBox.Show("An error occurred: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

private void OnChanged(object source, FileSystemEventArgs e)
{
    string line;

    Regex pattern = new Regex(@"\[[\w :]+\]\s<SYSTEMWIDE_MESSAGE>:");

    Stream stream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    StreamReader streamReader = new StreamReader(stream);

    while ((line = streamReader.ReadLine()) != null)
    {
        Match match = pattern.Match(line);
        if (match.Success)
        {
            tbOutput.AppendText(line + "\r\n");
        }
    }
    streamReader.Close();
    stream.Close();
}

Solution

  • You could remember the last position that you read at and start from there.

     Regex pattern = new Regex(@"\[[\w :]+\]\s<SYSTEMWIDE_MESSAGE>:");
     long lastPosition = 0;
    
     private void OnChanged(object source, FileSystemEventArgs e)
     {
       string line;
    
    
       Stream stream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read,     FileShare.ReadWrite);
       stream.Seek(lastPosition, SeekOrigin.Begin);
       StreamReader streamReader = new StreamReader(stream);
    
       while ((line = streamReader.ReadLine()) != null)
       {
          if (pattern.Match(line).Success)
          {
            tbOutput.AppendText(line + Environment.NewLine);
          }
       }
       lastPosition = stream.Position;  // may need to subtract 1!!!
       streamReader.Close();
       stream.Close();
    }