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
--- /dev/null
+#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;
+}
+*/
--- /dev/null
+/***************************************************************************
+ * 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