Redesigned gcm_input with polymorphic message filter classes.
[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.6 $
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    <para><picture src='logo.png' eps='logo' scale='0.7'/></para>
21    <author>Arjen Baart <code>&lt;arjen@andromeda.nl&gt;</code></author>
22    <author>Brenno de Winter<code>&lt;brenno@dewinter.com&gt;</code></author>
23    <author>Peter Roozemaal<code>&lt;mathfox@xs4all.nl&gt;</code></author>
24    <date>November 26, 2003</date>
25    <docinfo>
26       <infoitem label="Version">0.6</infoitem>
27       <infoitem label="Organization">Andromeda Technology &amp; Automation</infoitem>
28       <infoitem label="Organization">De Winter Information Solutions</infoitem>
29    </docinfo>
30    <abstract>
31    </abstract>
32 </titlepage>
33
34 <toc/>
35
36 <chapter>
37 <heading>Introduction</heading>
38
39 <para>
40 <strong>Gnucomo</strong> is a system to monitor computer systems.
41 This document describes the design of the <strong>Gnucomo</strong> applications
42 and is based upon the development manifest.
43 </para>
44
45 </chapter>
46
47 <chapter>
48 <heading>Architecture</heading>
49
50 <para>
51 The architecture of <strong>gnucomo</strong> is shown in the
52 data flow diagram below:
53 </para>
54
55 <para>
56    <picture src='dataflow.png' eps='dataflow' scale='0.7'/>
57 </para>
58
59 <para>
60 At the left of the diagram, information is acquired from the monitored system.
61 Several agents can be used to obtain information from this system, in
62 active or passive ways.
63 A passive agent uses information which is available on the system anyway,
64 such as log files or other lists.
65 An active agent, requests explicit data from the monitored system.
66 One example of a passive agent is <emph>logrunner</emph>, a program which
67 monitors system log files and sends regular updates to the <strong>gnucomo</strong>
68 server.
69 The agents on the monitored system send the data to some kind of transportation channel.
70 This can be any form of transport, such as Email, SOAP, plain file copying or
71 some special network connection.
72 If desired, the transportation may provide security.
73 Once arrived at the server, the information from monitored systems is captured
74 by the <emph>gcm_input</emph> process.
75 This process can obtain the data through many forms of transport and from
76 a number of input formats.
77 <emph>Gcm_input</emph> will try to recognize as much as possible from an
78 input message and store the obtained information into the <emph>Raw Storage</emph>
79 database.
80 The <emph>Raw Storage</emph> data is processed further and analyzed by
81 the <emph>gcm_daemon</emph>, which scans the data, gathers statistics and
82 stores its results into the <emph>Derived Storage</emph> database where
83 it is available for human review and further analysis.
84 </para>
85
86 <para>
87 Architectural items to consider:
88 <itemize>
89 <item>Active and passive data acquisition</item>
90 <item>Monitoring static and dynamic system parameters</item>
91 <item>Upper and lower limits for system parameters</item>
92 </itemize>
93 </para>
94
95 <para>
96 Existing log analysis tools: logwatch, analog.
97 </para>
98 </chapter>
99
100 <chapter>
101 <heading>System design</heading>
102
103 <para>
104 <strong>Gnucomo</strong> is a collection of different application programs,
105 rather than a single application.
106 All these application programs revolve around the <strong>Gnucomo</strong>
107 database as described in the manifest.
108 </para>
109
110 <section>
111 <heading>Database design</heading>
112
113 <para>
114 The design of the database is described extensively in
115 <reference href="manifest.html">the Manifest</reference>.
116 Assuming development is done on the same system on which the real (production)
117 gnucomo database is maintained, there is a need for a separate database
118 on which to perform development and integration tests.
119 Quite often, the test database will need to be destroyed and recreated.
120 To enable testing of <strong>gnucomo</strong> applications, all programs
121 need to access either the test database or the production database.
122 To accommodate this, each application needs an option to override the
123 default name of the <ref to='configuration'>configuration</ref> file (gnucomo.conf).
124 </para>
125
126 <para>
127 To create a convenient programming interface for object oriented languages,
128 a class <emph>gnucomo_database</emph> provides an abstract layer which
129 hides the details of the database implementation.
130 An object of this class maintains the connection to the database server
131 and provides convenience functions for accessing information in the
132 database.
133 A constructor of the <emph>gnucomo_database</emph> is passed a reference to
134 the <emph>gnucomo_configuration</emph> object in order to access the database.
135 This accommodates for both production and test databases.
136 The constructor will immediately try to connect to the database and check its
137 validity.
138 The destructor will of course close the database connection.
139 </para>
140
141 <para>
142 Other methods provide access to the database in a low-level manner.
143 There will be lots more in the future, but here are a few to begin with:
144 <itemize>
145 <item>Send a SQL query to the database.</item>
146 <item>Read a tuple from a result set.</item>
147 <item>Obtain the userid for the current database session.</item>
148 </itemize>
149 </para>
150
151 <para>
152 The information stored in the database as tuples is represented by classes in
153 other programming languages such as C++ of PHP.
154 Each class models a particular type of tuple (an <emph>entity</emph>)
155 in the database.
156 Such classes maintain the relation with the database on one end,
157 while providing methods that are specific to the entity on the other end.
158 All database communication and SQL queries are hidden inside the
159 entity's class.
160 This includes, for example, handling database result sets and access control.
161 </para>
162 <para>
163 Properties and operations that are common to all classes that represent
164 entities in the database are caught in a common base class.
165 The base class, named <emph>database_entity</emph> provides default
166 implementations for loading and storing tuples, construction and destruction
167 and iteration.
168 Most derived classes will override these functions.
169 Two examples of classes that represent entities in the database
170 are <emph>object</emph> and <emph>service</emph>.
171 Both are derived from a <emph>database_entity</emph>, as show below:
172 <para>
173   <picture src='class-database_entity.png' eps='class-database_entity'/>
174 </para>
175 </para>
176
177 <para>
178 Constructors of classes derived from <emph>database_entity</emph> come in
179 two varieties: with or without database interaction.
180 Constructors that do not interact with the database have only one argument:
181 a reference to the <emph>gnucomo_database</emph> object which handles
182 the low-level interaction with the database server.
183 The example below shows a few of these constructors:
184 <verbatim>
185
186   database_entity::database_entity(gnucomo_database &amp;gdb)
187
188   object::object(gnucomo_database &amp;gdb)
189
190   service::service(gnucomo_database &amp;gdb)
191
192 </verbatim>
193 The objective of this type of constructor is to cerate a fresh tuple and
194 store it in the database later on.
195 All these constructors do is establish the connection to the database
196 server and fill in the defaults for the fields in the tuple.
197 A destructor will put the actual tuple into the database if any
198 information in the object has changed.
199 This may be by sending an INSERT if the object is completely fresh
200 or an UPDATE if an already existing tuple was changed.
201 The state information about the freshness of an object is a property
202 common to all database entities and is therefore maintained in
203 the <emph>database_entity</emph> class.
204 </para>
205 <para>
206 Constructors that do interact with the database accept additional
207 arguments after the initial <emph>gnucomo_database</emph> reference.
208 These extra arguments are used to retrieve a tuple from the database.
209 Examples of such constructors are:
210 <verbatim>
211
212    object::object(gnucomo_database &amp;gdb, String hostname)
213
214    object::object(gnucomo_database &amp;gdb, long long oid)
215
216    service::service(gnucomo_database &amp;gdb, String name)
217
218 </verbatim>
219 The set of arguments must of course correspond to a set of fields that
220 uniquely identify the tuple.
221 The primary key of the database table would be ideally suitable.
222 If the tuple is not found in the database, data members of the object
223 are set to default values and the object is marked as being fresh and
224 not changed.
225 </para>
226
227 <para>
228 Methods with the same name as a field in a tuple read or change the
229 value of that field.
230 Without an argument, such a method returns the current value of the field.
231 With a single argument, the field is set to the new value passed in the
232 argument and the method returns the original value.
233 Whenever a field is set to a new value, the object is marked as being
234 'changed'.
235 A destructor will then save the tuple to the database.
236 </para>
237 </section>
238
239 <section>
240 <heading><label name='configuration'/>Configuration</heading>
241
242 <para>
243 Configuration parameters are stored in a XML formatted configuration file.
244 The config file contains a two-level hierarchy.
245 The first level denotes the section for which the parameter is used
246 and the second level is the parameter itself.
247 Both sections and parameters are elements in XML terminology.
248 The top-level (root) element is the configuration tree itself.
249 The root element must have the same name as the application's name
250 for which the configuration is intended.
251 The level-1 elements are sections of the configuration tree.
252 Within these section elements, the configuration has several parameter elements.
253 Each parameter is an element by itself.
254 The element's name is the name of the parameter, just as a section
255 element's name is the name of the section.
256 The content of the parameter element is the value of the parameter.
257 Attributes in either section elements or parameter elements are not used.
258 </para>
259 <para>
260 The configuration file is located in two places.
261 The is a system wide configuration in
262 <code>/usr/local/etc/gnucomo.conf</code> and each user may
263 have his or her own configuration in <code>~/.gnucomo.conf</code>.
264 The value of a user-specific configuration parameter overrides
265 the system-wide value.
266 </para>
267 <para>
268 The following sections and parameters are defined for the Gnucomo
269 configuration:
270 <itemize>
271 <item>database
272    <itemize>
273    <item>type</item>
274    <item>name</item>
275    <item>user</item>
276    <item>password</item>
277    <item>host</item>
278    <item>port</item>
279    </itemize>
280 </item>
281 <item>logging
282    <itemize>
283    <item>method</item>
284    <item>destination</item>
285    <item>level</item>
286    </itemize>
287 </item>
288 <item>gcm_input
289    <itemize>
290    <item>dbuser</item>
291    <item>password</item>
292    </itemize>
293 </item>
294 <item>gcm_daemon
295    <itemize>
296    <item>dbuser</item>
297    <item>password</item>
298    </itemize>
299 </item>
300 </itemize>
301
302 The <emph>database</emph> section defines how the database is accessed.
303 The <emph>database/type</emph> parameter must have the content <code>PostgreSQL</code>.
304 Other database systems are not supported yet.
305 The <emph>database/user</emph> and <emph>database/password</emph> provide default
306 login information onto the database server.
307 Specific user names and passwords may be specified for separate applications, such
308 as <emph>gcm_input</emph> and <emph>gcm_daemon</emph>.
309 </para>
310
311 <subsection>
312 <heading>gnucomo_config class</heading>
313
314 <para>
315 Each Gnucomo application should have exactly one object of the
316 <strong>gnucomo_config</strong> to obtain its configuration
317 parameters.
318 The following methods are supported in this class:
319
320 <itemize>
321
322 <item>
323   read(String name)
324   <para>
325   Reads the XML formatted configuration files from
326   <code>/usr/local/etc/&lt;name&gt;.conf</code> and
327   <code>~/.&lt;name&gt;.conf</code>.
328   </para>
329 </item>
330
331 <item>
332   String find_parameter(String section, String param)
333   <para>
334   Return the value of the parameter <emph>param</emph> in
335   section <emph>section</emph>.
336   </para>
337 </item>
338
339 <item>
340   String Database()
341   <para>
342   Return the database access string to be used for the PgDatabase constructor.
343   </para>
344 </item>
345
346 </itemize>
347 </para>
348
349 </subsection>
350 </section>
351
352 <section>
353 <heading>gcm_input</heading>
354
355 <para>
356 <strong>gcm_input</strong> is the application which captures messages from client
357 systems in one form or another and tries to store information from these messages
358 into the database.
359 A client message may arrive in a number of forms and through any kind of
360 transportation channel.
361 Here are a few examples:
362
363 <itemize>
364 <item>Obtained directly from a local client's file system.</item>
365 <item>From the output of another process, through standard input.</item>
366 <item>Copied remotely from a client's file system, e.g. using
367    <code>ftp</code>, <code>rcp</code> or <code>scp</code>.
368    This is usually handled through spooled files.
369 </item>
370 <item>Through an email.</item>
371 <item>As a SOAP web service, carried through HTTP or SMTP.</item>
372 <item>Through a TCP connection on a special socket.</item>
373 </itemize>
374
375 On top of that, any message may be encrypted, for example with PGP or GnuPG.
376 In any of these situations, <strong>gcm_input</strong> should be able to extract
377 as much information as possible from the client's message.
378 In case the message is encrypted, it may not be possible to run <strong>gcm_input</strong>
379 in the background, since human intervention is needed to enter the secret key.
380 </para>
381 <para>
382 The primary function of <strong>gcm_input</strong> is to store lines from a client's
383 log files into the <emph>log</emph> table or scan a report from a probe and update
384 the <emph>parameter</emph> table.
385 To do this, we need certain information about the client message that is usually not
386 in the content of a log file.
387 This information includes:
388 <itemize>
389 <item>The source of the log file, most often in the form of the client's hostname.</item>
390 <item>The time stamp of the time on which the log file arrived on the server.</item>
391 <item>The service on the client which produced the log file.</item>
392 </itemize>
393
394 Sometimes, this information is available from the message itself, as in an email header.
395 On other occasions, the information needs to be supplied externally,
396 e.g. by using command line options.
397 In any case, this type of 'header' information is relevant to the message
398 as a whole.
399 As a result, <emph>gcm_input</emph> can accept one and only one message at a time.
400 For example, it is not possible to connect the standard output of
401 <emph>logrunner</emph> to the standard input of <emph>gcm_input</emph> and have
402 a continuous stream of messages from different log sources.
403 Each message should be fed to <emph>gcm_input</emph> separately.
404 Also when <emph>logrunner</emph> uses a special socket to send logging data,
405 a new connection must be created for each message.
406 The dataflow diagram below shows how a message travels from the input source
407 to the database.
408 </para>
409
410 <para>
411    <picture src='gcm_input-dataflow.png' eps='gcm_input-dataflow' scale='0.6'/>
412 </para>
413
414 <para>
415 Internally, <emph>gcm_input</emph> handles <ref to='XML_input'>XML input</ref>
416 and each input item must have its data fields split into appropriate XML elements.
417 When data is offered in some other form, this data must be filtered
418 and transformed into XML before <emph>gcm_input</emph> can handle it.
419 Two levels of transformation are possible.
420 At the highest level, the whole message is transformed into an XML
421 document with a <code>&lt;message&gt;</code> root element and the
422 appropriate <code>&lt;header&gt;</code> and <code>&lt;data&gt;</code>
423 elements, all of which are put in the proper namespace.
424 At the lowest level, each line of the message's data can be transformed
425 into a <code>&lt;cooked&gt; &lt;log&gt;</code> element.
426 Two classes of replaceable filter objects take care of these transformations.
427 Depending on the content of the message and/or command line options to
428 <emph>gcm_input</emph>, an appropriate filter object is inserted into
429 the data stream.
430 </para>
431
432 <para>
433 The <ref to='message_filter'><emph>message_filter</emph></ref> transforms
434 the raw input data into an XML document.
435 The XML document is processed by the XML parser and stored into the database
436 or saved into a spool area for later processing.
437 The latter happens, for example, when the database is unavailable.
438 The task of the <emph>message_filter</emph> object is to create the &lt;header&gt;
439 elements and the &lt;data&gt; element containing either a &lt;log&gt; or
440 a &lt;parameters&gt; element, along with all their child elements.
441 To do this, a <emph>message_filter</emph> object must work closely
442 together with a <emph>line_cooker</emph> object.
443 </para>
444 <para>
445 There are two major classes of <emph>message_filter</emph> objects:
446 one to create a &lt;log&gt; element and one to create a &lt;parameters&gt;
447 element.
448 Either one of these must be capable to create a &lt;header&gt; element which
449 is filled with information from command line arguments or an email header
450 in the input stream.
451 The base <emph>message_filter</emph> is not much more than a short circuit,
452 which merely copies the input stream into the internal XML buffer.
453 This is used when the input is already in XML format.
454 </para>
455
456 <para>
457 The <ref to='line_cooker'><emph>line_cooker</emph></ref>
458 operates on a node in the DOM tree which is
459 supposed to be a &lt;raw&gt; &lt;log&gt; element that contains one line
460 from a log file.
461 The <emph>line_cooker</emph> transforms a <emph>raw</emph> log line into
462 its constituent parts that make up en &lt;cooked&gt; element.
463 Since each type of log file uses a different layout and syntax,
464 different line cookers can be used, depending on the type of log.
465 This type is indicated by the &lt;messagetype&gt; element in the header
466 part of the message.
467 Clearly, the <emph>line_cooker</emph> is a polymorphic entity.
468 Exactly which <emph>line_cooker</emph> is used is determined through
469 <ref to='classifying'>classifying</ref>
470 the content of the message or the message type indicated in the header.
471 The <emph>line_cooker</emph> base class provides a default implementation
472 for most methods, while derived classes provide the actual cooking.
473 </para>
474
475 <para>
476 Output created by <emph>gcm_input</emph> for logging and debugging purposes
477 can be sent to one of several destinations:
478 <itemize>
479 <item>standard error.</item>
480 <item>a log file.</item>
481 <item>the system log.</item>
482 <item>an email address.</item>
483 </itemize>
484 The actual destination is stated in the <strong>gnucomo</strong>
485 configuration file. The default is stderr.
486 A <emph>log</emph> object filters output according to the debug level.
487 </para>
488
489 <subsection>
490 <heading><label name='classifying'/>Classifying messages</heading>
491
492 <para>
493 Apart from determining information about the client's message, the content
494 of the message needs to be analyzed in order to handle it properly.
495 The body of the message may contain all sorts of information, such as:
496 <itemize>
497 <item>System log file</item>
498 <item>Apache log file</item>
499 <item>Report from a Gnucomo agent or other probe, for example "rpm -qa"
500       or "df -k".</item>
501 <item>Generic XML input</item>
502 <item>Something else...</item>
503 </itemize>
504
505 Basically, <strong>gcm_input</strong> accepts two kinds of input: Log lines
506 and parameter reports.
507 The message is analyzed to obtain information about what the message entails
508 and where it came from.
509 The message classification embodies the way in which a message must be
510 handled and in what way information from the message can be put into
511 the database.
512 Aspects for handling the message are for example:
513 <itemize>
514 <item>Strip lines at the beginning or end.</item>
515 <item>Store each line separately or store the message as a whole.</item>
516 <item>How to extract hostname, arrival time and service from the message.</item>
517 <item>How to break up the message into individual fields for a <emph>log</emph> record.</item>
518 </itemize>
519 These aspects are all handled in polymorphic <emph>message_filter</emph>
520 and <emph>line_cooker</emph> classes.
521 The result of classifying a message is the selection of the proper
522 objects derived from these classes from a collection of such objects.
523 </para>
524
525 <para>
526 The <strong>classify()</strong> method tries to extract that information.
527 Sometimes, this information can not be determined with absolute 100% certainty.
528 The certainty expresses how sure we are about the contents in the message.
529 Classifying a message may be performed with an algorithm as shown in
530 the following pseudo code:
531
532 <verbatim>
533 uncertainty = 1.0
534
535 while uncertainty &gt; &epsilon; AND not at end
536
537    Scan for a marker
538
539    if a marker matches
540
541       uncertainty = uncertainty * P    //  P &lt; 1.0
542 </verbatim>
543
544 With <emph>uncertainty</emph> of course being the opposite of the certainty.
545 It expresses how unsure we are about the content of the message, as a
546 number between 0.0 and 1.0.
547 In fact, it is the probability that the message is not what we think it is.
548 Initially, a message is not classified and the uncertainty is 1.0.
549 Some lines point toward a certain type of message but do not absolutely determine
550 the type of a message. Other pieces of text are typical for a certain message type.
551 Such pieces of text, called <emph>markers</emph> are discovered in a message,
552 possibly by using regular expression matches.
553 Examples of markers that determine the classification of a client message
554 are discussed below.
555 </para>
556
557 <para>
558 To determine the message type, <strong>classify()</strong> uses the collection
559 of <ref to='line_cooker'><emph>line_cooker</emph></ref> objects and maintains
560 the uncertainty associated with each <emph>line_cooker</emph> object.
561 A line of input from the message is tested using the <emph>line_cooker::check_pattern</emph>
562 method for each <emph>line_cooker</emph>object.
563 When a marker matches, we are a bit more sure about the content of the message
564 and the uncertainty for that <emph>line_cooker</emph> object decreases by
565 multiplying the uncertainty by <strong>P</strong>, a number between 0 and 1.
566 This process continues line after line from the input message until the
567 uncertainty for one of the <emph>line_cooker</emph> objects is sufficiently low
568 (i.e. less than a preset threshold, &epsilon;).
569 At the end, the <emph>line_cooker</emph> object with the lowest uncertainty
570 is selected.
571
572 <verbatim>
573 From - Sat Sep 14 15:01:15 2002
574 </verbatim>
575
576 This is almost certainly a UNIX style mail header.
577 There should be lines beginning with <code>From:</code> and <code>Date:</code>
578 before the first empty line is encountered.
579 The hostname of the client that sent the message and the time of arrival
580 can be determined from these email header lines.
581 The content of the message is still to be determined by matching
582 other markers.
583
584 <verbatim>
585 -----BEGIN PGP MESSAGE-----
586 </verbatim>
587
588 Such a line in the message certainly means that the message is PGP or GnuPG
589 encrypted.
590 Decrypting is possible only if someone or something provides a secret key.
591
592 <verbatim>
593 &lt;?xml version='1.0'?&gt;
594 </verbatim>
595
596 The XML header declares the message to be generic XML input.
597 The structure of the XML message that <strong>gcm_input</strong> accepts
598 is described in the next section.
599
600 <verbatim>
601 Sep  1 04:20:00 kithira kernel: solo1: unloading
602 </verbatim>
603
604 The general pattern of a system log file is an abbreviated month name, a day,
605 a time, a name of a host without the domain, the name of a service followed
606 by a colon and finally, the message of that service.
607 We can match this with a regular expression to see if the message holds syslog lines.
608 Similar matches can be used to find Apache log lines or output from the <emph>dump</emph>
609 backup program or anything else.
610 </para>
611 </subsection>
612
613 <subsection>
614 <heading><label name='XML_input'/>Generic XML input</heading>
615
616 <para>
617
618 Since <strong>gcm_input</strong> can not understand every conceivable form
619 of input, a client can offer its input in a more generic form which reflects
620 the structure of the Gnucomo database.
621 In this case, the input is structured in an XML document that contains the input
622 data in a form that allows <strong>gcm_input</strong> to store the information
623 into the database without knowing the nature of the input.
624 The XML root element for <strong>gcm_input</strong> is a <emph>&lt;message&gt;</emph>, defined
625 in the namespace with namespace name <code>http://gnucomo.org/transport/</code>.
626 All other elements and attributes of the <emph>&lt;message&gt;</emph> must be defined
627 within this namespace.
628 </para>
629 <para>
630 Within the <emph>&lt;message&gt;</emph> element there is a <emph>&lt;header&gt;</emph>
631 and a <emph>&lt;data&gt;</emph> element.
632 The <emph>&lt;data&gt;</emph> element may contain the log data in an externally
633 specified format.
634 The <emph>&lt;header&gt;</emph> element contains a number of elements (fields), some
635 mandatory, some optional. The text of the element contains the value of
636 the element.
637 The following elements have been defined:
638
639 <itemize>
640 <item>
641 <emph>&lt;mesagetype&gt;</emph> mandatory
642      <para>
643       The type (format) of the log data in the data element. The message type
644       determines the way in which raw log elements are parsed and split up
645       into separate fields for insertion into the database.
646       The message types gcm_input understands are:
647       <itemize>
648       <item><code>system log</code> : The most common form of UNIX system logs.
649             Also used in most Linux distributions.
650       </item>
651       <item><code>IRIX system log</code> : Variation of system log, used by SGI.
652       </item>
653       <item><code>apache access log</code> : Access log of the Apache http daemon,
654             in default form.
655       </item>
656       <item><code>apache error log</code> : Error log of the Apache http daemon,
657             in default form.
658       </item>
659       </itemize>
660       There must also be a 'generic' system log in case all elements are
661       cooked already.
662      </para>
663 </item>
664 <item>
665 <emph>&lt;hostname&gt;</emph> mandatory
666      <para>
667       The name of the system that generated the data in the data block.
668       This can be different from the computer composing the message.
669      </para>
670 </item>
671 <item>
672 <emph>&lt;service&gt;</emph> optional
673      <para>
674       The (default) value of the service running on the host that
675       generated the message data. For log files that don't contain the
676       service name embedded in them.
677      </para>
678 </item>
679 <item>
680 <emph>&lt;time&gt;</emph> optional
681      <para>
682       The best approximation to the time that the data was generated.
683       For (log)data that doesn't contain an embedded date stamp.
684      </para>
685 </item>
686 </itemize>
687
688 The following example shows an XML message for <strong>gcm_input</strong>
689 with a filled-in header and an empty <emph>&lt;data&gt;</emph> element:
690
691 <verbatim>
692   &lt;gcmt:message xmlns:gcmt='http://gnucomo.org/transport/'&gt;
693      &lt;gcmt:header&gt;
694         &lt;gcmt:messagetype&gt;apache error log&lt;/gcmt:messagetype&gt;
695         &lt;gcmt:hostname&gt;client.gnucomo.org&lt;/gcmt:hostname&gt;
696         &lt;gcmt:service&gt;httpd&lt;/gcmt:service&gt;
697         &lt;gcmt:time&gt;2003-04-17 14:40:46.312895+01:00&lt;/gcmt:time&gt;
698      &lt;/gcmt:header&gt;
699      &lt;gcmt:data/&gt;
700   &lt;/gcmt:message&gt;
701 </verbatim>
702 </para>
703
704 <para>
705 The <emph>data</emph> element can hold one of two possible child
706 elements: <emph>&lt;log&gt;</emph> or <emph>&lt;parameters&gt;</emph>.
707 The <emph>&lt;log&gt;</emph> element may contain any number of lines from
708 a system's log file, each line in a separate element.
709 A single log line is the content of either a <emph>&lt;raw&gt;</emph> or
710 a <emph>&lt;cooked&gt;</emph> element.
711 The <emph>&lt;raw&gt;</emph> element contains the log line "as is" and nothing more.
712 This is the easiest way to provide XML data for <strong>gcm_input</strong>.
713 However, the log line itself must be in a form that <strong>gcm_input</strong>
714 can understand.
715 After all, <strong>gcm_input</strong> still needs to extract meaningful information
716 from that line, such as the time stamp and the service that created the log.
717 The client can also choose to provide that information separately by encapsulating
718 the log line in a <emph>&lt;cooked&gt;</emph> element.
719 This element may have up to four child elements, two of which are mandatory:
720 <itemize>
721 <item><emph>&lt;timestamp&gt;</emph> mandatory.
722    <para>
723    The time at which the log line was generated by the client.
724    </para>
725 </item>
726 <item><emph>&lt;hostname&gt;</emph> optional.
727    <para>
728    For logs that include a hostname in each line. This hostname is checked
729    against the hostname in the <emph>&lt;header&gt;</emph> element.
730    </para>
731 </item>
732 <item><emph>&lt;service&gt;</emph> optional.
733    <para>
734    If the service that generated the log is not provided in the <emph>&lt;header&gt;</emph>
735    the service must be stated for each log line separately.
736    Otherwise, each log line is assumed to be generated by the same service.
737    </para>
738 </item>
739 <item><emph>&lt;raw&gt;</emph> mandatory.
740    <para>
741    The content of the full log line. This would have the same content of the singular
742    <emph>&lt;raw&gt;</emph> element if the log line was not provided in a
743    <emph>&lt;cooked&gt;</emph> element.
744    </para>
745 </item>
746 </itemize>
747 The following shows an example of the log message with two lines in the
748 <emph>&lt;log&gt;</emph> element, one raw and one cooked:
749
750 <verbatim>
751   &lt;gcmt:data xmlns:gcmt='http://gnucomo.org/transport/'&gt;
752     &lt;gcmt:log&gt;
753      &lt;gcmt:raw&gt;
754        Apr 13 04:31:03 schiza kernel: attempt to access beyond end of device
755      &lt;/gcmt:raw&gt;
756      &lt;gcmt:cooked&gt;
757         &lt;gcmt:timestamp&gt;2003-04-13 04:31:03+02:00&lt;/gcmt:timestamp&gt;
758         &lt;gcmt:hostname&gt;schiza&lt;/gcmt:hostname&gt;
759         &lt;gcmt:service&gt;kernel&lt;/gcmt:service&gt;
760         &lt;gcmt:raw&gt;
761          Apr 13 04:31:03 schiza kernel: 03:05: rw=0, want=1061109568, limit=2522173
762         &lt;/gcmt:raw&gt;
763      &lt;/gcmt:cooked&gt;
764     &lt;/gcmt:log&gt;
765   &lt;/gcmt:data&gt;
766 </verbatim>
767 </para>
768
769 <para>
770 The <emph>&lt;parameters&gt;</emph> element contains a list of parameters
771 of the same class. The class is provided as an attribute in the
772 <emph>&lt;parameters&gt;</emph> open tag.
773 There is a <emph>&lt;parameter&gt;</emph> element for each parameter in the list.
774 The child elements of a <emph>&lt;parameter&gt;</emph> are one optional
775 <emph>&lt;description&gt;</emph> element and zero or more <emph>&lt;property&gt;</emph>
776 elements.
777 The names of a parameter and a property are provided by the mandatory <emph>name</emph>
778 attributes in the respective elements.
779 The following example shows a possible parameter report from a "df -k":
780 <verbatim>
781   &lt;gcmt:data xmlns:gcmt='http://gnucomo.org/transport/'&gt;
782     &lt;gcmt:parameters gcmt:class='filesystem'&gt;
783       &lt;gcmt:parameter gcmt:name='root'&gt;
784          &lt;gcmt:description&gt;Root filesystem&lt;/gcmt:description&gt;
785          &lt;gcmt:property gcmt:name='size'&gt;303344&lt;/gcmt:property&gt;
786          &lt;gcmt:property gcmt:name='used'&gt;104051&lt;/gcmt:property&gt;
787          &lt;gcmt:property gcmt:name='available'&gt;183632&lt;/gcmt:property&gt;
788          &lt;gcmt:property gcmt:name='device'&gt;/dev/hda1&lt;/gcmt:property&gt;
789          &lt;gcmt:property gcmt:name='mountpoint'&gt;/&lt;/gcmt:property&gt;
790       &lt;/gcmt:parameter&gt;
791       &lt;gcmt:parameter gcmt:name='usr'&gt;
792          &lt;gcmt:description&gt;Usr filesystem&lt;/gcmt:description&gt;
793          &lt;gcmt:property gcmt:name='size'&gt;5044188&lt;/gcmt:property&gt;
794          &lt;gcmt:property gcmt:name='used'&gt;3073716&lt;/gcmt:property&gt;
795          &lt;gcmt:property gcmt:name='available'&gt;1714236&lt;/gcmt:property&gt;
796          &lt;gcmt:property gcmt:name='device'&gt;/dev/hdd2&lt;/gcmt:property&gt;
797          &lt;gcmt:property gcmt:name='mountpoint'&gt;/usr&lt;/gcmt:property&gt;
798       &lt;/gcmt:parameter&gt;
799     &lt;/gcmt:parameters&gt;
800   &lt;/gcmt:data&gt;
801 </verbatim>
802 </para>
803
804 </subsection>
805
806 <subsection>
807 <heading>Gcm_input classes</heading>
808 <para>
809 The figure below shows the class diagram that is used for <strong>gcm_input</strong>:
810    <para>
811    <picture src='classes-gcm_input.png' eps='classes-gcm_input' scale='0.8'/>
812    </para>
813
814 The heart of the application is a <emph>client_message</emph> object.
815 This object reads the message through the
816 <ref to='message_buffer'><emph>message_buffer</emph></ref> from some
817 input stream (file, string, stdin or socket), classifies the message and
818 enters information from the message into the database.
819 The <emph>client_message</emph> object holds a collection of <emph>message_filter</emph>
820 and associated <emph>line_cooker</emph> objects.
821 The association is maintained in a <emph>xform</emph> object.
822 Note that several <emph>line_cooker</emph> can be associated with
823 with a single <emph>message_filter</emph> object.
824 For example, a system log or a web server log are processed in a similar
825 manner, i.e. each line is transformed into a &lt;log&gt; element.
826 The patterns of the individual lines, however are entirely different.
827 During the classification of the input data, one combination of a
828 <emph>message_filter</emph> and <emph>line_cooker</emph> is selected.
829 The classification process works by calculating the uncertainty with which
830 a <emph>line_cooker</emph> matches with the input data.
831 The one with the least uncertainty is selected.
832 </para>
833
834 <subsubsection>
835 <heading><label name='client_message'/>client_message</heading>
836 <para>
837 The <emph>client_message</emph> has a relationship with a <emph>gnucomo_database</emph> object which
838 is an abstraction of the tables in the database.
839 These are the methods for the <emph>client_message</emph> class:
840
841 <itemize>
842 <item><code>client_message::client_message(istream *in, gnucomo_database *db)</code>
843    <para>
844    Constructor.
845    </para>
846 </item>
847 <item><code>void add_cooker(line_cooker *lc, message_filter *mf)</code>
848   <para>
849   Add another <emph>line_cooker</emph> object with the associated
850   <emph>message_filter</emph> object to the collection.
851   This initializes the uncertainty with which the <emph>line_cooker</emph>
852   is selected to 1.0.
853   </para>
854 </item>
855 <item><code>double client_message::classify(String host, date arrival_d,
856                                              hour arrival_t, String serv)</code>
857   <para>
858   Try to classify the message and return the certainty with which the class of the
859   message could be determined.
860   If the hostname, arrival time and service can not be extracted from the message,
861   use the arguments as default.
862   This will examine the first few lines of the input data
863   to select one of the <emph>message_filter</emph> with
864   associated <emph>line_cooker</emph> objects
865   from the collection built with the <emph>add_cooker</emph> method.
866   </para>
867 </item>
868 <item><code>int enter()</code>
869   <para>
870   Insert the message contents into the gnucomo database.
871   Returns the number of records inserted.
872   The input data from the <emph>message_buffer</emph>
873   is first transformed into an XML document (a strstream object)
874   by invoking the <emph>message_filter</emph> and <emph>line_cooker</emph> objects.
875   The XML document in the internal buffer is then parsed into an
876   XML DOM tree, using the Gnome XML parser.
877   The XML document may also be validated against an XML Schema definition.
878   </para>
879   <para>
880   After extracting and checking the &lt;header&gt; elements,
881   the data nodes are extracted and inserted into the database,
882   possibly using a <emph>line_cooker</emph> object to cook raw
883   log elements.
884   If an error occurs in some stage of this process, the XML document
885   is dumped in a spool area for later processing.
886   </para>
887 </item>
888 </itemize>
889
890 </para>
891 </subsubsection>
892
893 <subsubsection>
894 <heading><label name='message_filter'/>message_filter</heading>
895 <para>
896 A <emph>message_filter</emph> transforms the raw input data into an
897 XML document suitable for further parsing and storage into the database.
898 The base class, <emph>message_filter</emph> does nothing but copy the
899 input stream into an internal XML buffer.
900 An object of this class is used when the input is already in XML format.
901 Classes derived from <emph>message_filter</emph> read the input line by line,
902 possibly extracting information from an email header if available.
903 <itemize>
904 <item>
905    <code>message_filter::contruct_XML(message_buffer &amp;in, strstream &amp;xml)</code>
906    <para>
907    Simply copy the input stream into the internal XML buffer.
908    The base class function is used when the input is already in XML format.
909    Derived classes will override this function.
910    </para>
911 </item>
912 </itemize>
913 </para>
914
915 <para>
916 Classes derived from <emph>message_filter</emph> transform various kinds
917 of input into an XML document. The following diagram shows some examples:
918
919    <para>
920    <picture src='classes-message_filter.png' eps='classes-message_filter' scale='0.8'/>
921    </para>
922
923 The two classes, derived directly from <emph>message_filter</emph> reflect
924 that <strong>gcm_input</strong> can handle two kinds of input: The
925 <emph>log_filter</emph> for log files
926 and <emph>parameters_filter</emph> for parameter reports.
927 Each of these types of input are transformed into entirely different XML
928 documents and are stored quite differently into the database.
929 Classes that are derived further down the hierarchy will handle more specific
930 forms of input.
931 </para>
932 </subsubsection>
933
934 <subsubsection>
935 <heading><label name='line_cooker'/>line_cooker</heading>
936 <para>
937 To turn a raw line from a log file onto separate parts that can be stored
938 in the database, i.e. parse the line, the <emph>client_message</emph>
939 object uses a <emph>line_cooker</emph> object.
940 This is a polymorphic object, so each type of log can have its own parser,
941 while the <emph>client_message</emph> object uses a common interface
942 for each one.
943 For each message, one specific <emph>line_cooker</emph> object is
944 selected as determined by the message type.
945 E.g., the derived class <emph>syslog_cooker</emph> is used for system logs.
946 When the <emph>client_message</emph> object encounters a <strong>raw</strong>
947 log element, it takes the following steps to turn this into a
948 <strong>cooked</strong> log element:
949 <enumerate>
950 <item>
951   Remove the TEXT node of the "raw" element and save its content.
952 </item>
953 <item>
954   Change the name of the element into "cooked".
955 </item>
956 <item>
957   Check if the content matches the syntax of the type of log we're
958   processing at the moment.
959   This depends on the message type and is therefore a task for the
960   <emph>line_cooker</emph> object.
961 </item>
962 <item>
963   Have the <emph>line_cooker</emph> parse the content and extract
964   the time stamp and optionally the hostname and service.
965 </item>
966 <item>
967   Insert new child elements into the cooked element.
968 </item>
969 </enumerate>
970 After that, the <emph>cooked</emph> element is ready for further processing
971 and possibly storing into the database.
972 </para>
973
974 <para>
975 The <emph>line_cooker</emph> base class holds three protected members
976 that must be filled with information by the derived classes:
977 <itemize>
978 <item><code>UTC ts</code> : the timestamp.</item>
979 <item><code>String hn</code> : the hostname</item>
980 <item><code>String srv</code> : the service</item>
981 </itemize>
982 Corresponding base class methods (<emph>timestamp</emph>,
983 <emph>hostname</emph> and <emph>service</emph>) will do
984 nothing more than return these values.
985 It is up to the derived class's <emph>cook_this</emph> method
986 to properly initialize these members.
987 </para>
988
989 <para>
990 The methods for the <emph>line_cooker</emph> class are:
991 <itemize>
992 <item>
993   <code>bool line_cooker::check_pattern(String logline)</code>
994   <para>
995   Tries to match the <emph>logline</emph> against that patterns
996   that describe the message syntax.
997   In the <emph>line_cooker</emph> base class, this is a pure virtual function.
998   Returns true if the log line adheres to the message-specific syntax.
999   </para>
1000 </item>
1001 <item>
1002   <code>bool line_cooker::cook_this(String logline, UTC arrival)</code>
1003   <para>
1004   Extracts information from the <emph>logline</emph>.
1005   The <emph>arrival</emph> can be used to make corrections to incomplete
1006   time stamps in the log file.
1007   The implementation in a derived class must properly initialize the protected
1008   members described above.
1009   In the <emph>line_cooker</emph> base class, this is a pure virtual function.
1010   Returns false if the pattern does not match.
1011   </para>
1012 </item>
1013 <item>
1014   <code>String line_cooker::message_type()</code>
1015   <para>
1016   Return the message type for which this line cooker is intended.
1017   </para>
1018 </item>
1019 <item>
1020   <code>UTC line_cooker::timestamp()</code>
1021   <para>
1022   Returns the timestamp that was previously extracted from the log line
1023   or a 'null' timestamp if that information could nnot be extracted.
1024   </para>
1025 </item>
1026 <item>
1027    <code>String line_cooker::hostname()</code>
1028   <para>
1029   Returns the hostname that was previously extracted from the log line,
1030   or an empty string if that information could not be extracted.
1031   </para>
1032 </item>
1033 <item>
1034    <code>String line_cooker::service()</code>
1035   <para>
1036   Returns the service that was previously extracted from the log line,
1037   or an empty string if that information could not be extracted.
1038   </para>
1039 </item>
1040 </itemize>
1041 </para>
1042 </subsubsection>
1043
1044 <subsubsection>
1045 <heading><label name='message_buffer'/>message_buffer</heading>
1046 <para>
1047 Some kind of input buffering is needed when a client message is being processed.
1048 The contents of the message are not entirely clear until a few lines are analyzed,
1049 and these lines probably need to be read again.
1050 When the message is stored in a file, this is no problem; a simple lseek allows us
1051 to read any line over and over again.
1052 However, when the message comes from an input stream, like a TCP socket or just
1053 plain old stdin, this is a different matter.
1054 Lines of the messages that are already read will be lost forever, unless they are
1055 stored somewhere.
1056 To store an input stream temporarily, there are two options:
1057 <enumerate>
1058 <item>In an internal memory buffer.</item>
1059 <item>In an external (temporary) file.</item>
1060 </enumerate>
1061 The <emph>message_buffer</emph> class takes care of the input buffering, thus
1062 hiding these implementation details.
1063 On the outside, a <emph>message_buffer</emph> can be read line by line until the
1064 end of the input is reached.
1065 Lines of input can be read again by backing up to the beginning of the message
1066 by using the <strong>rewind()</strong> method or by backing up one line
1067 with the <strong>--</strong> operator.
1068 The <emph>message_buffer</emph> object maintains a pointer to the next
1069 available line.
1070 The <strong>++</strong> operator, being the opposite of the <strong>--</strong>
1071 operator, skips one line.
1072 </para>
1073
1074 <para>
1075 The <strong>&gt;&gt;</strong> operator reads data from the message
1076 into the second (String) operand, just like the <strong>&gt;&gt;</strong>
1077 operator for an istream.
1078 There is a small difference, though.
1079 The <strong>&gt;&gt;</strong> operator for a <emph>message_buffer</emph>
1080 returns a boolean value which states if there actually was input available.
1081 This value will usually turn to <code>false</code> at the end of file.
1082 A second difference is the fact that input data can only be read into
1083 <emph>String</emph> objects a line at a time.
1084 There are no functions for reading integer or floating point numbers.
1085 The <strong>&gt;&gt;</strong> operator reads the next line either from
1086 an internal buffer or from the external input stream if the internal
1087 buffer is exhausted.
1088 Lines read from the input stream are cached in the internal buffer,
1089 so they are available for reading another time, e.g. after
1090 rewinding to the beginning of the message.
1091 </para>
1092
1093 <para>
1094 Methods for the <emph>message_buffer</emph> class:
1095
1096 <itemize>
1097 <item>message_buffer::message_buffer(istream *in)
1098   <para>
1099   Constructor.
1100   </para>
1101 </item>
1102 <item>bool operator &gt;&gt;(message_buffer &amp;, String &amp;)
1103 </item>
1104 <item>message_buffer::rewind()</item>
1105 <item>message_buffer::operator --</item>
1106 <item>message_buffer::operator ++</item>
1107 </itemize>
1108 </para>
1109
1110 </subsubsection>
1111 </subsection>
1112
1113 <subsection>
1114
1115 <heading>Command arguments</heading>
1116
1117 <para>
1118 <strong>Gcm_input</strong> understands the following command line arguments:
1119 <itemize>
1120 <item>-c &lt;name&gt; : Configuration name</item>
1121 <item>-d &lt;date&gt; : Arrival time of the message</item>
1122 <item>-h &lt;hostname&gt; : FQDN of the client</item>
1123 <item>-s &lt;service&gt; : service that created the log</item>
1124 <item>-v : verbose output. Print lots of debug information</item>
1125 <item>-V : Print version and exit</item>
1126 </itemize>
1127 </para>
1128 </subsection>
1129 </section>
1130
1131 <section>
1132 <heading>gcm_daemon</heading>
1133 <para>
1134 <strong>Gcm_daemon</strong> is the application that processes data just
1135 arrived in the database.
1136 It handles the log-information delivered by <strong>gcm_input</strong>
1137 in the <emph>log</emph> table of the database.
1138 With the data further storage and classification can be done.
1139 Where <strong>gcm_input</strong> is a highly versatile application that is
1140 loaded and ended all the time the daemon is continuously available monitoring
1141 the entire system. Basically the daemon monitors everything that happens
1142 in the database and executes continuous checks and processes all the data.
1143 The two applications (gcm_input and gcm_daemon) together are the core of the central system. 
1144 The application has the following tasks:
1145 <itemize>
1146 <item>Processing data into other tables so that easy detection can take place</item>
1147 <item>Raising notifications based on the available input</item>
1148 <item>Maintain the status of notifications and changing priority when needed</item>
1149 <item>Periodically perform checks for alerts that are communicated through the notification-table</item>
1150 <item>Perform updates on the database when a new version of the software is loaded</item>
1151 </itemize>
1152 </para>
1153
1154 <subsection>
1155 <heading>Performing checks</heading>
1156
1157 <para>
1158 One of the most difficult tasks for the daemon is performing the automatic checks.
1159 Every check is different and will be made up of several parameters that have to test negative.
1160 That makes it hard to define this in software.
1161 Another downside is that some work may be very redundant.
1162 For that reason a more generic control structure is needed based on the technologies used.
1163 The logical choice is then to focus on the capabilities in the database and perform
1164 the job by executing queries.
1165 </para>
1166 <para>
1167 Since the system is about detecting problems and issues we build the detection in
1168 such a way that queries on the database result in 'suspicious' log records.
1169 So called 'innocent' records can be ignored. So if a query gives a result a
1170 problem is present, if there is no result there isn't a problem.
1171 As soon as we seek for common ground in the process of identifying problems
1172 it can be said that all results are based on the log-table
1173 (as stated in the manifest the log-table is the one and only table were input
1174 will arrive and stored for later use).
1175 Furthermore there are two ways of determining if a problem is present: 
1176 <itemize>
1177 <item>
1178 A single log-record or a group of log-records is within or outside the boundaries set.
1179 If it is outside the boundaries the log record(s) is/are a potential problem.
1180 If there are more boundaries set all of these need to be applied.
1181 Based on fixed data results can be derived.
1182 </item>
1183 <item>
1184 A set of records outline a trend that throughout time may turnout
1185 to be a problem. These type of values are not fixed and directly legible
1186 but more or less derived data. That data is input for some checks (previous bullet).
1187 </item>
1188 </itemize>
1189 In both cases a set of queries can be run.
1190 If there are more queries to be executed the later queries can be executed on
1191 only the results. For that reason intermediate results have to be stored in a
1192 temporary table for later reuse.
1193 Saving a session in combination with the found log-records are sufficient.
1194 This is also true since log records are the basis of all derived presences in
1195 the numerous log_adv_xxx-tables and always have a reference to the log-table. 
1196 </para>
1197 <para>
1198 Building the checks will thus be nothing more than combining queries
1199 and adding a classification to the results of that query.
1200 If this generic structure is being built properly with a simple (easy to understand) interface,
1201 many combinations can be made. People having a logically correct idea,
1202 but insufficient skills to program will be able to build checks.
1203 As a consequence we can offer the interface to the user,
1204 that in turn can also make particular checks for the environment that is unique to him/her.
1205 This - of course - doesn't mean that a clear SQL-interface shouldn't be offered.
1206 </para>
1207 <para>
1208 Whenever something happens, that is less than standard a line will be written to the syslogd.
1209 This will enable users and developers to trace exactly what happened.
1210 The gcm_daemon will also log startup and ending so that abrupt endings of the daemon will be detected.
1211 </para>
1212 </subsection>
1213
1214 <subsection>
1215 <heading>The initial process</heading>
1216 <para>
1217 When gcm_daemon starts first some basic actions take place that go beyond
1218 just opening a connection to the database. The following actions also need to take place:
1219 <itemize>
1220 <item>
1221 Check the database version if it is still the most recent version.
1222 The daemon will check the version-number of the database.
1223 If the database is not the same version as gcm_daemon an update will be performed.
1224 When the database is up-to-date normal processing will continue.
1225 </item>
1226 <item>
1227 If the database reflects that the used version gcm_daemon is less recent than
1228 the running version (i.e. a new version has been installed) all records
1229 in the log-table that weren't recognized before will now be set to unprocessed since
1230 there is a fair change that they might be recognized this time. This will ensure that no data is lost.
1231 </item>
1232 </itemize>
1233 </para>
1234
1235 </subsection>
1236 </section>
1237
1238 <section>
1239 <heading>Design ideas</heading>
1240
1241 <para>
1242 Use of a neural network to analyze system logs:
1243 <itemize>
1244 <item>Classify words</item>
1245 <item>Classify message based on word classification</item>
1246 </itemize>
1247 </para>
1248 </section>
1249
1250 </chapter>
1251
1252 </book>
1253 </doc>