505bd03a256a6d00961d1019728eaec2bd6d5bf6
[gnucomo.git] / doc / design.xml
1 <?xml version="1.0"?>
2 <!DOCTYPE doc SYSTEM "/usr/local/xslt/doc.dtd">
3 <?xml-stylesheet type="text/xsl" href="/usr/local/xslt/html.xsl"?>
4 <doc style="main.css">
5
6 <!--
7       XML documentation system
8       Original author :  Arjen Baart - arjen@andromeda.nl
9       Version         : $Revision: 1.4 $
10
11       This document is prepared for XMLDoc. Transform to HTML,
12       LaTeX, Postscript or plain text with XMLDoc utilities and
13       XSLT sheets from http://www.andromeda.nl/projects/xmldoc/
14 -->
15
16 <book>
17 <titlepage>
18    <title>Gnucomo - Computer Monitoring</title>
19    <subtitle>Design description</subtitle>
20 <!--
21    <para><picture src='logo.png' eps='logo' scale='0.7'/></para>
22 -->
23    <author>Arjen Baart <code>&lt;arjen@andromeda.nl&gt;</code></author>
24    <author>Brenno de Winter<code>&lt;brenno@dewinter.com&gt;</code></author>
25    <date>December 17, 2002</date>
26    <docinfo>
27       <infoitem label="Version">0.2</infoitem>
28       <infoitem label="Organization">Andromeda Technology &amp; Automation</infoitem>
29       <infoitem label="Organization">De Winter Information Solutions</infoitem>
30    </docinfo>
31    <abstract>
32    </abstract>
33 </titlepage>
34
35 <toc/>
36
37 <chapter>
38 <heading>Introduction</heading>
39
40 <para>
41 <strong>Gnucomo</strong> is a system to monitor computer systems.
42 This document describes the design of the <strong>Gnucomo</strong> applications
43 and is based upon the development manifest.
44 </para>
45
46 </chapter>
47
48 <chapter>
49 <heading>Architecture</heading>
50
51 <para>
52 The architecture of <strong>gnucomo</strong> is shown in the
53 data flow diagram below:
54 </para>
55
56 <para>
57    <picture src='dataflow.png' eps='dataflow' scale='0.7'/>
58 </para>
59
60 <para>
61 Architectural items to consider:
62 <itemize>
63 <item>Active and passive data acquisition</item>
64 <item>Monitoring static and dynamic system parameters</item>
65 <item>Upper and lower limits for system parameters</item>
66 </itemize>
67 </para>
68
69 <para>
70 Existing log analysis tools: logwatch, analog.
71 </para>
72 </chapter>
73
74 <chapter>
75 <heading>System design</heading>
76
77 <para>
78 <strong>Gnucomo</strong> is a collection of different application programs,
79 rather than a single application.
80 All these application programs revolve around the <strong>Gnucomo</strong>
81 database as described in the manifest.
82 </para>
83
84 <section>
85 <heading>Database design</heading>
86
87 <para>
88 The design of the database is described extensively in
89 <reference href="manifest.html">the Manifest</reference>.
90 Assuming development is done on the same system on which the real (production)
91 gnucomo database is maintained, there is a need for a separate database
92 on which to perform development and integration tests.
93 Quite often, the test database will need to be destroyed and recreated.
94 To enable testing of <strong>gnucomo</strong> applications, all programs
95 need to access either the test database or the production database.
96 To accommodate this, each application needs an option to override the
97 default name of the configuration file (gnucomo.conf).
98 </para>
99
100 <para>
101 To create a convenient programming interface for object oriented languages,
102 a class <emph>gnucomo_database</emph> provides an abstract layer which
103 hides the details of the database implementation.
104 An object of this class maintains the connection to the database server
105 and provides convenience functions for accessing information in the
106 database.
107 A constructor of the <emph>gnucomo_database</emph> is passed a reference to
108 the <emph>gnucomo_configuration</emph> object in order to access the database.
109 This accommodates for both production and test databases.
110 The constructor will immediately try to connect to the database and check its
111 validity.
112 The destructor will of course close the database connection.
113 </para>
114
115 <para>
116 Other methods provide access to the database.
117 There will be lots more in the future, but here are a few to begin with:
118 <itemize>
119 <item>Find the objectid of a host, given its hostname</item>
120 <item>Insert a log record into the log table</item>
121 </itemize>
122 </para>
123 </section>
124
125 <section>
126 <heading>Configuration</heading>
127
128 <para>
129 Configuration parameters are stored in a XML formatted configuration file.
130 The config file contains a two-level hierarchy.
131 The first level denotes the section for which the parameter is used
132 and the second level is the parameter itself.
133 Both sections and parameters are elements in XML terminology.
134 The top-level (root) element is the configuration tree itself.
135 The root element must have the same name as the application's name
136 for which the configuration is intended.
137 The level-1 elements are sections of the configuration tree.
138 Within these section elements, the configuration has several parameter elements.
139 Each parameter is an element by itself.
140 The element's name is the name of the parameter, just as a section
141 element's name is the name of the section.
142 The content of the parameter element is the value of the parameter.
143 Attributes in either section elements or parameter elements are not used.
144 </para>
145 <para>
146 The configuration file is located in two places.
147 The is a system wide configuration in
148 <code>/usr/local/etc/gnucomo.conf</code> and each user may
149 have his or her own configuration in <code>~/.gnucomo.conf</code>.
150 The value of a user-specific configuration parameter overrides
151 the system-wide value.
152 </para>
153 <para>
154 At the moment, the gnucomo configuration has one section, holding
155 four parameters which define how to access the gnucomo database:
156 <itemize>
157 <item>type</item>
158 <item>name</item>
159 <item>user</item>
160 <item>password</item>
161 </itemize>
162
163 The <emph>type</emph> parameter must have the content <code>PostgreSQL</code>.
164 Other database systems are not supported yet.
165 </para>
166
167 <subsection>
168 <heading>gnucomo_config class</heading>
169
170 <para>
171 Each Gnucomo application should have exactly one object of the
172 <strong>gnucomo_config</strong> to obtain its configuration
173 parameters.
174 The following methods are supported in this class:
175
176 <itemize>
177
178 <item>
179   read(String name)
180   <para>
181   Reads the XML formatted configuration files from
182   <code>/usr/local/etc/&lt;name&gt;.conf</code> and
183   <code>~/.&lt;name&gt;.conf</code>.
184   </para>
185 </item>
186
187 <item>
188   String find_parameter(String section, String param)
189   <para>
190   Return the value of the parameter <emph>param</emph> in
191   section <emph>section</emph>.
192   </para>
193 </item>
194
195 <item>
196   String Database()
197   <para>
198   Return the database access string to be used for the PgDatabase constructor.
199   </para>
200 </item>
201
202 </itemize>
203 </para>
204
205 </subsection>
206 </section>
207
208 <section>
209 <heading>gcm_input</heading>
210
211 <para>
212 <strong>gcm_input</strong> is the application which captures messages from client
213 systems in one form or another and tries to store information from these messages
214 into the database.
215 A client message may arrive in a number of forms and through any kind of
216 transportation channel.
217 Here are a few examples:
218
219 <itemize>
220 <item>Copied directly from a local client's file system.</item>
221 <item>Copied remotely from a client's file system, e.g. using
222 <code>ftp</code>, <code>rcp</code> or <code>scp</code>.</item>
223 <item>Through an email.</item>
224 </itemize>
225
226 On top of that, any message may be encrypted, for example with PGP or GnuPG.
227 In any of these situations, <strong>gcm_input</strong> should be able to extract
228 as much information as possible from the client's message.
229 In case the message is encrypted, it may not be possible to run <strong>gcm_input</strong>
230 in the background, since human intervention is needed to enter the secret key.
231 </para>
232 <para>
233 The primary function of <strong>gcm_input</strong> is to store lines from a client's
234 log files into the <emph>log</emph> table.
235 To do this, we need certain information about the client message that is usually not
236 in the content of a log file.
237 This information includes:
238 <itemize>
239 <item>The source of the log file, most often in the form of the client's hostname.</item>
240 <item>The time stamp of the time on which the log file arrived on the server.</item>
241 <item>The service on the client which produced the log file.</item>
242 </itemize>
243
244 Sometimes, this information is available from the message itself, as in an email header.
245 On other occasions, the information needs to be supplied externally,
246 e.g. by using command line options.
247 </para>
248 <para>
249 Apart from determining information about the client's message, the content
250 of the message needs to be analyzed in order to handle it properly.
251 The body of the message may contain all sorts of information, such as:
252 <itemize>
253 <item>System log file</item>
254 <item>Apache log file</item>
255 <item>Report from a Gnucomo agent</item>
256 <item>Something else...</item>
257 </itemize>
258
259 The message is analyzed to obtain information about what the message entails
260 and where it came from.
261 The <strong>classify()</strong> method tries to extract that information.
262 Sometimes, this information can not be determined with absolute 100% certainty.
263 The certainty expresses how sure we are about the contents in the message.
264 Classifying a message may be performed with an algorithm as shown in
265 the following pseudo code:
266
267 <verbatim>
268 while certainty &lt; &epsilon; AND not at end
269
270    Scan for a marker
271
272    Adjust certainty
273 </verbatim>
274
275 Initially, a message is not classified and the certainty is 0.0.
276 Some lines point toward a certain class of message but do not absolutely determine
277 the class of a message. Other pieces of text are typical for a certain message class.
278 Examples of markers that determine the classification of a client message
279 are discussed below.
280
281 <verbatim>
282 From - Sat Sep 14 15:01:15 2002
283 </verbatim>
284
285 This is almost certainly a UNIX style mail header.
286 There should be lines beginning with <code>From:</code> and <code>Date:</code>
287 before the first empty line is encountered.
288 The hostname of the client that sent the message and the time of arrival
289 can be determined from these email header lines.
290 The content of the message is still to be determined by matching
291 other markers.
292
293 <verbatim>
294 -----BEGIN PGP MESSAGE-----
295 </verbatim>
296
297 Such a line in the message certainly means that the message is PGP or GnuPG
298 encrypted.
299 Decrypting is possible only if someone or something provides a secret key.
300
301 <verbatim>
302 Sep  1 04:20:00 kithira kernel: solo1: unloading
303 </verbatim>
304
305 The general pattern of a system log file is an abbreviated month name, a day,
306 a time, a name of a host without the domain, the name of a service followed
307 by a colon and finally, the message of that service.
308 We can match this with a regular expression to see if the message holds syslog lines.
309 Similar matches can be used to find Apache log lines or output from the <emph>dump</emph>
310 backup program or anything else.
311 </para>
312
313 <para>
314 The message classification embodies the way in which a message must be
315 handled and in what way information from the message can be put into
316 the database.
317 Aspects for handling the message are for example:
318 <itemize>
319 <item>Strip lines at the beginning or end.</item>
320 <item>Store each line separately or store the message as a whole.</item>
321 <item>How to extract hostname, arrival time and service from the message.</item>
322 <item>How to break up the message into individual fields for a <emph>log</emph> record.</item>
323 </itemize>
324 </para>
325
326 <para>
327 The figure below shows the class diagram that is used for <strong>gcm_input</strong>:
328    <para>
329    <picture src='classes-gcm_input.png' eps='classes-gcm_input'/>
330    </para>
331
332 The heart of the application is a <emph>client_message</emph> object.
333 This object reads the message through the <emph>message_buffer</emph> from some
334 input stream (file, string, stdin or socket), classifies the message and
335 enters information from the message into the database.
336 It has a relationship with a <emph>gnucomo_database</emph> object which
337 is an abstraction of the tables in the database.
338 These are the methods for the <emph>client_message</emph> class:
339
340 <itemize>
341 <item>client_message::client_message(istream *in, gnucomo_database *db)
342    <para>
343    Constructor.
344    </para>
345 </item>
346 <item>double client_message::classify(String host, date arrival_d, hour arrival_t, String serv)
347   <para>
348   Try to classify the message and return the certainty with which the class of the
349   message could be determined.
350   If the hostname, arrival time and service can not be extracted from the message,
351   use the arguments as default.
352   </para>
353 </item>
354 <item>int enter()
355   <para>
356   Insert the message contents into the <emph>log</emph> table of the gnucomo
357   database.
358   Returns the number of records inserted.
359   </para>
360 </item>
361 </itemize>
362
363 </para>
364 <para>
365 Some kind of input buffering is needed when a client message is being processed.
366 The contents of the message are not entirely clear until a few lines are analyzed,
367 and these lines probably need to be read again.
368 When the message is stored in a file, this is no problem; a simple lseek allows us
369 to read any line over and over again.
370 However, when the message comes from an input stream, like a TCP socket or just
371 plain old stdin, this is a different matter.
372 Lines of the messages that are already read will be lost forever, unless they are
373 stored somewhere.
374 To store an input stream temporarily, there are two options:
375 <enumerate>
376 <item>In an internal memory buffer.</item>
377 <item>In an external (temporary) file.</item>
378 </enumerate>
379 The <emph>message_buffer</emph> class takes care of the input buffering, thus
380 hiding these implementation details.
381 On the outside, a <emph>message_buffer</emph> can be read line by line until the
382 end of the input is reached.
383 Lines of input can be read again by backing up to the beginning of the message
384 by using the <strong>rewind()</strong> method or by backing up one line
385 with the <strong>--</strong> operator.
386 The <emph>message_buffer</emph> object maintains a pointer to the next
387 available line.
388 The <strong>++</strong> operator, being the opposite of the <strong>--</strong>
389 operator, skips one line.
390 </para>
391
392 <para>
393 The <strong>&gt;&gt;</strong> operator reads data from the message
394 into the second (String) operand, just like the <strong>&gt;&gt;</strong>
395 operator for an istream.
396 There is a small difference, though.
397 The <strong>&gt;&gt;</strong> operator for a <emph>message_buffer</emph>
398 returns a boolean value which states if there actually was input available.
399 This value will usually turn to <code>false</code> at the end of file.
400 A second difference is the fact that input data can only be read into
401 <emph>String</emph> objects a line at a time.
402 There are no functions for reading integer or floating point numbers.
403 The <strong>&gt;&gt;</strong> operator reads the next line either from
404 an internal buffer or from the external input stream if the internal
405 buffer is exhausted.
406 Lines read from the input stream are cached in the internal buffer,
407 so they are available for reading another time, e.g. after
408 rewinding to the beginning of the message.
409 </para>
410
411 <para>
412 Methods for the <emph>message_buffer</emph> class:
413
414 <itemize>
415 <item>message_buffer::message_buffer(istream *in)
416   <para>
417   Constructor.
418   </para>
419 </item>
420 <item>bool operator &gt;&gt;(message_buffer &amp;, String &amp;)
421 </item>
422 <item>message_buffer::rewind()</item>
423 <item>message_buffer::operator --</item>
424 <item>message_buffer::operator ++</item>
425 </itemize>
426 </para>
427 <subsection>
428
429 <heading>Command arguments</heading>
430
431 <para>
432 <strong>Gcm_input</strong> understands the following command line arguments:
433 <itemize>
434 <item>-c &lt;name&gt; : Configuration name</item>
435 <item>-d &lt;date&gt; : Arrival time of the message</item>
436 <item>-h &lt;hostname&gt; : FQDN of the client</item>
437 <item>-s &lt;service&gt; : service that created the log</item>
438 <item>-v : verbose output. Print lots of debug information</item>
439 <item>-V : Print version and exit</item>
440 </itemize>
441 </para>
442 </subsection>
443 </section>
444
445 <section>
446 <heading>gcm_daemon</heading>
447 <para>
448 <strong>Gcm_daemon</strong> is the application that processes data just
449 arrived in the database.
450 It handles the log-information delivered by <strong>gcm_input</strong>
451 in the <emph>log</emph> table of the database.
452 With the data further storage and classification can be done.
453 Where <strong>gcm_input</strong> is a highly versatile application that is
454 loaded and ended all the time the daemon is continously available monitoring
455 the entire system. Basically the daemon monitors everything that happens
456 in the database and excecutes continous checks and processes all the data.
457 The two applications (gcm_input and gcm_daemon) together are the core of the central system. 
458 The application has the following tasks:
459 <itemize>
460 <item>Processing data into other tables so that easy detection can take place</item>
461 <item>Raising notifications based on the available input</item>
462 <item>Maintain the status of notifications and changing priority when needed</item>
463 <item>Priodically perform checks for alerts that are communicated through the notification-table</item>
464 <item>Perform updates on the database when a new version of the software is loaded</item>
465 </itemize>
466 </para>
467
468 <subsection>
469 <heading>Performing checks</heading>
470
471 <para>
472 One of the most difficult tasks for the daemon is performing the automatic checks.
473 Every check is different and will be made up of several parameters that have to test negative.
474 That makes it hard to define this in software.
475 Another downside is that some work may be very redundant.
476 For that reason a more generic control structure is needed based on the technologies used.
477 The logical choice is then to focus on the capabilities in the database and perform
478 the job by executing queries.
479 </para>
480 <para>
481 Since the system is about detecting problems and issues we build the detection in
482 such a way that queries on the database result in 'suspicious' logrecords.
483 So called 'innocent' records can be ignored. So if a query gives a result a
484 problem is present, if there is no result there isn't a problem.
485 As soon as we seek for common ground in the process of identifying problems
486 it can be said that all results are based on the log-table
487 (as stated in the manifest the log-table is the one and only table were input
488 will arrive and stored for later use).
489 Furthermore there are two ways of determining if a problem is present: 
490 <itemize>
491 <item>
492 A single log-record or a group of log-records is within or outside the boundaries set.
493 If it is outside the boundaries the logrecord(s) is/are a potential problem.
494 If there are more boundaries set all of these need to be applied.
495 Based on fixed data results can be derived.
496 </item>
497 <item>
498 A set of records outline a trend that throughout time may turnout
499 to be a problem. These type of values are not fixed and directly legible
500 but more or less derived data. That data is input for some checks (previous bullet).
501 </item>
502 </itemize>
503 In both cases a set of queries can be run.
504 If there are more queries to be executed the later queries can be executed on
505 only the results. For that reason intermediate results have to be stored in a
506 temporary table for later reuse.
507 Saving a session in combination with the found log-records are sufficient.
508 This is also true since logrecords are the basis of all derived presences in
509 the numerous log_adv_xxx-tables and always have a reference to the log-table. 
510 </para>
511 <para>
512 Building the checks will thus be nothing more than combining queries
513 and adding a classification to the results of that query.
514 If this generic structure is being built properly with a simple (easy to understand) interface,
515 many combinations can be made. People having a logically correct idea,
516 but insufficient skills to program will be able to build checks.
517 As a consequence we can offer the interface to the user,
518 that in turn can also make particular checks for the environment that is unique to him/her.
519 This - of course - doesn't mean that a clear SQL-interface shouldn't be offered.
520 </para>
521 <para>
522 Whenever something happens, that is less than standard a line will be written to the syslogd.
523 This will enable users and developpers to trace exactly what happened.
524 The gcm_daemon will also log startup and ending so that abrupt endings of the daemon will be detected.
525 </para>
526 </subsection>
527
528 <subsection>
529 <heading>The initial process</heading>
530 <para>
531 When gcm_daemon starts first some basic actions take place that go beyond
532 just opening a connection to the database. The following actions also need to take place:
533 <itemize>
534 <item>
535 Check the database version if it is still the most recent version.
536 The daemon will check the version-number of the database.
537 If the database is not the same version as gcm_daemon an update will be performed.
538 When the database is up-to-date normal processing will continue.
539 </item>
540 <item>
541 If the database reflects that the used version gcm_daemon is less recent than
542 the running version (i.e. a new version has been installed) all records
543 in the log-table that weren't recognized before will now be set to unprocessed since
544 there is a fair change that they might be recognized this time. This will ensure that no data is lost.
545 </item>
546 </itemize>
547 </para>
548
549 </subsection>
550 </section>
551
552 <section>
553 <heading>Design ideas</heading>
554
555 <para>
556 Use of a neural network to analyze system logs:
557 <itemize>
558 <item>Classify words</item>
559 <item>Classify message based on word classification</item>
560 </itemize>
561 </para>
562 </section>
563
564 </chapter>
565
566 </book>
567 </doc>