libi2ncommon: (tomj) log file reader class
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Wed, 11 Oct 2006 07:49:39 +0000 (07:49 +0000)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Wed, 11 Oct 2006 07:49:39 +0000 (07:49 +0000)
src/Makefile.am
src/logread.cpp [new file with mode: 0644]
src/logread.hxx [new file with mode: 0644]

index 1a698e6..7b571fa 100644 (file)
@@ -3,9 +3,9 @@
 INCLUDES = -I$(top_srcdir)/src @LIBGETTEXT_CFLAGS@ @LIBICONV_CFLAGS@ $(all_includes)
 
 # the library search path.
-lib_LTLIBRARIES =  libi2ncommon.la
-include_HEADERS = insocketstream.hxx oftmpstream.hxx pipestream.hxx filefunc.hxx stringfunc.hxx timefunc.hxx ipfunc.hxx ip_type.hxx
-libi2ncommon_la_SOURCES = oftmpstream.cpp ipfunc.cpp timefunc.cpp filefunc.cpp stringfunc.cpp
+lib_LTLIBRARIES = libi2ncommon.la
+include_HEADERS = logread.hxx insocketstream.hxx oftmpstream.hxx pipestream.hxx filefunc.hxx stringfunc.hxx timefunc.hxx ipfunc.hxx ip_type.hxx
+libi2ncommon_la_SOURCES = logread.cpp oftmpstream.cpp ipfunc.cpp timefunc.cpp filefunc.cpp stringfunc.cpp
 
 # Note:  If you specify a:b:c as the version in the next line,
 #  the library that is made has version (a-c).c.b.  In this
diff --git a/src/logread.cpp b/src/logread.cpp
new file mode 100644 (file)
index 0000000..b241ed5
--- /dev/null
@@ -0,0 +1,164 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdexcept>
+
+#include "logread.hxx"
+
+using namespace std;
+
+/// Constructor
+logread::logread(string filename, bool _goto_end)
+{
+    this->filename = filename;
+    reset();
+
+    if (_goto_end)
+        goto_end();
+}
+
+/// Reset line state engine
+void logread::reset()
+{
+    logsize = 0;
+    logsize_old = 0;
+
+    line.clear();
+    line_complete = false;
+}
+
+/// Skip initial content. Useful when parsing /var/log/messages
+void logread::goto_end()
+{
+    struct stat my_stat;
+    if (stat(filename.c_str(), &my_stat) == 0) {
+        logsize = my_stat.st_size;
+        logsize_old = logsize;
+    }
+}
+
+/// Main read loop
+void logread::read()
+{
+    // check if size changed
+    if (check_changed()) {
+        if (logsize > logsize_old) {
+            string logChanges = getLogChanges();
+
+            do {
+                extractSingeLine (logChanges);
+                line_complete == true ? processLine() : processUnfinishedLine();
+            } while (!logChanges.empty());
+        } else
+            reset();    // file got truncated
+
+        logsize_old = logsize;
+    }
+}
+
+/// Check if file is modified
+bool logread::check_changed()
+{
+    bool changed = false;
+
+    struct stat my_stat;
+    if (stat(filename.c_str(), &my_stat) == 0
+        && my_stat.st_size != logsize)
+    {
+        logsize = my_stat.st_size;
+        changed = true;
+    }
+
+    return changed;
+}
+
+/// Get changed content since last read
+string logread::getLogChanges()
+{
+    // open logfile
+    FILE *log = fopen (filename.c_str(), "r");
+    if (!log)
+        return "";
+
+    // read logfile
+    int size = logsize-logsize_old;
+
+    char *read_buffer = new char [size+1];
+    if (fseek (log, logsize_old, SEEK_SET) != 0)
+        throw runtime_error("can't seek in file " + filename);
+    fread (read_buffer, size, 1, log);
+    if (ferror(log))
+        throw runtime_error("error reading from file " + filename);
+    fclose (log);
+
+    read_buffer[size] = 0;
+    string changes(read_buffer);
+    delete[] read_buffer;
+
+    return changes;
+}
+
+/// Extract a single line from input buffer
+void logread::extractSingeLine(string &input)
+{
+    string::size_type rtn_pos, copysize;
+
+    // go to next line
+    if (line_complete) {
+        line_complete = false;
+        line.clear();
+    }
+
+    rtn_pos = input.find("\n", 0);
+
+    // complete line or even multi-line
+    if (rtn_pos != string::npos)
+        copysize = rtn_pos;
+    else
+        copysize = input.length();
+
+    line.append (input.c_str(), copysize);
+
+    // Erase data from the input buffer
+    if (rtn_pos == string::npos)    // no return found
+        input.erase (0, copysize);
+    else {
+        // also erase the return
+        input.erase (0, copysize+1);
+        line_complete = true;
+    }
+}
+
+/** Short example
+
+#include <iostream>
+class logread_syslog : public logread
+{
+public:
+    logread_syslog() : logread("messages", false) {};
+
+    void processLine()
+    {
+        cout << "finished: " << line << endl;
+    }
+
+    void processUnfinishedLine()
+    {
+        cout << "unfinished: " << line << endl;
+    }
+};
+
+int main(void)
+{
+    logread_syslog messages;
+
+    while (1) {
+        messages.read();
+        sleep(1);
+    }
+
+    return 0;
+}
+*/
diff --git a/src/logread.hxx b/src/logread.hxx
new file mode 100644 (file)
index 0000000..7f796d2
--- /dev/null
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *   Copyright (C) 2006 by Thomas Jarosch                                  *
+ *   info@intra2net.com                                                    *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef __LOGREAD_HXX
+#define __LOGREAD_HXX
+
+#include <string>
+
+/**
+    Log file reader class.
+
+    Works on complete and incomplete lines.
+    Devire from this class and implement your
+    own processLine() / processUnfinishedLine() function.
+*/
+class logread
+{
+public:
+    logread(std::string filename, bool _goto_end=false);
+    void read();
+
+protected:
+    std::string line;
+
+    virtual void processUnfinishedLine() {};
+    virtual void processLine() {};
+
+private:
+    // Internal implementation
+    void reset();
+    void goto_end();
+
+    bool check_changed();
+    bool process();
+
+    std::string getLogChanges();
+    void extractSingeLine (std::string &input);
+
+    std::string filename;
+    int logsize;
+    int logsize_old;
+
+    bool line_complete;
+};
+
+#endif