1 /**************************************************************************
2 ** (c) Copyright 2002, Andromeda Technology & Automation
3 ** This is free software; you can redistribute it and/or modify it under the
4 ** terms of the GNU General Public License, see the file COPYING.
5 ***************************************************************************
6 ** MODULE INFORMATION *
7 ***********************
8 ** FILE NAME : gcm_input.cpp
9 ** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
10 ** VERSION NUMBER : $Revision: 1.16 $
12 ** DESCRIPTION : Application to store client messages into the database
13 ** The client message contains a log file from one of the
14 ** system logs. Gcm_input parses the log file and enters
15 ** the raw data into the 'log' table of the gnucomo database.
17 ** The system log may arrive in one of several forms:
18 ** 1. Log file (archived or not) from a client machine.
19 ** 2. Log file from a client system, arriving in a clear Email.
20 ** 3. Log file from a client machine, arriving in an
23 ** additional information we need that may not be availble in
24 ** the content of the log is:
25 ** - FQDN of the client.
26 ** - Time of arrival of the log
27 ** - Service that created the log.
29 ** If the log arrives in an Email, these items probably are
30 ** available in the mail header. Otherwise, they have to be
31 ** provided as command line arguments.
33 ** Command line arguments:
34 ** -c <name> Configuration name (default = gnucomo).
35 ** -d <date> Date and time of log arrival.
36 ** -h <hostname> FQDN of the client.
37 ** -i Incremental - partial list of parameters.
38 ** -s <service> Service that created the log.
39 ** -T Test mode. Do not alter the database.
40 ** -v Verbose (debug) output.
41 ** -V Print version and exit.
46 ***************************************************************************
47 ** ADMINISTRATIVE INFORMATION *
48 ********************************
49 ** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
50 ** CREATION DATE : Aug 29, 2002
51 ** LAST UPDATE : Nov 26, 2003
53 **************************************************************************/
55 /*****************************
56 $Log: gcm_input.cpp,v $
57 Revision 1.16 2011-03-24 10:20:37 arjen
60 Revision 1.15 2007/11/14 16:19:25 arjen
61 Bugfix: Segmentation fault when reading an rpm package list
64 Revision 1.14 2007/11/03 10:26:13 arjen
65 Added a new filter which can directly read the output
66 of the UNIX df command. A brief description is added in
69 Revision 1.13 2003/12/22 10:20:21 arjen
70 Report if the message type can not be detected.
72 Revision 1.12 2003/12/04 10:38:09 arjen
73 Major redesign. All input is handled through XML. Raw input data is first
74 transformed into an XML document for further processing.
75 A collection of polymorphic classes handle the transformation of various
76 input formats into XML.
77 Classifying input data is done with a finite improbability calculation.
79 Revision 1.11 2003/10/27 13:00:15 arjen
80 Catch exceptions from the database library
82 Revision 1.10 2003/09/03 06:58:31 arjen
83 Changed version string to 0.0.8
85 Revision 1.9 2003/09/01 06:59:26 arjen
86 A date without the time for the '-d <date> option will
87 assume midnight on that date.
89 Revision 1.8 2003/08/16 15:30:19 arjen
90 Fixed a gcc 2 vs. gcc 3 problem
92 Revision 1.7 2003/08/14 10:28:37 arjen
93 Use parameters from a new section 'logging' with three configuration parameters:
94 method - Output method to use for logging.
95 destination - Name of the log output destination.
96 level - Log level: Verbose output if greater than 0.
98 Revision 1.6 2003/08/11 16:56:16 arjen
99 Different kinds of log files are parsed by a collection of objects
100 of different classes, derived from the base class line_cooker
101 Depending on the message content or the message_type element in
102 XML, one of these objects is selected.
104 Logrunner is integrated with gcm_input. Although its functionality
105 is still limited, a connection between logrunner and gcm_input
106 is beginning to form.
108 Revision 1.5 2003/08/05 08:11:06 arjen
109 Added two configuration parameters:
110 logfile - Log to this file instead of stderr.
111 verbosity - Verbose output if greater than 0.
112 Added '-i' option for incremental parameter updates
114 Revision 1.4 2003/03/29 08:42:00 arjen
115 Exit without reading any input if the database connection fails.
117 Revision 1.3 2002/11/09 08:04:27 arjen
118 Added a reference to the GPL
120 Revision 1.2 2002/11/04 10:13:36 arjen
121 Use proper namespace for iostream classes
123 Revision 1.1 2002/10/05 10:25:49 arjen
124 Creation of gcm_input and a first approach to a web interface
126 *****************************/
134 #include "log_filter.h"
135 #include "rpm_filter.h"
136 #include "df_filter.h"
138 #include "xml_cooker.h"
139 #include "syslog_cooker.h"
140 #include "irix_syslog_cooker.h"
141 #include "access_cooker.h"
142 #include "error_cooker.h"
144 bool verbose = false;
145 bool testmode = false;
146 bool incremental = false;
147 std::ostream *Log = &std::cerr;
149 static char Version[] = "gcm_input version 0.0.13 - Sep 22, 2020";
152 /*=========================================================================
154 ** SYNOPSIS : int main(int argc, char *argv[])
158 ** DESCRIPTION : Parse command line arguments and establish a connection
160 ** When we have a database connection, parse the log file
167 ** LAST MODIFIED : Aug 11, 2003
168 **=========================================================================
171 int main(int argc, char *argv[])
173 const char *usage = "Usage: gcm_input [-c configname] [-h hostname] [-i] [-d date]"
174 " [-s service] [-T] [-v] [-V]\n";
177 String config_name("gnucomo");
178 std::ofstream logfile;
181 /* Parse command line arguments */
184 String hostname(""), service("");
188 while ((option = getopt(argc, argv, "c:h:d:s:iTvV")) != -1)
193 config_name = optarg;
201 arrival = String(optarg);
202 if (!date(arrival).proper())
204 std::cerr << "gcm_input: Invalid date string: " << optarg
205 << "(" << arrival << ").\n";
208 else if (!hour(arrival).proper())
210 arrival = UTC(date(arrival), hour(0,0,0));
231 std::cout << Version << "\n";
240 /* Get the configuration file */
242 if (!cfg.read(config_name))
244 std::cerr << "Can not read Gnucomo configuration file for " << config_name << ".\n";
248 String log_method = cfg.find_parameter("logging", "method");
249 String log_destination = cfg.find_parameter("logging", "destination");
250 int level = cfg.find_parameter("logging", "level");
252 if (log_method == "file" && log_destination != "")
254 logfile.open(log_destination, std::ios_base::app);
257 std::cerr << "Can't open logfile " << log_destination << " for writing.\n";
264 verbose = verbose || level > 0;
268 *Log << "Hostname = " << hostname;
269 *Log << " Arrival = " << arrival;
270 *Log << " Service = " << service << "\n";
271 *Log << "Config OK.\n";
274 /* Try to connect to the database */
276 gnucomo_database db(&cfg);
278 int gcm_input_result = 0;
281 client_message msg(&std::cin, db);
283 double message_probability;
285 message_filter shortcircuit(hostname, arrival, service);
286 log_filter lf(hostname, arrival, service);
287 rpm_filter rf(hostname, arrival, service);
288 df_filter df(hostname, arrival, service);
291 irix_syslog_cooker islc;
298 msg.add_cooker(&xlc, &shortcircuit);
299 msg.add_cooker(&slc, &lf);
300 msg.add_cooker(&islc, &lf);
301 msg.add_cooker(&alc, &lf);
302 msg.add_cooker(&elc, &lf);
303 msg.add_cooker(&rlc, &rf);
304 msg.add_cooker(&dlc, &df);
306 message_probability = msg.classify(hostname, arrival, service);
307 if (message_probability > 0.75)
313 // Can not store the input in the database. Dump the message in a file.
315 String spool_dir = cfg.find_parameter("spool", "directory");
316 String pid(getpid());
321 xmlfilename = spool_dir + "/";
323 xmlfilename += "gnucomo" + pid + ".xml";
325 msg.saveXML(xmlfilename);
327 // Report the error to the log and stderr.
328 *Log << "Entering the content into the database failed. XML content stored in " + xmlfilename + "\n";
329 std::cerr << "Entering the content into the database failed. XML content stored in " + xmlfilename + "\n";
331 gcm_input_result = 1;
334 catch (std::exception &e)
336 *Log << "Caught an exception: " << e.what() << "\n";
341 *Log << "Cannot determine message type with sufficient certainty.\n";
344 return gcm_input_result;