-
/**************************************************************************
** (c) Copyright 2002, Andromeda Technology & Automation
+** This is free software; you can redistribute it and/or modify it under the
+** terms of the GNU General Public License, see the file COPYING.
***************************************************************************
** MODULE INFORMATION *
***********************
** FILE NAME : gcm_input.cpp
** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
-** VERSION NUMBER : $Revision: 1.2 $
+** VERSION NUMBER : $Revision: 1.16 $
**
** DESCRIPTION : Application to store client messages into the database
** The client message contains a log file from one of the
** -c <name> Configuration name (default = gnucomo).
** -d <date> Date and time of log arrival.
** -h <hostname> FQDN of the client.
+** -i Incremental - partial list of parameters.
** -s <service> Service that created the log.
** -T Test mode. Do not alter the database.
** -v Verbose (debug) output.
********************************
** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
** CREATION DATE : Aug 29, 2002
-** LAST UPDATE : Nov 04, 2002
+** LAST UPDATE : Nov 26, 2003
** MODIFICATIONS :
**************************************************************************/
/*****************************
$Log: gcm_input.cpp,v $
- Revision 1.2 2002-11-04 10:13:36 arjen
+ Revision 1.16 2011-03-24 10:20:37 arjen
+ Added some debug info
+
+ Revision 1.15 2007/11/14 16:19:25 arjen
+ Bugfix: Segmentation fault when reading an rpm package list
+ with empty lines.
+
+ Revision 1.14 2007/11/03 10:26:13 arjen
+ Added a new filter which can directly read the output
+ of the UNIX df command. A brief description is added in
+ the user manual.
+
+ Revision 1.13 2003/12/22 10:20:21 arjen
+ Report if the message type can not be detected.
+
+ Revision 1.12 2003/12/04 10:38:09 arjen
+ Major redesign. All input is handled through XML. Raw input data is first
+ transformed into an XML document for further processing.
+ A collection of polymorphic classes handle the transformation of various
+ input formats into XML.
+ Classifying input data is done with a finite improbability calculation.
+
+ Revision 1.11 2003/10/27 13:00:15 arjen
+ Catch exceptions from the database library
+
+ Revision 1.10 2003/09/03 06:58:31 arjen
+ Changed version string to 0.0.8
+
+ Revision 1.9 2003/09/01 06:59:26 arjen
+ A date without the time for the '-d <date> option will
+ assume midnight on that date.
+
+ Revision 1.8 2003/08/16 15:30:19 arjen
+ Fixed a gcc 2 vs. gcc 3 problem
+
+ Revision 1.7 2003/08/14 10:28:37 arjen
+ Use parameters from a new section 'logging' with three configuration parameters:
+ method - Output method to use for logging.
+ destination - Name of the log output destination.
+ level - Log level: Verbose output if greater than 0.
+
+ Revision 1.6 2003/08/11 16:56:16 arjen
+ Different kinds of log files are parsed by a collection of objects
+ of different classes, derived from the base class line_cooker
+ Depending on the message content or the message_type element in
+ XML, one of these objects is selected.
+
+ Logrunner is integrated with gcm_input. Although its functionality
+ is still limited, a connection between logrunner and gcm_input
+ is beginning to form.
+
+ Revision 1.5 2003/08/05 08:11:06 arjen
+ Added two configuration parameters:
+ logfile - Log to this file instead of stderr.
+ verbosity - Verbose output if greater than 0.
+ Added '-i' option for incremental parameter updates
+
+ Revision 1.4 2003/03/29 08:42:00 arjen
+ Exit without reading any input if the database connection fails.
+
+ Revision 1.3 2002/11/09 08:04:27 arjen
+ Added a reference to the GPL
+
+ Revision 1.2 2002/11/04 10:13:36 arjen
Use proper namespace for iostream classes
Revision 1.1 2002/10/05 10:25:49 arjen
*****************************/
-static const char *RCSID = "$Id: gcm_input.cpp,v 1.2 2002-11-04 10:13:36 arjen Exp $";
+#include <fstream>
#include <getopt.h>
+#include <unistd.h>
#include "message.h"
+#include "log_filter.h"
+#include "rpm_filter.h"
+#include "df_filter.h"
+
+#include "xml_cooker.h"
+#include "syslog_cooker.h"
+#include "irix_syslog_cooker.h"
+#include "access_cooker.h"
+#include "error_cooker.h"
bool verbose = false;
bool testmode = false;
+bool incremental = false;
+std::ostream *Log = &std::cerr;
-static char *Version = "gcm_input version 0.0.4 - Nov 05, 2002";
+static char Version[] = "gcm_input version 0.0.13 - Sep 22, 2020";
/*=========================================================================
** VARS CHANGED :
** FUNCTIONS USED :
** SEE ALSO :
-** LAST MODIFIED : Sep 30, 2002
+** LAST MODIFIED : Aug 11, 2003
**=========================================================================
*/
int main(int argc, char *argv[])
{
- const char *usage = "Usage: gcm_input [-c configname] [-h hostname] [-d date]"
+ const char *usage = "Usage: gcm_input [-c configname] [-h hostname] [-i] [-d date]"
" [-s service] [-T] [-v] [-V]\n";
gnucomo_config cfg;
- char *config_name = "gnucomo";
+ String config_name("gnucomo");
+ std::ofstream logfile;
+
/* Parse command line arguments */
String hostname(""), service("");
int option;
-
- while ((option = getopt(argc, argv, "c:h:d:s:TvV")) != -1)
+
+ while ((option = getopt(argc, argv, "c:h:d:s:iTvV")) != -1)
{
switch (option)
{
case 'd':
arrival = String(optarg);
- if (!arrival.proper())
+ if (!date(arrival).proper())
{
- std::cerr << "gcm_input: Invalid date string: " << optarg << ".\n";
+ std::cerr << "gcm_input: Invalid date string: " << optarg
+ << "(" << arrival << ").\n";
exit(1);
}
+ else if (!hour(arrival).proper())
+ {
+ arrival = UTC(date(arrival), hour(0,0,0));
+ }
break;
case 's':
service = optarg;
break;
+ case 'i':
+ incremental = true;
+ break;
+
case 'T':
testmode = true;
break;
exit(1);
}
}
-
- if (verbose)
- {
- std::cout << "Hostname = " << hostname;
- std::cout << " Arrival = " << arrival;
- std::cout << " Service = " << service << "\n";
- }
-
/* Get the configuration file */
if (!cfg.read(config_name))
exit(1);
}
+ String log_method = cfg.find_parameter("logging", "method");
+ String log_destination = cfg.find_parameter("logging", "destination");
+ int level = cfg.find_parameter("logging", "level");
+
+ if (log_method == "file" && log_destination != "")
+ {
+#if __GNUC__ == 2
+ logfile.open(log_destination, _IO_APPEND); // for gcc 2
+#else
+ logfile.open(log_destination, std::ios_base::app); // for gcc 3
+#endif
+ if (!logfile)
+ {
+ std::cerr << "Can't open logfile " << log_destination << " for writing.\n";
+ }
+ else
+ {
+ Log = &logfile;
+ }
+ }
+ verbose = verbose || level > 0;
+
if (verbose)
{
- std::cout << "Config OK.\n";
+ *Log << "Hostname = " << hostname;
+ *Log << " Arrival = " << arrival;
+ *Log << " Service = " << service << "\n";
+ *Log << "Config OK.\n";
}
/* Try to connect to the database */
gnucomo_database db(&cfg);
- client_message msg(&std::cin, db);
+ int gcm_input_result = 0;
+
+
+ client_message msg(&std::cin, db);
+
+ double message_probability;
+
+ message_filter shortcircuit(hostname, arrival, service);
+ log_filter lf(hostname, arrival, service);
+ rpm_filter rf(hostname, arrival, service);
+ df_filter df(hostname, arrival, service);
+
+ syslog_cooker slc;
+ irix_syslog_cooker islc;
+ access_cooker alc;
+ error_cooker elc;
+ xml_cooker xlc;
+ rpm_cooker rlc;
+ df_cooker dlc;
+
+ msg.add_cooker(&xlc, &shortcircuit);
+ msg.add_cooker(&slc, &lf);
+ msg.add_cooker(&islc, &lf);
+ msg.add_cooker(&alc, &lf);
+ msg.add_cooker(&elc, &lf);
+ msg.add_cooker(&rlc, &rf);
+ msg.add_cooker(&dlc, &df);
+
+ message_probability = msg.classify(hostname, arrival, service);
+ if (message_probability > 0.75)
+ {
+ try
+ {
+ if (msg.enter() < 0)
+ {
+ // Can not store the input in the database. Dump the message in a file.
+
+ String spool_dir = cfg.find_parameter("spool", "directory");
+ String pid(getpid());
+ String xmlfilename;
+
+ if (spool_dir)
+ {
+ xmlfilename = spool_dir + "/";
+ }
+ xmlfilename += "gnucomo" + pid + ".xml";
+
+ msg.saveXML(xmlfilename);
+
+ // Report the error to the log and stderr.
+ *Log << "Entering the content into the database failed. XML content stored in " + xmlfilename + "\n";
+ std::cerr << "Entering the content into the database failed. XML content stored in " + xmlfilename + "\n";
- if (msg.classify(hostname, arrival, service) > 0.9)
+ gcm_input_result = 1;
+ }
+ }
+ catch (std::exception &e)
+ {
+ *Log << "Caught an exception: " << e.what() << "\n";
+ }
+ }
+ else
{
- msg.enter();
+ *Log << "Cannot determine message type with sufficient certainty.\n";
}
- return 0;
+ return gcm_input_result;
}