From 7113c4f097e2f8c1410d238317fd481fde8c8883 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Wed, 11 Oct 2006 07:49:39 +0000 Subject: [PATCH] libi2ncommon: (tomj) log file reader class --- src/Makefile.am | 6 +- src/logread.cpp | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/logread.hxx | 49 ++++++++++++++++ 3 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 src/logread.cpp create mode 100644 src/logread.hxx diff --git a/src/Makefile.am b/src/Makefile.am index 1a698e6..7b571fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000..b241ed5 --- /dev/null +++ b/src/logread.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +#include + +#include + +#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 +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 index 0000000..7f796d2 --- /dev/null +++ b/src/logread.hxx @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2006 by Thomas Jarosch * + * info@intra2net.com * + * * + ***************************************************************************/ + +#ifndef __LOGREAD_HXX +#define __LOGREAD_HXX + +#include + +/** + 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 -- 1.7.1