Merge branch 'daemon-ext'
[libi2ncommon] / src / logread.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
7113c4f0
TJ
20#include <stdlib.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
a74046f1 24#include <stdio.h>
7113c4f0 25
8843e320 26#include <fstream>
7113c4f0
TJ
27#include <stdexcept>
28
8843e320
TJ
29#include <boost/scoped_array.hpp>
30
7113c4f0
TJ
31#include "logread.hxx"
32
33using namespace std;
34
35/// Constructor
36logread::logread(string filename, bool _goto_end)
37{
38 this->filename = filename;
39 reset();
40
41 if (_goto_end)
42 goto_end();
43}
44
45/// Reset line state engine
46void logread::reset()
47{
48 logsize = 0;
49 logsize_old = 0;
50
51 line.clear();
52 line_complete = false;
53}
54
55/// Skip initial content. Useful when parsing /var/log/messages
56void logread::goto_end()
57{
58 struct stat my_stat;
59 if (stat(filename.c_str(), &my_stat) == 0) {
60 logsize = my_stat.st_size;
61 logsize_old = logsize;
62 }
63}
64
65/// Main read loop
66void logread::read()
67{
68 // check if size changed
69 if (check_changed()) {
70 if (logsize > logsize_old) {
71 string logChanges = getLogChanges();
72
73 do {
74 extractSingeLine (logChanges);
75 line_complete == true ? processLine() : processUnfinishedLine();
76 } while (!logChanges.empty());
77 } else
78 reset(); // file got truncated
79
80 logsize_old = logsize;
81 }
82}
83
84/// Check if file is modified
85bool logread::check_changed()
86{
87 bool changed = false;
88
89 struct stat my_stat;
90 if (stat(filename.c_str(), &my_stat) == 0
91 && my_stat.st_size != logsize)
92 {
93 logsize = my_stat.st_size;
94 changed = true;
95 }
96
97 return changed;
98}
99
100/// Get changed content since last read
101string logread::getLogChanges()
102{
103 // open logfile
8843e320
TJ
104 ifstream log( filename.c_str(), ifstream::in );
105 if ( !log.is_open() )
7113c4f0
TJ
106 return "";
107
108 // read logfile
109 int size = logsize-logsize_old;
110
8843e320
TJ
111 boost::scoped_array<char> read_buffer( new char[ size + 1 ] );
112 log.seekg( logsize_old, fstream::beg );
113 if ( log.rdstate() != fstream::goodbit )
7113c4f0 114 throw runtime_error("can't seek in file " + filename);
8843e320
TJ
115 log.read( read_buffer.get(), size );
116 if ( log.rdstate() != fstream::goodbit )
7113c4f0 117 throw runtime_error("error reading from file " + filename);
8843e320 118 log.close();
7113c4f0
TJ
119
120 read_buffer[size] = 0;
8843e320 121 string changes( read_buffer.get() );
7113c4f0
TJ
122
123 return changes;
124}
125
126/// Extract a single line from input buffer
127void logread::extractSingeLine(string &input)
128{
129 string::size_type rtn_pos, copysize;
130
131 // go to next line
132 if (line_complete) {
133 line_complete = false;
134 line.clear();
135 }
136
137 rtn_pos = input.find("\n", 0);
138
139 // complete line or even multi-line
140 if (rtn_pos != string::npos)
141 copysize = rtn_pos;
142 else
143 copysize = input.length();
144
145 line.append (input.c_str(), copysize);
146
147 // Erase data from the input buffer
148 if (rtn_pos == string::npos) // no return found
149 input.erase (0, copysize);
150 else {
151 // also erase the return
152 input.erase (0, copysize+1);
153 line_complete = true;
154 }
155}
156
157/** Short example
158
159#include <iostream>
160class logread_syslog : public logread
161{
162public:
163 logread_syslog() : logread("messages", false) {};
164
165 void processLine()
166 {
167 cout << "finished: " << line << endl;
168 }
169
170 void processUnfinishedLine()
171 {
172 cout << "unfinished: " << line << endl;
173 }
174};
175
176int main(void)
177{
178 logread_syslog messages;
179
180 while (1) {
181 messages.read();
182 sleep(1);
183 }
184
185 return 0;
186}
187*/