From 4ed55ea5cac00af72f5081d0f7711a268e116084 Mon Sep 17 00:00:00 2001 From: arjen Date: Mon, 11 Aug 2003 16:56:15 +0000 Subject: [PATCH] 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. --- doc/class-database_entity.obj | 177 ++++++++++ doc/classes-gcm_input.obj | 51 ++- doc/dataflow.obj | 136 ++++---- doc/design.xml | 620 +++++++++++++++++++++++++++++++++-- doc/gcm_input-dataflow.obj | 512 +++++++++++++++++++++++++++++ doc/makefile | 20 +- src/gcm_input/Makefile.am | 7 +- src/gcm_input/Makefile.in | 27 +- src/gcm_input/access_cooker.cpp | 83 +++++ src/gcm_input/access_cooker.h | 81 +++++ src/gcm_input/error_cooker.cpp | 83 +++++ src/gcm_input/error_cooker.h | 81 +++++ src/gcm_input/gcm_input.cpp | 35 +- src/gcm_input/irix_syslog_cooker.cpp | 100 ++++++ src/gcm_input/irix_syslog_cooker.h | 81 +++++ src/gcm_input/line_cooker.h | 103 ++++++ src/gcm_input/logrunner.cpp | 495 ++++++++++++++++++++++++++++ src/gcm_input/message.cpp | 397 ++++++++-------------- src/gcm_input/message.h | 32 +- src/gcm_input/syslog_cooker.cpp | 100 ++++++ src/gcm_input/syslog_cooker.h | 81 +++++ 21 files changed, 2922 insertions(+), 380 deletions(-) create mode 100644 doc/class-database_entity.obj create mode 100644 doc/gcm_input-dataflow.obj create mode 100644 src/gcm_input/access_cooker.cpp create mode 100644 src/gcm_input/access_cooker.h create mode 100644 src/gcm_input/error_cooker.cpp create mode 100644 src/gcm_input/error_cooker.h create mode 100644 src/gcm_input/irix_syslog_cooker.cpp create mode 100644 src/gcm_input/irix_syslog_cooker.h create mode 100644 src/gcm_input/line_cooker.h create mode 100644 src/gcm_input/logrunner.cpp create mode 100644 src/gcm_input/syslog_cooker.cpp create mode 100644 src/gcm_input/syslog_cooker.h diff --git a/doc/class-database_entity.obj b/doc/class-database_entity.obj new file mode 100644 index 0000000..b5f6396 --- /dev/null +++ b/doc/class-database_entity.obj @@ -0,0 +1,177 @@ +%TGIF 4.1.42-QPL +state(0,37,100.000,86,7,0,4,1,9,1,1,0,0,0,0,1,0,'Helvetica',0,69120,0,0,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). +% +% @(#)$Header: /src/cvsroot/gnucomo/doc/class-database_entity.obj,v 1.1 2003-08-11 16:57:42 arjen Exp $ +% %W% +% +unit("1 pixel/pixel"). +color_info(11,65535,0,[ + "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, + "red", 65535, 0, 0, 65535, 0, 0, 1, + "green", 0, 65535, 0, 0, 65535, 0, 1, + "blue", 0, 0, 65535, 0, 0, 65535, 1, + "yellow", 65535, 65535, 0, 65535, 65535, 0, 1, + "pink", 65535, 49931, 50971, 65535, 49344, 52171, 1, + "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, + "CadetBlue", 22885, 40569, 40569, 24415, 40606, 41120, 1, + "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, + "black", 0, 0, 0, 0, 0, 0, 1, + "DarkSlateGray", 10402, 19764, 18724, 12079, 20303, 20303, 1 +]). +script_frac("0.6"). +fg_bg_colors('black','White'). +dont_reencode("FFDingbests:ZapfDingbats"). +page(1,"",1,''). +box('black','',96,72,680,576,0,2,1,209,0,0,0,0,0,'2',0,[ +]). +text('black',388,534,1,1,1,320,23,211,18,5,0,0,0,0,2,320,23,0,0,"",0,0,0,0,552,'',[ +minilines(320,23,0,0,1,0,0,[ +mini_line(320,18,5,0,0,0,[ +str_block(0,320,18,5,0,-1,0,0,0,[ +str_seg('black','Helvetica-Bold',1,103680,320,18,5,0,-1,0,0,0,0,0, + "database_entity and derived classes")]) +]) +])]). +group([ +box('black','',412,352,540,416,0,1,1,896,0,0,0,0,0,'1',0,[ +]), +text('black',476,364,1,1,1,44,15,897,12,3,0,0,0,0,2,44,15,0,0,"",0,0,0,0,376,'',[ +minilines(44,15,0,0,1,0,0,[ +mini_line(44,12,3,0,0,0,[ +str_block(0,44,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica-Bold',1,69120,44,12,3,0,-1,0,0,0,0,0, + "service")]) +]) +])]) +], +895,0,0,[ +]). +group([ +box('black','',176,352,304,416,0,1,1,824,0,0,0,0,0,'1',0,[ +]), +text('black',240,364,1,1,1,36,15,825,12,3,0,0,0,0,2,36,15,0,0,"",0,0,0,0,376,'',[ +minilines(36,15,0,0,1,0,0,[ +mini_line(36,12,3,0,0,0,[ +str_block(0,36,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica-Bold',1,69120,36,12,3,0,0,0,0,0,0,0, + "object")]) +]) +])]) +], +823,0,0,[ +]). +poly('black','',2,[ + 304,380,412,380],0,1,1,972,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +box('black','',276,100,404,228,0,1,1,89,0,0,0,0,0,'1',0,[ +]), +text('black',340,112,1,1,1,96,15,90,12,3,0,0,0,0,2,96,15,0,0,"",0,0,0,0,124,'',[ +minilines(96,15,0,0,1,0,0,[ +mini_line(96,12,3,0,0,0,[ +str_block(0,96,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica-Bold',1,69120,96,12,3,0,-1,0,0,0,0,0, + "database_entity")]) +]) +])]) +], +913,0,0,[ +]). +poly('black','',2,[ + 276,132,404,132],0,1,1,974,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 276,180,404,180],0,1,1,983,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +box('black','',456,100,584,228,0,1,1,1009,0,0,0,0,0,'1',0,[ +]), +text('black',520,112,1,1,1,114,15,1010,12,3,0,0,0,0,2,114,15,0,0,"",0,0,0,0,124,'',[ +minilines(114,15,0,0,1,0,0,[ +mini_line(114,12,3,0,0,0,[ +str_block(0,114,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica-Bold',1,69120,114,12,3,0,-1,0,0,0,0,0, + "gnucomo_database")]) +]) +])]) +], +1008,0,0,[ +]). +poly('black','',2,[ + 456,132,584,132],0,1,1,1016,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +text('black',460,180,1,0,1,78,15,1019,12,3,0,0,0,0,2,78,15,0,0,"",0,0,0,0,192,'',[ +minilines(78,15,0,0,0,0,0,[ +mini_line(78,12,3,0,0,0,[ +str_block(0,78,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,78,12,3,0,-1,0,0,0,0,0, + "current_user()")]) +]) +])]). +text('black',460,196,1,0,1,43,15,1020,12,3,0,0,0,0,2,43,15,0,0,"",0,0,0,0,208,'',[ +minilines(43,15,0,0,0,0,0,[ +mini_line(43,12,3,0,0,0,[ +str_block(0,43,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,43,12,3,0,-1,0,0,0,0,0, + "Query()")]) +]) +])]). +poly('black','',2,[ + 456,180,584,180],0,1,1,1021,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 404,140,456,140],0,1,1,1066,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +oval('black','',404,376,412,384,1,1,1,1067,0,0,0,0,0,'1',0,[ +]). +polygon('black','',4,[ + 340,256,320,276,360,276,340,256],0,1,1,0,1190,0,0,0,0,0,'1',0, + "0",[ +]). +poly('black','',2,[ + 340,228,340,256],0,1,1,1196,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 340,276,236,276,236,352],0,1,1,1199,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 340,276,484,276,484,352],0,1,1,1200,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +oval('black','',304,376,312,384,1,1,1,1201,0,0,0,0,0,'1',0,[ +]). +text('black',288,136,3,0,1,77,45,1226,12,3,0,0,0,0,2,77,45,0,0,"",0,0,0,0,148,'',[ +minilines(77,45,0,0,0,0,0,[ +mini_line(55,12,3,0,0,0,[ +str_block(0,55,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,55,12,3,0,-1,0,0,0,0,0, + "bool fresh")]) +]), +mini_line(77,12,3,0,0,0,[ +str_block(0,77,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,77,12,3,0,-1,0,0,0,0,0, + "bool changed")]) +]), +mini_line(69,12,3,0,0,0,[ +str_block(0,69,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,69,12,3,0,-1,0,0,0,0,0, + "bool deleted")]) +]) +])]). diff --git a/doc/classes-gcm_input.obj b/doc/classes-gcm_input.obj index 9f058f8..2d19f5a 100644 --- a/doc/classes-gcm_input.obj +++ b/doc/classes-gcm_input.obj @@ -1,7 +1,7 @@ %TGIF 4.1.41-QPL -state(0,37,100.000,108,0,1,4,1,0,1,1,0,0,0,0,1,0,'Helvetica',0,69120,0,0,0,10,0,1,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). +state(0,37,100.000,0,0,0,4,1,0,1,1,0,0,0,1,1,0,'Helvetica',0,69120,0,0,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). % -% @(#)$Header: /src/cvsroot/gnucomo/doc/classes-gcm_input.obj,v 1.1 2002-10-05 10:23:08 arjen Exp $ +% @(#)$Header: /src/cvsroot/gnucomo/doc/classes-gcm_input.obj,v 1.2 2003-08-11 16:57:42 arjen Exp $ % %W% % unit("1 pixel/pixel"). @@ -264,3 +264,50 @@ str_seg('black','Helvetica',0,69120,41,12,3,0,-1,0,0,0,0,0, ], 1006,0,0,[ ]). +group([ +box('black','',540,104,668,232,0,1,1,1009,0,0,0,0,0,'1',0,[ +]), +text('black',604,116,1,1,1,67,15,1010,12,3,0,0,0,0,2,67,15,0,0,"",0,0,0,0,128,'',[ +minilines(67,15,0,0,1,0,0,[ +mini_line(67,12,3,0,0,0,[ +str_block(0,67,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica-Bold',1,69120,67,12,3,0,0,0,0,0,0,0, + "line_cooker")]) +]) +])]) +], +1008,0,0,[ +]). +poly('black','',2,[ + 540,136,668,136],0,1,1,1016,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +text('black',544,184,1,0,1,61,15,1019,12,3,0,0,0,0,2,61,15,0,0,"",0,0,0,0,196,'',[ +minilines(61,15,0,0,0,0,0,[ +mini_line(61,12,3,0,0,0,[ +str_block(0,61,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,61,12,3,0,-1,0,0,0,0,0, + "cook_this()")]) +]) +])]). +text('black',544,200,1,0,1,61,15,1020,12,3,0,0,0,0,2,61,15,0,0,"",0,0,0,0,212,'',[ +minilines(61,15,0,0,0,0,0,[ +mini_line(61,12,3,0,0,0,[ +str_block(0,61,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,61,12,3,0,-1,0,0,0,0,0, + "hostname()")]) +]) +])]). +poly('black','',2,[ + 540,184,668,184],0,1,1,1021,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 488,144,540,144],0,1,1,1066,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +oval('black','',532,140,540,148,1,1,1,1067,0,0,0,0,0,'1',0,[ +]). diff --git a/doc/dataflow.obj b/doc/dataflow.obj index cdf5e8b..5c55709 100644 --- a/doc/dataflow.obj +++ b/doc/dataflow.obj @@ -1,7 +1,7 @@ %TGIF 4.1.41-QPL -state(0,37,100.000,0,0,0,8,1,0,2,2,0,0,1,0,1,1,'Helvetica',0,69120,0,0,0,10,0,0,1,0,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). +state(0,37,100.000,0,36,0,8,1,0,2,2,0,0,1,0,1,1,'Helvetica',0,69120,0,0,0,10,0,0,1,0,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). % -% @(#)$Header: /src/cvsroot/gnucomo/doc/dataflow.obj,v 1.1 2002-09-05 13:21:45 arjen Exp $ +% @(#)$Header: /src/cvsroot/gnucomo/doc/dataflow.obj,v 1.2 2003-08-11 16:57:42 arjen Exp $ % %W% % unit("1 pixel/pixel"). @@ -30,48 +30,34 @@ str_seg('black','Helvetica-Bold',1,103680,368,18,5,0,-1,0,0,0,0,0, box('black','',64,64,896,896,0,1,1,7,0,0,0,0,0,'1',0,[ ]). group([ -oval('black','',144,208,240,304,0,1,1,8,0,0,0,0,0,'1',0,[ +oval('black','',256,208,352,304,0,1,1,8,0,0,0,0,0,'1',0,[ ]), -text('black',192,249,1,1,1,44,15,9,12,3,0,0,0,0,2,44,15,0,0,"",0,0,0,0,261,'',[ -minilines(44,15,0,0,1,0,0,[ -mini_line(44,12,3,0,0,0,[ -str_block(0,44,12,3,0,-1,0,0,0,[ -str_seg('black','Helvetica',0,69120,44,12,3,0,-1,0,0,0,0,0, - "Passive")]) +text('black',304,249,1,1,1,53,15,9,12,3,0,0,0,0,2,53,15,0,0,"",0,0,0,0,261,'',[ +minilines(53,15,0,0,1,0,0,[ +mini_line(53,12,3,0,0,0,[ +str_block(0,53,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,53,12,3,0,0,0,0,0,0,0, + "logrunner")]) ]) ])]) ], 17,0,0,[ ]). group([ -oval('black','',144,400,240,496,0,1,1,19,0,0,0,0,0,'1',0,[ +oval('black','',264,352,360,448,0,1,1,19,0,0,0,0,0,'1',0,[ ]), -text('black',192,441,1,1,1,36,15,20,12,3,0,0,0,0,2,36,15,0,0,"",0,0,0,0,453,'',[ -minilines(36,15,0,0,1,0,0,[ -mini_line(36,12,3,0,0,0,[ -str_block(0,36,12,3,0,-1,0,0,0,[ -str_seg('black','Helvetica',0,69120,36,12,3,0,-1,0,0,0,0,0, - "Active")]) +text('black',312,393,1,1,1,78,15,20,12,3,0,0,0,0,2,78,15,0,0,"",0,0,0,0,405,'',[ +minilines(78,15,0,0,1,0,0,[ +mini_line(78,12,3,0,0,0,[ +str_block(0,78,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,78,12,3,0,-1,0,0,0,0,0, + "Active probes")]) ]) ])]) ], 18,0,0,[ ]). group([ -oval('black','',272,304,368,400,0,1,1,22,0,0,0,0,0,'1',0,[ -]), -text('black',320,345,1,1,1,55,15,23,12,3,0,0,0,0,2,55,15,0,0,"",0,0,0,0,357,'',[ -minilines(55,15,0,0,1,0,0,[ -mini_line(55,12,3,0,0,0,[ -str_block(0,55,12,3,0,-1,0,0,0,[ -str_seg('black','Helvetica',0,69120,55,12,3,0,-1,0,0,0,0,0, - "Aquisition")]) -]) -])]) -], -21,0,0,[ -]). -group([ oval('black','',464,264,560,360,0,1,1,31,0,0,0,0,0,'1',0,[ ]), text('black',512,305,2,1,1,52,30,32,12,3,0,0,0,0,2,52,30,0,0,"",0,0,0,0,317,'',[ @@ -93,12 +79,12 @@ str_seg('black','Helvetica',0,69120,46,12,3,0,-1,0,0,0,0,0, group([ oval('black','',464,400,560,496,0,1,1,34,0,0,0,0,0,'1',0,[ ]), -text('black',512,441,1,1,1,78,15,35,12,3,0,0,0,0,2,78,15,0,0,"",0,0,0,0,453,'',[ -minilines(78,15,0,0,1,0,0,[ -mini_line(78,12,3,0,0,0,[ -str_block(0,78,12,3,0,-1,0,0,0,[ -str_seg('black','Helvetica',0,69120,78,12,3,0,-1,0,0,0,0,0, - "Uniformication")]) +text('black',512,441,1,1,1,57,15,35,12,3,0,0,0,0,2,57,15,0,0,"",0,0,0,0,453,'',[ +minilines(57,15,0,0,1,0,0,[ +mini_line(57,12,3,0,0,0,[ +str_block(0,57,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,57,12,3,0,0,0,0,0,0,0, + "gcm_input")]) ]) ])]) ], @@ -107,12 +93,12 @@ str_seg('black','Helvetica',0,69120,78,12,3,0,-1,0,0,0,0,0, group([ oval('black','',208,592,304,688,0,1,1,37,0,0,0,0,0,'1',0,[ ]), -text('black',256,633,1,1,1,29,15,38,12,3,0,0,0,0,2,29,15,0,0,"",0,0,0,0,645,'',[ -minilines(29,15,0,0,1,0,0,[ -mini_line(29,12,3,0,0,0,[ -str_block(0,29,12,3,0,-1,0,0,0,[ -str_seg('black','Helvetica',0,69120,29,12,3,0,-1,0,0,0,0,0, - "Scan")]) +text('black',256,633,1,1,1,74,15,38,12,3,0,0,0,0,2,74,15,0,0,"",0,0,0,0,645,'',[ +minilines(74,15,0,0,1,0,0,[ +mini_line(74,12,3,0,0,0,[ +str_block(0,74,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,74,12,3,0,-1,0,0,0,0,0, + "gcm_daemon")]) ]) ])]) ], @@ -264,21 +250,6 @@ str_seg('black','Helvetica',0,69120,43,12,3,0,-1,0,0,0,0,0, ], 98,0,0,[ ]). -poly('black','',3,[ - 240,256,320,256,320,304],1,1,1,116,0,0,0,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). -poly('black','',3,[ - 240,448,320,448,320,400],1,1,1,117,0,0,0,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). -poly('black','',4,[ - 368,352,416,352,416,312,464,312],1,1,1,118,0,0,0,0,0,0,0,'1',0,0, - "0","",[ - 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ -]). poly('black','',2,[ 512,360,512,400],1,1,1,120,0,0,0,0,0,0,0,'1',0,0, "0","",[ @@ -320,7 +291,56 @@ poly('black','',4,[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). poly('black','',3,[ - 304,808,576,808,576,688],1,1,1,130,0,0,0,0,0,0,0,'1',0,0, + 304,832,576,832,576,688],1,1,1,130,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 352,256,448,256,480,280],1,1,1,1089,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 360,400,424,400,480,344],1,1,1,1090,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +oval('black','',384,720,480,816,0,1,1,1102,0,0,0,0,0,'1',0,[ +]), +text('black',432,761,1,1,1,35,15,1103,12,3,0,0,0,0,2,35,15,0,0,"",0,0,0,0,773,'',[ +minilines(35,15,0,0,1,0,0,[ +mini_line(35,12,3,0,0,0,[ +str_block(0,35,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,35,12,3,0,-1,0,0,0,0,0, + "Admin")]) +]) +])]) +], +1101,0,0,[ +]). +poly('black','',2,[ + 432,720,432,688],1,1,1,1107,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +box('black','',104,296,232,352,0,1,1,1110,0,0,0,0,0,'1',0,[ +]). +text('black',168,316,1,1,1,96,15,1111,12,3,0,0,0,0,2,96,15,0,0,"",0,0,0,0,328,'',[ +minilines(96,15,0,0,1,0,0,[ +mini_line(96,12,3,0,0,0,[ +str_block(0,96,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,96,12,3,0,-1,0,0,0,0,0, + "monitored system")]) +]) +])]). +poly('black','',3,[ + 168,296,168,256,256,256],1,1,1,1113,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 168,352,168,400,264,400],1,1,1,1114,0,0,0,0,0,0,0,'1',0,0, "0","",[ 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ ]). diff --git a/doc/design.xml b/doc/design.xml index 505bd03..d73154d 100644 --- a/doc/design.xml +++ b/doc/design.xml @@ -6,7 +6,7 @@ Arjen Baart <arjen@andromeda.nl> Brenno de Winter<brenno@dewinter.com> - December 17, 2002 + Peter Roozemaal<mathfox@xs4all.nl> + August 06, 2003 - 0.2 + 0.5 Andromeda Technology & Automation De Winter Information Solutions @@ -58,6 +57,33 @@ data flow diagram below: +At the left of the diagram, information is aquired from the monitored system. +Several agents can be used to obtain information from this system, in +active or passive ways. +A passive agent uses information which is available on the system anyway, +such as log files or other lists. +An active agent, requests explicit data from the monitored system. +One example of a passive agent is logrunner, a program which +monitores system log files and sends regular updates to the gnucomo +server. +The agents on the monitored system send the data to some kind of transportation channel. +This can be any form of transport, such as Email, SOAP, plain file copying or +some special network connection. +If desired, the transportation may provide security. +Once arrived at the server, the information from monitored systems is captured +by the gcm_input process. +This process can obtain the data through many forms of transport and from +a number of input formats. +Gcm_input will try to recognize as much as possible from an +input message and store the obtained information into the Raw Storage +database. +The Raw Storage data is processed further and analyzed by +the gcm_daemon, which scans the data, gathers statistics and +stores its results into the Derived Storage database where +it is available for human review and further analysis. + + + Architectural items to consider: Active and passive data acquisition @@ -113,13 +139,101 @@ The destructor will of course close the database connection. -Other methods provide access to the database. +Other methods provide access to the database in a low-level manner. There will be lots more in the future, but here are a few to begin with: -Find the objectid of a host, given its hostname -Insert a log record into the log table +Send a SQL query to the database. +Read a tuple from a result set. +Obtain the userid for the current database session. + + +The information stored in the database as tuples is represented by classes in +other programming languages such as C++ of PHP. +Each class models a particular type of tuple (an entity) +in the database. +Such classes maintain the relation with the database on one end, +while providing methods that are specific to the entity on the other end. +All database communication and SQL queries are hidden inside the +entity's class. +This includes, for example, handling database result sets and access control. + + +Properties and operations that are common to all classes that represent +entities in the database are caught in a common base class. +The base class, named database_entity provides default +implementations for loading and storing tuples, construction and destruction +and iteration. +Most derived classes will override these functions. +Two examples of classes that represent entities in the database +are object and service. +Both are derived from a database_entity, as show below: + + + + + + +Constructors of classes derived from database_entity come in +two variaties: with or without database interaction. +Constructors that do not interact with the database have only one argument: +a reference to the gnucomo_database object which handles +the low-level interaction with the database server. +The example below shows a few of these constructors: + + + database_entity::database_entity(gnucomo_database &gdb) + + object::object(gnucomo_database &gdb) + + service::service(gnucomo_database &gdb) + + +The objective of this type of constructor is to cerate a fresh tuple and +store it in the database later on. +All these constructors do is establish the connection to the database +server and fill in the defaults for the fields in the tuple. +A destructor will put the actual tuple into the database if any +information in the object has changed. +This mey be by sending an INSERT if the object is completely fresh +or an UPDATE if an already existing tuple was changed. +The state information about the freshness of an object is a property +common to all database entities and is therefore maintained in +the database_entity class. + + +Constructors that do interact with the database accept additional +arguments after the initial gnucomo_database reference. +These extra arguments are used to retreive a tuple from the database. +Examples of such constructors are: + + + object::object(gnucomo_database &gdb, String hostname) + + object::object(gnucomo_database &gdb, long long oid) + + service::service(gnucomo_database &gdb, String name) + + +The set of arguments must of course correspond to a set of fields that +uniquely identify the tuple. +The primary key of the database table would be ideally suitable. +If the tuple is not found in the database, data members of the object +are set to default values and the object is marked as being fresh and +not changed. + + + +Methods with the same name as a field in a tuple read or change the +value of that field. +Without an argument, such a method returns the current value of the field. +With a single argument, the field is set to the new value passed in the +argument and the method returns the original value. +Whenever a field is set to a new value, the object is marked as being +'changed'. +A destructor will then save the tuple to the database. +
@@ -151,17 +265,47 @@ The value of a user-specific configuration parameter overrides the system-wide value. -At the moment, the gnucomo configuration has one section, holding -four parameters which define how to access the gnucomo database: +The following sections and parameters are defined for the Gnucomo +configuration: -type -name -user -password +database + + type + name + user + password + host + port + + +logging + + method + destination + level + + +gcm_input + + dbuser + password + + +gcm_daemon + + dbuser + password + + -The type parameter must have the content PostgreSQL. +The database section defines how the database is accessed. +The database/type parameter must have the content PostgreSQL. Other database systems are not supported yet. +The database/user and database/password provide default +login information onto the database server. +Specific user names and passwords may be specified for separate applications, such +as gcm_input and gcm_daemon. @@ -217,10 +361,15 @@ transportation channel. Here are a few examples: -Copied directly from a local client's file system. +Obtained directly from a local client's file system. +From the output of another process, through standard input. Copied remotely from a client's file system, e.g. using -ftp, rcp or scp. + ftp, rcp or scp. + This is usually handled through spooled files. + Through an email. +As a SOAP web service, carried through HTTP or SMTP. +Through a TCP connection on a special socket. On top of that, any message may be encrypted, for example with PGP or GnuPG. @@ -231,7 +380,8 @@ in the background, since human intervention is needed to enter the secret key. The primary function of gcm_input is to store lines from a client's -log files into the log table. +log files into the log table or scan a report from a probe and update +the parameter table. To do this, we need certain information about the client message that is usually not in the content of a log file. This information includes: @@ -244,7 +394,77 @@ This information includes: Sometimes, this information is available from the message itself, as in an email header. On other occasions, the information needs to be supplied externally, e.g. by using command line options. +In any case, this type of 'header' information is relevant to the message +as a whole. +As a result, gcm_input can accept one and only one message at a time. +For example, it is not possible to connect the standard output of +logrunner to the standard input of gcm_input and have +a continuous stream of messages from different log sources. +Each message should be fed to gcm_input separately. +Also when logrunner uses a special socket to send logging data, +a new connection must be created for each message. +The dataflow diagram below shows how a message travels from the input source +to the database. + + + + + + + +Internally, gcm_input handles XML input +and each input item must have its data fields split into appropriate XML elements. +when data is offered in some other form, this data must be filtered +and transformed into XML before gcm_input can handle it. +Two levels of transformation are possible. +At the highest level, the whole message is transformed into an XML +document with a <message> root element and the +appropriate <header> and <data> +elements, all of which are put in the proper namespace. +At the lowest level, each line of the message's data can be transformed +into a <cooked> <log> element. +Two classes of replaceable filter objects take care of these transformations. +Depending on the content of the message and/or command line options to +gcm_input, and appropriate filter object is inserted into +the data stream. + + + +The line_cooker +operates on a node in the DOM tree which is +supposed to be a <raw> <log> element that contains one line +from a log file. +The line_cooker transforms a raw log line into +its constituent parts that make up en <cooked> element. +Since each type of logfile uses a different layout and syntax, +different line cookers can be used, depending on the type of log. +This type is indicated by the <messagetype> element in the header +part of the message. +Clearly, the line_cooker is a polymorphic entity. +Exactly which line_cooker is used is determined through +classifying +the content of the message or the message type indicated in the header. +The line_cooker base class provides a default implementation +for most methods, while derived classes provide the actual cooking. + + + +Ouput created by gcm_input for logging and debugging purposes +can be sent to one of several destinations: + +standard error. +a log file. +the system log. +an email address. + +The actual destination is stated in the gnucomo +configuration file. The default is stderr. +A log object filters output according to the debug level. + + + + Apart from determining information about the client's message, the content of the message needs to be analyzed in order to handle it properly. @@ -252,12 +472,33 @@ The body of the message may contain all sorts of information, such as: System log file Apache log file -Report from a Gnucomo agent +Report from a Gnucomo agent or other probe, for example "rpm -qa" + or "df -k". +Generic XML input Something else... +Basically, gcm_input acceepts two kinds of input: Log lines +and parameter reprots. The message is analyzed to obtain information about what the message entails and where it came from. +The message classification embodies the way in which a message must be +handled and in what way information from the message can be put into +the database. +Aspects for handling the message are for example: + +Strip lines at the beginning or end. +Store each line separately or store the message as a whole. +How to extract hostname, arrival time and service from the message. +How to break up the message into individual fields for a log record. + +These aspects are all handled in polymorphic message_filter +and line_cooker classes. +The result of classifying a message is the selection of the proper +objects derived from these classes from a collection of such objects. + + + The classify() method tries to extract that information. Sometimes, this information can not be determined with absolute 100% certainty. The certainty expresses how sure we are about the contents in the message. @@ -299,6 +540,14 @@ encrypted. Decrypting is possible only if someone or something provides a secret key. +<?xml version='1.0'?> + + +The XML header declares the message to be generic XML input. +The structure of the XML message that gcm_input accepts +is described in the next section. + + Sep 1 04:20:00 kithira kernel: solo1: unloading @@ -309,20 +558,203 @@ We can match this with a regular expression to see if the message holds syslog l Similar matches can be used to find Apache log lines or output from the dump backup program or anything else. + + + + -The message classification embodies the way in which a message must be -handled and in what way information from the message can be put into -the database. -Aspects for handling the message are for example: + +Since gcm_input can not understand every conceivable form +of input, a client can offer its input in a more generic form which reflects +the structure of the Gnucomo database. +In this case, the input is structured in an XML document that contains the input +data in a form that allows gcm_input to store the information +into the database without knowing the nature of the input. +The XML root element for gcm_input is a <message>, defined +in the namespace with namespace name http://gnucomo.org/transport/. +All other elements and attributes of the <message> must be defined +within this namespace. + + +Within the <message> element there is a <header> +and a <data> element. +The <data> element may contain the logdata in an externally +specified format. +The <header> element contains a number of elements (fields), some +mandatory, some optional. The text of the element contains the value of +the element. +The following elements have been defined: + -Strip lines at the beginning or end. -Store each line separately or store the message as a whole. -How to extract hostname, arrival time and service from the message. -How to break up the message into individual fields for a log record. + +<mesagetype> mandatory + + The type (format) of the logdata in the data element. The message type + determines the way in which raw log elements are parsed and split up + into separate fields for insertion into the database. + The message types gcm_input understands are: + + system log : The most common form of UNIX system logs. + Also used in most Linux distributions. + + IRIX system log : Variation of system log, used by SGI. + + apache access log : Access log of the Apache http daemon, + in default form. + + apache error log : Error log of the Apache http daemon, + in default form. + + + There mnust also be a 'generic' system log in case all elements are + cooked already. + + + +<hostname> mandatory + + The name of the system that generated the data in the data block. + This can be different from the computer composing the message. + + + +<service> optional + + The (default) value of the service running on the host that + generated the message data. For logfiles that don't contain the + service name embedded in them. + + + +<time> optional + + The best approximation to the time that the data was generated. + For (log)data that doesn't contain an embedded datestamp. + + + + +The following example shows an XML message for gcm_input +with a filled-in header and an empty <data> element: + + + <gcmt:message xmlns:gcmt='http://gnucomo.org/transport/'> + <gcmt:header> + <gcmt:messagetype>apache error log</gcmt:messagetype> + <gcmt:hostname>client.gnucomo.org</gcmt:hostname> + <gcmt:service>httpd</gcmt:service> + <gcmt:time>2003-04-17 14:40:46.312895+01:00</gcmt:time> + </gcmt:header> + <gcmt:data/> + </gcmt:message> + + + + +The data element can hold one of two possible child +elemnts: <log> or <parameters>. +The <log> element may contain any number of lines from +a system's log file, each line in a separate element. +A single log line is the content of either a <raw> or +a <cooked> element. +The <raw> element contains the log line "as is" and nothing more. +This is the easiest way to provide XML data for gcm_input. +However, the log line itself must be in a form that gcm_input +can understand. +After all, gcm_input still needs to extract meaningfull information +from that line, such as the timestamp and the service that created the log. +The client can also choose to provide that information separately by encapsulating +the log line in a <cooked> element. +This element may have up to four child elements, two of which are mandatory: + +<timestamp> mandatory. + + The time at which the log line was generated by the client. + + +<hostname> optional. + + For logs that include a hostname in each line. This hostname is checked + against the hostname in the <header> element. + + +<service> optional. + + If the service that generated the log is not provided in the <header> + the service must be stated for each log line separately. + Othewise, each log line is assumed to be generated by the same service. + + +<raw> mandatory. + + The content of the full log line. This would have the same content of the singular + <raw> element if the log line was not provided in a + <cooked> element. + + +The following shows an example of the log message with two lines in the +<log> element, one raw and one cooked: + + + <gcmt:data xmlns:gcmt='http://gnucomo.org/transport/'> + <gcmt:log> + <gcmt:raw> + Apr 13 04:31:03 schiza kernel: attempt to access beyond end of device + </gcmt:raw> + <gcmt:cooked> + <gcmt:timestamp>2003-04-13 04:31:03+02:00</gcmt:timestamp> + <gcmt:hostname>schiza</gcmt:hostname> + <gcmt:service>kernel</gcmt:service> + <gcmt:raw> + Apr 13 04:31:03 schiza kernel: 03:05: rw=0, want=1061109568, limit=2522173 + </gcmt:raw> + </gcmt:cooked> + </gcmt:log> + </gcmt:data> + + + + +The <parameters> element contains a list of parameters +of the same class. The class is provided as an attribute in the +<parameters> open tag. +There is a <parameter> element for each parameter in the list. +The child elements of a <parameter> are one optional +<description> element and zero or more <property> +elements. +The names of a parameter and a property are provided by the mandatory name +attributes in the respective elements. +The following example shows a possible parameter report from a "df -k": + + <gcmt:data xmlns:gcmt='http://gnucomo.org/transport/'> + <gcmt:parameters gcmt:class='filesystem'> + <gcmt:parameter gcmt:name='root'> + <gcmt:description>Root filesystem</gcmt:description> + <gcmt:property gcmt:name='size'>303344</gcmt:property> + <gcmt:property gcmt:name='used'>104051</gcmt:property> + <gcmt:property gcmt:name='available'>183632</gcmt:property> + <gcmt:property gcmt:name='device'>/dev/hda1</gcmt:property> + <gcmt:property gcmt:name='mountpoint'>/</gcmt:property> + </gcmt:parameter> + <gcmt:parameter gcmt:name='usr'> + <gcmt:description>Usr filesystem</gcmt:description> + <gcmt:property gcmt:name='size'>5044188</gcmt:property> + <gcmt:property gcmt:name='used'>3073716</gcmt:property> + <gcmt:property gcmt:name='available'>1714236</gcmt:property> + <gcmt:property gcmt:name='device'>/dev/hdd2</gcmt:property> + <gcmt:property gcmt:name='mountpoint'>/usr</gcmt:property> + </gcmt:parameter> + </gcmt:parameters> + </gcmt:data> + + + + +Gcm_input classes The figure below shows the class diagram that is used for gcm_input: @@ -330,7 +762,8 @@ The figure below shows the class diagram that is used for gcm_input The heart of the application is a client_message object. -This object reads the message through the message_buffer from some +This object reads the message through the +message_buffer from some input stream (file, string, stdin or socket), classifies the message and enters information from the message into the database. It has a relationship with a gnucomo_database object which @@ -338,20 +771,28 @@ is an abstraction of the tables in the database. These are the methods for the client_message class: -client_message::client_message(istream *in, gnucomo_database *db) +client_message::client_message(istream *in, gnucomo_database *db) Constructor. -double client_message::classify(String host, date arrival_d, hour arrival_t, String serv) +void add_cooker(line_cooker *lc) + + Add another line_cooker object to the collection. + + +double client_message::classify(String host, date arrival_d, + hour arrival_t, String serv) Try to classify the message and return the certainty with which the class of the message could be determined. If the hostname, arrival time and service can not be extracted from the message, use the arguments as default. + This will try to select one of the line_cooker objects + from the collection built with the add_cooker method. -int enter() +int enter() Insert the message contents into the log table of the gnucomo database. @@ -361,6 +802,119 @@ These are the methods for the client_message class: + + + + +To turn a raw line from a log file onto separate parts that can be stored +in the database, i.e. parse the line, the client_message +object uses a line_cooker object. +This is a polymorphic object, so each type of log can have its own parser, +while the client_message object uses a common interface +for each one. +For each message, one specific line_cooker object is +selected as determined by the message type. +E.g., the derived class syslog_cooker is used for system logs. +When the client_message object encounters a raw +log element, it takes the following steps to turn this into a +cooked log element: + + + Remove the TEXT node of the "raw" element and save its content. + + + Change the name of the element into "cooked". + + + Check if the content matches the syntax of the type of log we're + processing at the moment. + This depends on the message type and is therefore a task for the + line_cooker object. + + + Have the line_cooker parse the content and extract + the timestamp and optionally the hostname and service. + + + Insert new child elements into the cooked element. + + +After that, the cooked element is ready for further processing +and possibly storing into the database. + + + +The line_cooker base class holds three protected members +that must be filled with infomation by the derived classes: + +UTC ts : the timestamp. +String hn : the hostname +String srv : the service + +Corresponding base class methods (timestamp, +hostname and service) will do +nothing more than return these values. +It is up to the derived class's cook_this method +to properly initialize these members. + + + +The methods for the line_cooker class are: + + + bool line_cooker::check_pattern(String logline) + + Tries to match the logline against that patterns + that describe the message syntax. + In the line_cooker base class, this is a pure virtual function. + Returns true if the log line adheres to the message-specific syntax. + + + + bool line_cooker::cook_this(String logline, UTC arrival) + + Extracts information from the logline. + The arrival can be used to make corrections to incomplete + time stamps in the log file. + The implementation in a derived class must properly initialize the protected + members described above. + In the line_cooker base class, this is a pure virtual function. + Returns false if the pattern does not match. + + + + String line_cooker::message_type() + + Return the message type for which this line cooker is intended. + + + + UTC line_cooker::timestamp() + + Returns the timestamp that was previously extracted from the log line + or a 'null' timestamp if that information could nnot be extracted. + + + + String line_cooker::hostname() + + Returns the hostname that was previously extracted from the log line, + or an empty string if that information could not be extracted. + + + + String line_cooker::service() + + Returns the service that was previously extracted from the log line, + or an empty string if that information could not be extracted. + + + + + + + + Some kind of input buffering is needed when a client message is being processed. The contents of the message are not entirely clear until a few lines are analyzed, @@ -424,6 +978,10 @@ Methods for the message_buffer class: message_buffer::operator ++ + + + + Command arguments diff --git a/doc/gcm_input-dataflow.obj b/doc/gcm_input-dataflow.obj new file mode 100644 index 0000000..2c9c2a1 --- /dev/null +++ b/doc/gcm_input-dataflow.obj @@ -0,0 +1,512 @@ +%TGIF 4.1.41-QPL +state(0,37,100.000,0,16,0,8,1,0,2,2,0,0,1,0,1,1,'Helvetica',0,69120,0,0,0,10,0,0,1,0,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0). +% +% @(#)$Header: /src/cvsroot/gnucomo/doc/gcm_input-dataflow.obj,v 1.1 2003-08-11 16:57:42 arjen Exp $ +% %W% +% +unit("1 pixel/pixel"). +color_info(8,65535,0,[ + "black", 0, 0, 0, 0, 0, 0, 1, + "red", 65535, 0, 0, 65535, 0, 0, 1, + "green", 0, 65535, 0, 0, 65535, 0, 1, + "blue", 0, 0, 65535, 0, 0, 65535, 1, + "magenta", 65535, 0, 65535, 65535, 0, 65535, 1, + "cyan", 0, 65535, 65535, 0, 65535, 65535, 1, + "white", 65535, 65535, 65535, 65535, 65535, 65535, 1, + "yellow", 65535, 65535, 0, 65535, 65535, 0, 1 +]). +script_frac("0.6"). +fg_bg_colors('black','White'). +dont_reencode("FFDingbests:ZapfDingbats"). +page(1,"",1,''). +text('black',480,78,1,1,1,262,23,0,18,5,0,0,0,0,2,262,23,0,0,"",0,0,0,0,96,'',[ +minilines(262,23,0,0,1,0,0,[ +mini_line(262,18,5,0,0,0,[ +str_block(0,262,18,5,0,-1,0,0,0,[ +str_seg('black','Helvetica-Bold',1,103680,262,18,5,0,-1,0,0,0,0,0, + "gcm_input - Dataflow diagram")]) +]) +])]). +box('black','',64,64,896,896,0,1,1,7,0,0,0,0,0,'1',0,[ +]). +group([ +oval('black','',544,136,640,232,0,1,1,8,0,0,0,0,0,'1',0,[ +]), +text('black',592,177,2,1,1,49,30,9,12,3,0,0,0,0,2,49,30,0,0,"",0,0,0,0,189,'',[ +minilines(49,30,0,0,1,0,0,[ +mini_line(49,12,3,0,0,0,[ +str_block(0,49,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,49,12,3,0,-1,0,0,0,0,0, + "message")]) +]), +mini_line(23,12,3,0,0,0,[ +str_block(0,23,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,23,12,3,0,0,0,0,0,0,0, + "filter")]) +]) +])]) +], +17,0,0,[ +]). +group([ +box('black','',192,160,288,216,0,1,1,1110,0,0,0,0,0,'1',0,[ +]), +text('black',240,172,2,1,1,38,30,1111,12,3,0,0,0,0,2,38,30,0,0,"",0,0,0,0,184,'',[ +minilines(38,30,0,0,1,0,0,[ +mini_line(27,12,3,0,0,0,[ +str_block(0,27,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,27,12,3,0,0,0,0,0,0,0, + "input")]) +]), +mini_line(38,12,3,0,0,0,[ +str_block(0,38,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,38,12,3,0,-1,0,0,0,0,0, + "source")]) +]) +])]) +], +1253,0,0,[ +]). +group([ +box('black','',80,296,176,352,0,1,1,1255,0,0,0,0,0,'1',0,[ +]), +text('black',128,308,1,1,1,17,15,1256,12,3,0,0,0,0,2,17,15,0,0,"",0,0,0,0,320,'',[ +minilines(17,15,0,0,1,0,0,[ +mini_line(17,12,3,0,0,0,[ +str_block(0,17,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,17,12,3,0,-1,0,0,0,0,0, + "cin")]) +]) +])]) +], +1254,0,0,[ +]). +group([ +box('black','',192,296,288,352,0,1,1,1258,0,0,0,0,0,'1',0,[ +]), +text('black',240,308,1,1,1,42,15,1259,12,3,0,0,0,0,2,42,15,0,0,"",0,0,0,0,320,'',[ +minilines(42,15,0,0,1,0,0,[ +mini_line(42,12,3,0,0,0,[ +str_block(0,42,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,42,12,3,0,-1,0,0,0,0,0, + "ifstream")]) +]) +])]) +], +1257,0,0,[ +]). +group([ +box('black','',304,296,400,352,0,1,1,1261,0,0,0,0,0,'1',0,[ +]), +text('black',352,308,2,1,1,36,30,1262,12,3,0,0,0,0,2,36,30,0,0,"",0,0,0,0,320,'',[ +minilines(36,30,0,0,1,0,0,[ +mini_line(27,12,3,0,0,0,[ +str_block(0,27,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,27,12,3,0,0,0,0,0,0,0, + "input")]) +]), +mini_line(36,12,3,0,0,0,[ +str_block(0,36,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,36,12,3,0,0,0,0,0,0,0, + "socket")]) +]) +])]) +], +1260,0,0,[ +]). +polygon('black','',4,[ + 240,240,224,256,256,256,240,240],0,1,1,0,1272,0,0,0,0,0,'1',0, + "0",[ +]). +poly('black','',2,[ + 240,216,240,240],0,1,1,1274,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 240,256,128,256,128,296],0,1,1,1275,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 240,256,240,296],0,1,1,1279,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 240,256,352,256,352,296],0,1,1,1280,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 288,184,416,184],0,1,1,1296,0,1,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +group([ +oval('black','',440,176,456,192,1,1,1,1281,0,0,0,0,0,'1',0,[ +]), +box('black','',456,180,480,188,1,1,1,1283,0,0,0,0,0,'1',0,[ +]) +], +1291,0,0,[ +]), +group([ +arc('black','',0,3,1,0,432,168,448,184,448,168,448,200,0,32,32,5760,11520,1282,0,0,12,5,0,0,0,'3','12','5',0,[ +]), +poly('black','',2,[ + 432,184,416,184],0,1,1,1284,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]) +], +1295,0,0,[ +]) +], +1308,0,0,[ +]). +group([ +group([ +oval('black','',696,176,712,192,1,1,1,1311,0,0,0,0,0,'1',0,[ +]), +box('black','',672,180,696,188,1,1,1,1312,0,0,0,0,0,'1',0,[ +]) +], +1310,0,0,[ +]), +group([ +arc('black','',0,3,1,0,688,168,704,184,704,168,704,200,1,32,32,5760,-11520,1314,0,0,12,5,0,0,0,'3','12','5',0,[ +]), +poly('black','',2,[ + 720,184,736,184],0,1,1,1315,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]) +], +1313,0,0,[ +]) +], +1309,0,0,[ +]). +poly('black','',2,[ + 480,184,544,184],1,1,1,1323,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 640,184,672,184],1,1,1,1327,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +oval('black','',664,312,760,408,0,1,1,1329,0,0,0,0,0,'1',0,[ +]), +text('black',712,353,1,1,1,24,15,1330,12,3,0,0,0,0,2,24,15,0,0,"",0,0,0,0,365,'',[ +minilines(24,15,0,0,1,0,0,[ +mini_line(24,12,3,0,0,0,[ +str_block(0,24,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,24,12,3,0,0,0,0,0,0,0, + "Raw")]) +]) +])]) +], +1328,0,0,[ +]). +group([ +oval('black','',544,312,640,408,0,1,1,1332,0,0,0,0,0,'1',0,[ +]), +text('black',592,353,1,1,1,30,15,1333,12,3,0,0,0,0,2,30,15,0,0,"",0,0,0,0,365,'',[ +minilines(30,15,0,0,1,0,0,[ +mini_line(30,12,3,0,0,0,[ +str_block(0,30,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,30,12,3,0,-1,0,0,0,0,0, + "Email")]) +]) +])]) +], +1331,0,0,[ +]). +group([ +oval('black','',424,312,520,408,0,1,1,1335,0,0,0,0,0,'1',0,[ +]), +text('black',472,353,2,1,1,34,30,1336,12,3,0,0,0,0,2,34,30,0,0,"",0,0,0,0,365,'',[ +minilines(34,30,0,0,1,0,0,[ +mini_line(27,12,3,0,0,0,[ +str_block(0,27,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,27,12,3,0,0,0,0,0,0,0, + "short")]) +]), +mini_line(34,12,3,0,0,0,[ +str_block(0,34,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,34,12,3,0,0,0,0,0,0,0, + "circuit")]) +]) +])]) +], +1334,0,0,[ +]). +polygon('black','',4,[ + 592,264,576,280,608,280,592,264],0,1,1,0,1350,0,0,0,0,0,'1',0, + "0",[ +]). +poly('black','',2,[ + 592,232,592,264],0,1,1,1351,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 592,280,472,280,472,312],0,1,1,1352,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 592,280,592,312],0,1,1,1353,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 592,280,712,280,712,312],0,1,1,1357,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +oval('black','',776,392,872,488,0,1,1,1362,0,0,0,0,0,'1',0,[ +]), +text('black',824,433,2,1,1,35,30,1363,12,3,0,0,0,0,2,35,30,0,0,"",0,0,0,0,445,'',[ +minilines(35,30,0,0,1,0,0,[ +mini_line(27,12,3,0,0,0,[ +str_block(0,27,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,27,12,3,0,-1,0,0,0,0,0, + "XML")]) +]), +mini_line(35,12,3,0,0,0,[ +str_block(0,35,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,35,12,3,0,0,0,0,0,0,0, + "parser")]) +]) +])]) +], +1361,0,0,[ +]). +poly('black','',3,[ + 736,184,824,184,824,392],1,1,1,1367,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +group([ +oval('black','',704,520,720,536,1,1,1,1387,0,0,0,0,0,'1',0,[ +]), +box('black','',680,524,704,532,1,1,1,1388,0,0,0,0,0,'1',0,[ +]) +], +1386,0,0,[ +]), +group([ +arc('black','',0,3,1,0,696,512,712,528,712,512,712,544,1,32,32,5760,-11520,1390,0,0,12,5,0,0,0,'3','12','5',0,[ +]), +poly('black','',2,[ + 728,528,744,528],0,1,1,1391,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]) +], +1389,0,0,[ +]) +], +1385,0,0,[ +]). +poly('black','',3,[ + 824,488,824,528,736,528],1,1,1,1392,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +text('black',360,164,1,1,1,87,15,1393,12,3,0,0,0,0,2,87,15,0,0,"",0,0,0,0,176,'',[ +minilines(87,15,0,0,1,0,0,[ +mini_line(87,12,3,0,0,0,[ +str_block(0,87,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,87,12,3,0,0,0,0,0,0,0, + "message_buffer")]) +]) +])]). +text('black',784,164,1,1,1,83,15,1395,12,3,0,0,0,0,2,83,15,0,0,"",0,0,0,0,176,'',[ +minilines(83,15,0,0,1,0,0,[ +mini_line(83,12,3,0,0,0,[ +str_block(0,83,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,83,12,3,0,-1,0,0,0,0,0, + "XML_message")]) +]) +])]). +text('black',784,508,1,1,1,30,15,1397,12,3,0,0,0,0,2,30,15,0,0,"",0,0,0,0,520,'',[ +minilines(30,15,0,0,1,0,0,[ +mini_line(30,12,3,0,0,0,[ +str_block(0,30,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,30,12,3,0,-1,0,0,0,0,0, + "DOM")]) +]) +])]). +group([ +oval('black','',544,480,640,576,0,1,1,1400,0,0,0,0,0,'1',0,[ +]), +text('black',592,521,1,1,1,62,15,1401,12,3,0,0,0,0,2,62,15,0,0,"",0,0,0,0,533,'',[ +minilines(62,15,0,0,1,0,0,[ +mini_line(62,12,3,0,0,0,[ +str_block(0,62,12,3,0,0,0,0,0,[ +str_seg('black','Helvetica',0,69120,62,12,3,0,0,0,0,0,0,0, + "line cooker")]) +]) +])]) +], +1399,0,0,[ +]). +poly('black','',2,[ + 680,528,640,528],1,1,1,1405,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +oval('black','',664,656,760,752,0,1,1,1407,0,0,0,0,0,'1',0,[ +]), +text('black',712,697,1,1,1,64,15,1408,12,3,0,0,0,0,2,64,15,0,0,"",0,0,0,0,709,'',[ +minilines(64,15,0,0,1,0,0,[ +mini_line(64,12,3,0,0,0,[ +str_block(0,64,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,64,12,3,0,-1,0,0,0,0,0, + "access_log")]) +]) +])]) +], +1406,0,0,[ +]). +group([ +oval('black','',544,656,640,752,0,1,1,1410,0,0,0,0,0,'1',0,[ +]), +text('black',592,697,1,1,1,36,15,1411,12,3,0,0,0,0,2,36,15,0,0,"",0,0,0,0,709,'',[ +minilines(36,15,0,0,1,0,0,[ +mini_line(36,12,3,0,0,0,[ +str_block(0,36,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,36,12,3,0,-1,0,0,0,0,0, + "syslog")]) +]) +])]) +], +1409,0,0,[ +]). +group([ +oval('black','',424,656,520,752,0,1,1,1413,0,0,0,0,0,'1',0,[ +]), +text('black',472,697,1,1,1,50,15,1414,12,3,0,0,0,0,2,50,15,0,0,"",0,0,0,0,709,'',[ +minilines(50,15,0,0,1,0,0,[ +mini_line(50,12,3,0,0,0,[ +str_block(0,50,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,50,12,3,0,-1,0,0,0,0,0, + "error_log")]) +]) +])]) +], +1412,0,0,[ +]). +polygon('black','',4,[ + 592,608,576,624,608,624,592,608],0,1,1,0,1415,0,0,0,0,0,'1',0, + "0",[ +]). +poly('black','',3,[ + 592,624,472,624,472,656],0,1,1,1416,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 592,624,592,656],0,1,1,1417,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',3,[ + 592,624,712,624,712,656],0,1,1,1418,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 592,576,592,608],0,1,1,1419,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +group([ +oval('black','',432,520,448,536,1,1,1,1433,0,0,0,0,0,'1',0,[ +]), +box('black','',448,524,472,532,1,1,1,1434,0,0,0,0,0,'1',0,[ +]) +], +1432,0,0,[ +]), +group([ +arc('black','',0,3,1,0,424,512,440,528,440,512,440,544,0,32,32,5760,11520,1436,0,0,12,5,0,0,0,'3','12','5',0,[ +]), +poly('black','',2,[ + 424,528,408,528],0,1,1,1437,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]) +], +1435,0,0,[ +]) +], +1431,0,0,[ +]). +group([ +oval('black','',232,480,328,576,0,1,1,1439,0,0,0,0,0,'1',0,[ +]), +text('black',280,521,2,1,1,51,30,1440,12,3,0,0,0,0,2,51,30,0,0,"",0,0,0,0,533,'',[ +minilines(51,30,0,0,1,0,0,[ +mini_line(51,12,3,0,0,0,[ +str_block(0,51,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,51,12,3,0,-1,0,0,0,0,0, + "database")]) +]), +mini_line(28,12,3,0,0,0,[ +str_block(0,28,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,28,12,3,0,-1,0,0,0,0,0, + "entry")]) +]) +])]) +], +1438,0,0,[ +]). +poly('black','',2,[ + 544,528,472,528],1,1,1,1444,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +poly('black','',2,[ + 408,528,328,528],1,1,1,1445,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +group([ +box('black','',112,656,208,712,0,1,1,1450,0,0,0,0,0,'1',0,[ +]), +text('black',160,668,1,1,1,67,15,1451,12,3,0,0,0,0,2,67,15,0,0,"",0,0,0,0,680,'',[ +minilines(67,15,0,0,1,0,0,[ +mini_line(67,12,3,0,0,0,[ +str_block(0,67,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,67,12,3,0,-1,0,0,0,0,0, + "DATABASE")]) +]) +])]) +], +1449,0,0,[ +]). +poly('black','',3,[ + 232,528,160,528,160,656],1,1,1,1452,0,0,0,0,0,0,0,'1',0,0, + "0","",[ + 0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[ +]). +text('black',376,508,1,1,1,75,15,1459,12,3,0,0,0,0,2,75,15,0,0,"",0,0,0,0,520,'',[ +minilines(75,15,0,0,1,0,0,[ +mini_line(75,12,3,0,0,0,[ +str_block(0,75,12,3,0,-1,0,0,0,[ +str_seg('black','Helvetica',0,69120,75,12,3,0,-1,0,0,0,0,0, + "cooked DOM")]) +]) +])]). diff --git a/doc/makefile b/doc/makefile index ca1f9a4..9c4bf83 100644 --- a/doc/makefile +++ b/doc/makefile @@ -14,14 +14,14 @@ IMAGES= dataflow.png architecture.png erd-action.png erd-anu.png erd-log.png \ erd-objprior.png erd-objservice.png erd-objsysusr.png erd-objusr.png \ erd-prior.png erd-service.png erd-status.png erd-toi.png \ erd-unplog.png erd-usr.png erd.png \ - classes-gcm_input.png + class-database_entity.png classes-gcm_input.png gcm_input-dataflow.png PICTURES= dataflow.eps architecture.eps erd-action.eps erd-anu.eps erd-log.eps \ erd-lognotif.eps erd-notif.eps erd-object.eps erd-objissue.eps \ erd-objprior.eps erd-objservice.eps erd-objsysusr.eps erd-objusr.eps \ erd-prior.eps erd-service.eps erd-status.eps erd-toi.eps \ erd-unplog.eps erd-usr.eps erd.eps \ - classes-gcm_input.eps + class-database_entity.eps classes-gcm_input.eps gcm_input-dataflow.eps html: manifest.html design.html @@ -31,34 +31,34 @@ txt: manifest.txt design.txt all: ps html txt -manifest.html : $(XMLS) $(IMAGES) +manifest.html : manifest.xml $(IMAGES) xml2html manifest.xml > manifest.html -manifest.ps : $(XMLS) $(PICTURES) +manifest.ps : manifest.xml $(PICTURES) xml2latex manifest.xml >manifest.tex latex manifest.tex dvips -o manifest.ps manifest.dvi -manifest.pdf : $(XMLS) $(PICTURES) +manifest.pdf : manifest.xml $(PICTURES) xml2latex manifest.xml >manifest.tex pdflatex manifest.tex -manifest.txt : $(XMLS) +manifest.txt : manifest.xml xml2text manifest.xml > manifest.txt -design.html : $(XMLS) $(IMAGES) +design.html : design.xml $(IMAGES) xml2html design.xml > design.html -design.ps : $(XMLS) $(PICTURES) +design.ps : design.xml $(PICTURES) xml2latex design.xml >design.tex latex design.tex dvips -o design.ps design.dvi -design.pdf : $(XMLS) $(PICTURES) +design.pdf : design.xml $(PICTURES) xml2latex design.xml >design.tex pdflatex design.tex -design.txt : $(XMLS) +design.txt : design.xml xml2text design.xml > design.txt check: diff --git a/src/gcm_input/Makefile.am b/src/gcm_input/Makefile.am index 5540d82..8019c90 100644 --- a/src/gcm_input/Makefile.am +++ b/src/gcm_input/Makefile.am @@ -1,7 +1,10 @@ -bin_PROGRAMS = gcm_input +bin_PROGRAMS = gcm_input logrunner INCLUDES = -I../include LDADD = ../lib/libgnucomo.a @LIBS@ -gcm_input_SOURCES = gcm_input.cpp message.cpp +gcm_input_SOURCES = gcm_input.cpp message.cpp string_utils.cpp syslog_cooker.cpp \ + irix_syslog_cooker.cpp access_cooker.cpp error_cooker.cpp + +logrunner_SOURCES = logrunner.cpp string_utils.cpp diff --git a/src/gcm_input/Makefile.in b/src/gcm_input/Makefile.in index 76cc6a1..fa8e496 100644 --- a/src/gcm_input/Makefile.in +++ b/src/gcm_input/Makefile.in @@ -70,12 +70,16 @@ VERSION = @VERSION@ XML_CONFIG = @XML_CONFIG@ YACC = @YACC@ -bin_PROGRAMS = gcm_input +bin_PROGRAMS = gcm_input logrunner INCLUDES = -I../include LDADD = ../lib/libgnucomo.a @LIBS@ -gcm_input_SOURCES = gcm_input.cpp message.cpp +gcm_input_SOURCES = gcm_input.cpp message.cpp string_utils.cpp syslog_cooker.cpp \ + irix_syslog_cooker.cpp access_cooker.cpp error_cooker.cpp + + +logrunner_SOURCES = logrunner.cpp string_utils.cpp mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = PROGRAMS = $(bin_PROGRAMS) @@ -89,10 +93,15 @@ X_CFLAGS = @X_CFLAGS@ X_LIBS = @X_LIBS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ -gcm_input_OBJECTS = gcm_input.o message.o +gcm_input_OBJECTS = gcm_input.o message.o string_utils.o \ +syslog_cooker.o irix_syslog_cooker.o access_cooker.o error_cooker.o gcm_input_LDADD = $(LDADD) gcm_input_DEPENDENCIES = ../lib/libgnucomo.a gcm_input_LDFLAGS = +logrunner_OBJECTS = logrunner.o string_utils.o +logrunner_LDADD = $(LDADD) +logrunner_DEPENDENCIES = ../lib/libgnucomo.a +logrunner_LDFLAGS = CXXFLAGS = @CXXFLAGS@ CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) @@ -104,9 +113,11 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = gtar GZIP_ENV = --best -DEP_FILES = .deps/gcm_input.P .deps/message.P -SOURCES = $(gcm_input_SOURCES) -OBJECTS = $(gcm_input_OBJECTS) +DEP_FILES = .deps/access_cooker.P .deps/error_cooker.P \ +.deps/gcm_input.P .deps/irix_syslog_cooker.P .deps/logrunner.P \ +.deps/message.P .deps/string_utils.P .deps/syslog_cooker.P +SOURCES = $(gcm_input_SOURCES) $(logrunner_SOURCES) +OBJECTS = $(gcm_input_OBJECTS) $(logrunner_OBJECTS) all: all-redirect .SUFFIXES: @@ -163,6 +174,10 @@ maintainer-clean-compile: gcm_input: $(gcm_input_OBJECTS) $(gcm_input_DEPENDENCIES) @rm -f gcm_input $(CXXLINK) $(gcm_input_LDFLAGS) $(gcm_input_OBJECTS) $(gcm_input_LDADD) $(LIBS) + +logrunner: $(logrunner_OBJECTS) $(logrunner_DEPENDENCIES) + @rm -f logrunner + $(CXXLINK) $(logrunner_LDFLAGS) $(logrunner_OBJECTS) $(logrunner_LDADD) $(LIBS) .cpp.o: $(CXXCOMPILE) -c $< diff --git a/src/gcm_input/access_cooker.cpp b/src/gcm_input/access_cooker.cpp new file mode 100644 index 0000000..339114b --- /dev/null +++ b/src/gcm_input/access_cooker.cpp @@ -0,0 +1,83 @@ + +/************************************************************************** +** (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 : access_cooker.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks Apache http daemon access log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 11, 2003 +** LAST UPDATE : Aug 11, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: access_cooker.cpp,v $ + Revision 1.1 2003-08-11 16:56:15 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. + +*****************************/ + +/* static const char *RCSID = "$Id: access_cooker.cpp,v 1.1 2003-08-11 16:56:15 arjen Exp $"; */ + +#include + +#include "access_cooker.h" + +static const regex re_accesslog("(GET|POST) .+ HTTP"); + +bool access_cooker::check_pattern(String logline) +{ + return logline == re_accesslog; +} + +bool access_cooker::cook_this(String logline, UTC arrival) +{ + if (check_pattern(logline)) + { + String datestring = logline(regex("\\[.+\\]")); + + datestring <<= 1; + datestring >>= 1; + datestring[datestring.index(':')] = ' '; + + date log_date = datestring; + hour log_time = datestring; + + log_date = datestring; + log_time = datestring; + + ts = UTC(log_date, log_time); + + hn = ""; + srv = "httpd"; + + return true; + } + else + { + return false; + } +} + + diff --git a/src/gcm_input/access_cooker.h b/src/gcm_input/access_cooker.h new file mode 100644 index 0000000..e65c15b --- /dev/null +++ b/src/gcm_input/access_cooker.h @@ -0,0 +1,81 @@ + +/************************************************************************** +** (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 : access_cooker.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks Apache http daemon access log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 11, 2003 +** LAST UPDATE : Aug 11, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: access_cooker.h,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: access_cooker.h,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include "line_cooker.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : access_cooker +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Aug 11, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class access_cooker : public line_cooker +{ + +protected: + + +public: + + access_cooker() + { + } + + bool check_pattern(String logline); + bool cook_this(String logline, UTC arrival); + + String message_type() + { + return "apache access log"; + } + +}; diff --git a/src/gcm_input/error_cooker.cpp b/src/gcm_input/error_cooker.cpp new file mode 100644 index 0000000..3179c68 --- /dev/null +++ b/src/gcm_input/error_cooker.cpp @@ -0,0 +1,83 @@ + +/************************************************************************** +** (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 : error_cooker.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks Apache http daemon error log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 11, 2003 +** LAST UPDATE : Aug 11, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: error_cooker.cpp,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: error_cooker.cpp,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include + +#include "error_cooker.h" + +static const String unix_date_re("[[:alpha:]]{3} [[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}"); +static const regex re_errorlog("^\\[" + unix_date_re + "\\] \\[(error|notice)\\] .+"); + +bool error_cooker::check_pattern(String logline) +{ + return logline == re_errorlog; +} + +bool error_cooker::cook_this(String logline, UTC arrival) +{ + if (check_pattern(logline)) + { + String datestring = logline(regex("\\[.+\\]")); + + datestring <<= 1; + datestring >>= 1; + + date log_date = datestring; + hour log_time = datestring; + + log_date = datestring; + log_time = datestring; + + ts = UTC(log_date, log_time); + + hn = ""; + srv = "httpd"; + + return true; + } + else + { + return false; + } +} + + diff --git a/src/gcm_input/error_cooker.h b/src/gcm_input/error_cooker.h new file mode 100644 index 0000000..a3f7e11 --- /dev/null +++ b/src/gcm_input/error_cooker.h @@ -0,0 +1,81 @@ + +/************************************************************************** +** (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 : error_cooker.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks Apache http daemon error log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 11, 2003 +** LAST UPDATE : Aug 11, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: error_cooker.h,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: error_cooker.h,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include "line_cooker.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : error_cooker +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Aug 11, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class error_cooker : public line_cooker +{ + +protected: + + +public: + + error_cooker() + { + } + + bool check_pattern(String logline); + bool cook_this(String logline, UTC arrival); + + String message_type() + { + return "apache error log"; + } + +}; diff --git a/src/gcm_input/gcm_input.cpp b/src/gcm_input/gcm_input.cpp index 915934e..34d768b 100644 --- a/src/gcm_input/gcm_input.cpp +++ b/src/gcm_input/gcm_input.cpp @@ -7,7 +7,7 @@ *********************** ** FILE NAME : gcm_input.cpp ** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring -** VERSION NUMBER : $Revision: 1.5 $ +** VERSION NUMBER : $Revision: 1.6 $ ** ** DESCRIPTION : Application to store client messages into the database ** The client message contains a log file from one of the @@ -48,13 +48,23 @@ ******************************** ** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl ** CREATION DATE : Aug 29, 2002 -** LAST UPDATE : Jul 24, 2003 +** LAST UPDATE : Aug 11, 2003 ** MODIFICATIONS : **************************************************************************/ /***************************** $Log: gcm_input.cpp,v $ - Revision 1.5 2003-08-05 08:11:06 arjen + 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. @@ -74,13 +84,17 @@ *****************************/ -static const char *RCSID = "$Id: gcm_input.cpp,v 1.5 2003-08-05 08:11:06 arjen Exp $"; +static const char *RCSID = "$Id: gcm_input.cpp,v 1.6 2003-08-11 16:56:16 arjen Exp $"; #include #include #include "message.h" +#include "syslog_cooker.h" +#include "irix_syslog_cooker.h" +#include "access_cooker.h" +#include "error_cooker.h" bool verbose = false; bool testmode = false; @@ -105,7 +119,7 @@ static char *Version = "gcm_input version 0.0.7 - Jul 24, 2003"; ** VARS CHANGED : ** FUNCTIONS USED : ** SEE ALSO : -** LAST MODIFIED : Jul 24, 2003 +** LAST MODIFIED : Aug 11, 2003 **========================================================================= */ @@ -217,7 +231,16 @@ int main(int argc, char *argv[]) if (db.is_connected()) { - client_message msg(&std::cin, db); + client_message msg(&std::cin, db); + syslog_cooker slc; + irix_syslog_cooker islc; + access_cooker alc; + error_cooker elc; + + msg.add_cooker(&slc); + msg.add_cooker(&islc); + msg.add_cooker(&alc); + msg.add_cooker(&elc); if (msg.classify(hostname, arrival, service) > 0.9) { diff --git a/src/gcm_input/irix_syslog_cooker.cpp b/src/gcm_input/irix_syslog_cooker.cpp new file mode 100644 index 0000000..19a69e3 --- /dev/null +++ b/src/gcm_input/irix_syslog_cooker.cpp @@ -0,0 +1,100 @@ + +/************************************************************************** +** (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 : irix_syslog_cooker.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks IRIX system log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 09, 2003 +** LAST UPDATE : Aug 09, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: irix_syslog_cooker.cpp,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: irix_syslog_cooker.cpp,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include + +#include "irix_syslog_cooker.h" + +static const String syslog_date_re("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}"); +static const regex re_syslog_irix(syslog_date_re + " [0-7][A-T]:[[:alnum:]]+ [[:alpha:]]+.*:.+"); + +bool irix_syslog_cooker::check_pattern(String logline) +{ + return logline == re_syslog_irix; +} + +bool irix_syslog_cooker::cook_this(String logline, UTC arrival) +{ + if (check_pattern(logline)) + { + String datestring = logline(0,16); + date log_date = datestring; + hour log_time = datestring; + String rest; // Rest of the line to be parsed + int i; + + if (log_date.Year() < 0 || log_date.Year() > 2500) + { + // The year is not in the log file. Assume the year of arrival, + // unless this puts the log entry at a later date than the arrival date. + // This happens e.g. when a log entry from December arrives in Januari. + + log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year()); + if (log_date > date(arrival)) + { + log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year() - 1); + } + } + + ts = UTC(log_date, log_time); + + // Extract the hostname + + rest = logline << 19; + i = rest.index(' '); + hn = rest(0,i); + + // Extract the service + + rest <<= i + 1; + for (i = 0; isalpha(rest[i]) && i < ~rest; i++); + srv = rest(0, i); + + return true; + } + else + { + return false; + } +} + + diff --git a/src/gcm_input/irix_syslog_cooker.h b/src/gcm_input/irix_syslog_cooker.h new file mode 100644 index 0000000..24dd189 --- /dev/null +++ b/src/gcm_input/irix_syslog_cooker.h @@ -0,0 +1,81 @@ + +/************************************************************************** +** (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 : irix_syslog_cooker.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks system log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 09, 2003 +** LAST UPDATE : Aug 09, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: irix_syslog_cooker.h,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: irix_syslog_cooker.h,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include "line_cooker.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : syslog_cooker +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Aug 09, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class irix_syslog_cooker : public line_cooker +{ + +protected: + + +public: + + irix_syslog_cooker() + { + } + + bool check_pattern(String logline); + bool cook_this(String logline, UTC arrival); + + String message_type() + { + return "IRIX system log"; + } + +}; diff --git a/src/gcm_input/line_cooker.h b/src/gcm_input/line_cooker.h new file mode 100644 index 0000000..24d31d4 --- /dev/null +++ b/src/gcm_input/line_cooker.h @@ -0,0 +1,103 @@ + +/************************************************************************** +** (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 : line_cooker.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : The line_cooker abstract base class. +** Defines the interface for a collection of derived +** classes the parse different kinds of logs. +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 06, 2003 +** LAST UPDATE : Aug 06, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: line_cooker.h,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: line_cooker.h,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#ifndef LINE_COOKER_H +#define LINE_COOKER_H + +#include +#include + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : line_cooker +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Aug 06, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class line_cooker +{ + +protected: + + UTC ts; // the timestamp. + String hn; // the hostname + String srv; // the service + +public: + + line_cooker() + { + } + + virtual bool check_pattern(String logline) = 0; + virtual bool cook_this(String logline, UTC arrival) = 0; + + virtual String message_type() = 0; + + UTC timestamp() + { + return ts; + } + + String hostname() + { + return hn; + } + + String service() + { + return srv; + } +}; + +#endif // LINE_COOKER_H diff --git a/src/gcm_input/logrunner.cpp b/src/gcm_input/logrunner.cpp new file mode 100644 index 0000000..4968579 --- /dev/null +++ b/src/gcm_input/logrunner.cpp @@ -0,0 +1,495 @@ +/* + * logrunner.c + * (c) Peter Roozemaal, feb 2003 + * + * $Id: logrunner.cpp,v 1.1 2003-08-11 16:56:16 arjen Exp $ + * + * 1) compile, + * 2) create 'logrunner.conf' containing a list of filenames and types of the + * logfiles to scan; one file per line: + * TAB + * example: + * syslog /var/log/messages + * syslog /var/log/secure + * 3) run executable + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern String XML_Entities(String s); + +static const char* const usage = + "Usage: logrunner [] []\n\n" + " is the gnucomo data collection server\n" + "Options are:\n" + " -1: one-shot; stop after a single pass over one of the configured logfiles\n" + " -p : set IP port number to connect to\n" + " -c : specify alternative configuration file, default is \'logrunner.conf\'\n" + "If no hostname is specified, logrunner sends output to stdout\n"; + +struct fileinfo { + struct fileinfo* next; + char* name; /* strdupped name */ + char* type; /* strdupped logtype */ + int fd; + ino_t inode; + off_t position; +}; + +static const char* confname = "logrunner.conf"; +static const char* statusname = "logrunner.status"; +static const char* newstatusname = "logrunner.status.new"; + +static const char *hostname = NULL; +static int port = 2996; /* random magic number */ +static int out_stream = 1; + +static int oneshot = 0; + +static struct fileinfo* filelist = NULL; + +static int something_has_changed = 0; + +static volatile sig_atomic_t sig_seen = 0; + +static void sighandler(int sig) +{ + sig_seen = sig; +} + +static void set_signal_handler(void) +{ + /* These aren't all; but it's a nice set to start with */ + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGQUIT, sighandler); + signal(SIGABRT, sighandler); + signal(SIGPIPE, sighandler); + signal(SIGTERM, sighandler); +} + +void open_output() +{ + struct hostent* hostptr; + struct sockaddr_in addr; + unsigned int namelen = sizeof(addr); + + if ( hostname ) + { + hostptr = gethostbyname(hostname); + if ( !hostptr ) + { + fprintf(stderr, "logrunner: FATAL: cannot resolve %s\n", hostname); + exit(2); + } + out_stream = socket(PF_INET, SOCK_STREAM, 0); + if ( out_stream < 0 ) + { + fprintf(stderr, "logrunner: FATAL: Socket creation failed\n"); + exit(2); + } + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = *((long*)(hostptr->h_addr)); + addr.sin_port = htons(port); + if ( connect(out_stream, (struct sockaddr*) &addr, namelen) < 0 ) + { + fprintf(stderr, "logrunner: FATAL: connect to %s failed\n", hostname); + exit(2); + } + } + else + { + out_stream = 1; + } +} + +void xsend(const char* str) +{ + write(out_stream, str, strlen(str)); +} + +void xml_header(struct fileinfo *f) +{ + char buffer[256]; + *buffer = 0; + gethostname(buffer, sizeof(buffer)); + xsend("\n"); + xsend("\n"); + xsend("\n"); + xsend(buffer); + xsend("\n"); + xsend(f->type); + xsend("\n\n"); + xsend(""); +} + +void xml_footer(void) +{ + xsend("\n\n"); +} + +void output(const char* str) +{ + write(2, str, strlen(str)); +} + +void output_error(const char* str) +{ + char error[80]; + sprintf(error, " errno=%d\n", errno); + output(str); + output(error); +} + +void write_status_file(struct fileinfo* fl) +{ + FILE* dumpfile; + int localerror = 0; + dumpfile = fopen(newstatusname, "w"); + if ( !dumpfile ) + { + char error[80]; + sprintf(error, ", errno=%d\n", errno); + output("!!! dumpstatus: open failed: "); + output(newstatusname); + output(error); + something_has_changed = 0; + return; + } + while ( fl ) + { + if ( fprintf(dumpfile, "%s %li %lu\n", + fl->name, (long) fl->inode, + (unsigned long) fl->position) < 0 ) + { + output_error("!!! dumpstatus: write failed"); + localerror = 1; + break; + } + fl = fl->next; + } + if ( fclose(dumpfile) && localerror == 0 ) + { + output_error("!!! dumpstatus: close failed"); + localerror = 1; + } + if ( localerror == 0 ) + { + if ( rename(newstatusname, statusname) ) + { + output_error("!!! dumpstatus: rename failed"); + } + } + something_has_changed = 0; +} + +void read_status() +{ + FILE* statusfile; + char buffer[4096]; + char* xp; + long ino; + unsigned long pos; + struct fileinfo* fp; + + statusfile = fopen(statusname, "r"); + if ( statusfile == NULL ) + { + fprintf(stderr, "logrunner: can\'t open status file \'%s\': ", + statusname); + perror(""); + return; + } + while ( fgets(buffer, sizeof(buffer), statusfile ) ) + { + xp = strchr(buffer, ' '); + if ( xp ) + { + *xp = 0; + sscanf(xp+1, "%ld %lu", &ino, &pos); + fp = filelist; + while ( fp ) + { + if ( strcmp(buffer, fp->name) == 0 ) + { + fp->inode = ino; + fp->position = pos; + break; + } + fp = fp->next; + } + } + } + fclose(statusfile); +} + +struct fileinfo* new_info() +{ + struct fileinfo* rv; + rv = (struct fileinfo *)malloc(sizeof(struct fileinfo)); + if ( rv ) + { + rv->next = NULL; + rv->name = NULL; + rv->type = NULL; + rv->fd = -1; + rv->position = 0; + rv->inode = 0; + } + return rv; +} + +void read_config() +{ + /* The config file now is a simple list of type, filenames; + * it should be more user-friendly in the future! + */ + FILE* conffile; + char buffer[4096]; + + conffile = fopen(confname, "r"); + if ( !conffile ) + { + fprintf(stderr, + "logrunner: can\'t open configuration file \'%s\': ", + confname); + perror(""); + exit(2); + } + while ( fgets(buffer, sizeof(buffer), conffile) ) + { + int len = strlen(buffer); + char *fname; + if ( buffer[len-1] == '\n' ) + { + buffer[--len] = 0; + } + fname = strchr(buffer, '\t'); + if ( fname ) + { + struct fileinfo* fi; + fi = new_info(); + *(fname++) = 0; + if ( fi ) + { + fi->name = strdup(fname); + fi->type = strdup(buffer); + fi->next = filelist; + filelist = fi; + } + else + { + fprintf(stderr, "logrunner: out of memory\n"); + exit(2); + } + } + else if ( len > 0 ) + { + fprintf(stderr, "logrunner: WARNING: bad config line: %s\n", buffer); + } + } + fclose(conffile); +} + +void copy_data(struct fileinfo *f) +{ + char buffer[4096]; + int ndata; + + /* read data and dump to output */ + ndata = read(f->fd, buffer, sizeof(buffer)); + if ( ndata > 0 ) + { + xml_header(f); + while ( ndata > 0 ) + { + // Make a separate element from each line + + char *line, *nextline; + + line = buffer; + nextline = buffer; + + while (nextline < buffer + ndata) + { + while (*nextline != '\n' && nextline < buffer + ndata) + { + nextline++; + } + if (*nextline == '\n') + { + // Another line found - make the split. + *nextline++ = '\0'; + write(out_stream, "", 10); + + String logline(line); + logline = XML_Entities(logline); + write(out_stream, logline, ~logline); + write(out_stream, "\n", 12); + line = nextline; + } + } + if (line != nextline) + { + // There is still an incomplete line in the buffer. + memmove(buffer, line, nextline - line); + } + f->position += ndata - (nextline - line); + ndata -= line - buffer; + ndata += read(f->fd, buffer + (nextline - line), sizeof(buffer) - (nextline - line)); + } + xml_footer(); + something_has_changed = 1; + } + if ( ndata < 0 ) + { + char error[80]; + sprintf(error, ", errno=%d\n", errno); + output("!!! logfile: read failed: "); + output(f->name); + output(error); + } +} + +void do_file(struct fileinfo *f) +{ + struct stat statinfo; + char buffer[80]; + + /* inode check */ + if ( stat(f->name, &statinfo) ) + { + sprintf(buffer, ", errno=%d\n", errno); + output("!!! logfile: stat failed: "); + output(f->name); + output(buffer); + } + else + { + if ( statinfo.st_ino != f->inode ) + { + if ( f->fd >= 0 ) + { + copy_data(f); + close(f->fd); + f->fd = -1; + } + output("@@@ logfile: logrotate detected: "); + output(f->name); + output("\n"); + f->inode = statinfo.st_ino; + f->position = 0; + } + } + if ( f->fd < 0 ) + { + /* attempt to open the file */ + f->fd = open(f->name, O_RDONLY); + if ( f->fd < 0 ) + { + sprintf(buffer, ", errno=%d\n", errno); + output("!!! logfile: open failed: "); + output(f->name); + output(buffer); + return; + } + output("*** logfile: opened: "); + output(f->name); + sprintf(buffer, + "\n*** logfile: resumed read from position %ld\n", + (long) lseek(f->fd, f->position, SEEK_SET) ); + output(buffer); + } + + copy_data(f); +} + +void process_options(int argc, char* argv[]) +{ + const char* const options = "1c:p:"; + int opt; + + opt = getopt(argc, argv, options); + while ( opt != -1 ) + { + switch ( opt ) + { + case '1': + oneshot = 1; + break; + case 'c': + confname = strdup(optarg); + break; + case 'p': + port = atoi(optarg); + break; + default: + fputs(usage, stderr); + exit(2); + } + opt = getopt(argc, argv, options); + } + switch ( argc-optind ) + { + case 0: + break; + case 1: + hostname = argv[optind]; + break; + default: + fputs(usage, stderr); + exit(2); + } +} + +int main(int argc, char* argv[]) +{ + process_options(argc, argv); + open_output(); + + read_config(); + read_status(); + + set_signal_handler(); + + while ( sig_seen == 0 ) + { + struct fileinfo* fip; + fip = filelist; + while ( fip ) + { + do_file(fip); + if (something_has_changed && oneshot) + { + break; + } + fip = fip->next; + } + if ( something_has_changed ) + { + write_status_file(filelist); + } + if ( oneshot ) + { + return 0; + } + sleep(1); + } + + fprintf(stderr, "logrunner: stopped by signal %d\n", sig_seen); + /* shouldn't we close files and release memory here? */ + return 0; +} diff --git a/src/gcm_input/message.cpp b/src/gcm_input/message.cpp index 363aaa2..2c5d3f4 100644 --- a/src/gcm_input/message.cpp +++ b/src/gcm_input/message.cpp @@ -8,7 +8,7 @@ *********************** ** FILE NAME : message.cpp ** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring -** VERSION NUMBER : $Revision: 1.11 $ +** VERSION NUMBER : $Revision: 1.12 $ ** ** DESCRIPTION : Implementation of the message handling classes ** @@ -26,7 +26,17 @@ /***************************** $Log: message.cpp,v $ - Revision 1.11 2003-08-05 08:15:00 arjen + Revision 1.12 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.11 2003/08/05 08:15:00 arjen Debug output to the log stream instead of cerr. Fixed namespace problems in XPath searches of the DOM. Moved string utility functions to a separate file. @@ -70,13 +80,15 @@ *****************************/ -static const char *RCSID = "$Id: message.cpp,v 1.11 2003-08-05 08:15:00 arjen Exp $"; +static const char *RCSID = "$Id: message.cpp,v 1.12 2003-08-11 16:56:16 arjen Exp $"; #include #include #include #include "message.h" +//#define DEBUG + extern bool verbose; /* Defined in the main application */ extern bool testmode; extern bool incremental; @@ -155,7 +167,6 @@ static const regex re_accesslog("(GET|POST) .+ HTTP"); static const regex re_errorlog("^\\[" + unix_date_re + "\\] \\[(error|notice)\\] .+"); static const regex re_rpm("[[:alnum:]+-]+-[0-9][[:alnum:].-]"); -static const regex re_syslog_date("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}"); static const regex re_uxmail_from("^From [^ \t]+[ ]+" + unix_date_re); static const regex re_mail_From("^From:[[:blank:]]+"); static const regex re_mail_Date("^Date:[[:blank:]]+" + mail_date_re); @@ -221,6 +232,27 @@ int client_message::readXMLinput(String first_line) xmlDebugDumpNodeList(stdout, *res->nodesetval->nodeTab, 0); #endif item = *res->nodesetval->nodeTab; + + // Select a line cooker based on the message type. + +#ifdef DEBUG + std::cout << "Looking for a line cooker for " << item->content << "\n"; +#endif + list::iterator lci = kitchen.begin(); + pan = 0; + while (pan == 0 && lci != kitchen.end()) + { + pan = *lci; + if (pan->message_type() != (const char *)(item->content)) + { + pan = 0; + } + lci++; + } + if (pan == 0) + { + *log << "Can not find a line cooker for message type " << item->content << "\n"; + } } else { @@ -270,7 +302,7 @@ int client_message::readXMLinput(String first_line) ** VARS CHANGED : ** FUNCTIONS USED : ** SEE ALSO : -** LAST MODIFIED : Apr 28, 2003 +** LAST MODIFIED : Aug 11, 2003 **========================================================================= */ @@ -327,6 +359,8 @@ double client_message::classify(String host, UTC arriv, String serv) } + pan = 0; + /* * Now that we have the mail header out of the way, try to figure * out what the content of the message is. @@ -350,24 +384,6 @@ double client_message::classify(String host, UTC arriv, String serv) } readXMLinput(line); } - else if (line == re_syslog) - { - certainty = 1.0; - classification = SYSLOG; - if (verbose) - { - *log << "Syslog detected.\n"; - } - } - else if (line == re_syslog_irix) - { - certainty = 1.0; - classification = SYSLOG_IRIX; - if (verbose) - { - *log << "IRIX Syslog detected.\n"; - } - } else if (line == re_PGP) { certainty = 1.0; @@ -382,26 +398,6 @@ double client_message::classify(String host, UTC arriv, String serv) *log << "DUMP output detected.\n"; } } - else if (line == re_accesslog) - { - certainty = 1.0; - classification = ACCESSLOG; - service = "httpd"; - if (verbose) - { - *log << "HTTP access log detected.\n"; - } - } - else if (line == re_errorlog) - { - certainty = 1.0; - classification = ERRORLOG; - service = "httpd"; - if (verbose) - { - *log << "HTTP error log detected.\n"; - } - } else if (line == re_rpm) { certainty = 1.0; @@ -412,6 +408,31 @@ double client_message::classify(String host, UTC arriv, String serv) *log << "RPM package list detected.\n"; } } + else + { + // Scan the list of line cookers if there is anything familiar. + + list::iterator lci = kitchen.begin(); + pan = 0; + while (pan == 0 && lci != kitchen.end()) + { + pan = *lci; + if (!pan->check_pattern(line)) + { + pan = 0; + } + lci++; + } + if (pan != 0) + { + certainty = 1.0; + classification = COOKER_OBJECT; + if (verbose) + { + *log << "Detected message type " << pan->message_type() << "\n"; + } + } + } } input.rewind(); @@ -497,20 +518,43 @@ void client_message::enterXML() { if (node->type == XML_ELEMENT_NODE) { + xmlNodePtr item; + String log_hostname; + UTC log_date; + String raw("");; + String log_service; + if (strcmp((char *)node->name, "raw") == 0) { - *log << "Can not cook log elements yet.\n"; + item = node->children; + if (pan == 0) + { + *log << "Can not cook this type of log element.\n"; + } + else + { + raw = String((const char *)item->content); + if (pan->cook_this(raw, arrival)) + { + log_hostname = pan->hostname(); + if (log_hostname == "") + { + log_hostname = hostname; + } + log_service = pan->service(); + log_date = pan->timestamp(); + } + else + { + *log << "Log line " << raw << " does not match.\n"; + raw = ""; + } + } } else if (strcmp((char *)node->name, "cooked") == 0) { // Find the parts of the log entry - xmlNodePtr item; - String log_hostname; - UTC log_date; - String raw("");; - String log_service; - if (verbose) { *log << "Analyzing cooked element.\n"; @@ -566,35 +610,38 @@ void client_message::enterXML() *log << " missing from cooked log element.\n"; } - if (raw != "" && log_hostname != "" && log_date.proper()) - { - String insertion("insert into log (objectid, servicecode," - " object_timestamp, timestamp, rawdata, processed) values ("); + } - /* Insert a new record into the log table */ + // Insert a new log record into the database. + if (raw != "" && log_hostname != "" && log_date.proper()) + { + String insertion("insert into log (objectid, servicecode," + " object_timestamp, timestamp, rawdata, processed) values ("); - insertion += "'" + objectid + "',"; - insertion += "'" + log_service + "',"; - insertion += "'" + log_date.format("%Y-%m-%d %T") + "',"; - insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; - insertion += "'" + SQL_Escape(raw) + "',FALSE"; - insertion += ")"; + /* Insert a new record into the log table */ - if (testmode) - { - *log << insertion << "\n"; - } - else - { - database.Query(insertion); - } + insertion += "'" + objectid + "',"; + insertion += "'" + log_service + "',"; + insertion += "'" + log_date.format("%Y-%m-%d %T") + "',"; + insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; + insertion += "'" + SQL_Escape(raw) + "',FALSE"; + insertion += ")"; - if (verbose) - { - *log << "\n\n"; - } + if (testmode) + { + *log << insertion << "\n"; + } + else + { + database.Query(insertion); + } + + if (verbose) + { + *log << "\n\n"; } } + } node = node->next; } @@ -702,6 +749,7 @@ int client_message::enter() /* Scan the input line by line, entring records into the database */ String rest; // Rest of the line to be parsed + regex re_any(".*"); while (input >> line) { @@ -717,21 +765,12 @@ int client_message::enter() switch (classification) { - case SYSLOG: - check = &re_syslog; - break; - case SYSLOG_IRIX: - check = &re_syslog_irix; - break; - case ACCESSLOG: - check = &re_accesslog; - break; - case ERRORLOG: - check = &re_errorlog; - break; case RPMLIST: check = &re_rpm; break; + case COOKER_OBJECT: + check = &re_any; + break; } if (line == *check) @@ -746,116 +785,26 @@ int client_message::enter() switch (classification) { - case SYSLOG: - datestring = line(0,16); - log_date = datestring; - log_time = datestring; - if (log_date.Year() < 0 || log_date.Year() > 2500) - { - // The year is not in the log file. Assume the year of arrival, - // unless this puts the log entry at a later date than the arrival date. - // This happens e.g. when a log entry from December arrives in Januari. - - log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year()); - if (log_date > date(arrival)) - { - log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year() - 1); - } - } - - if (verbose) - { - *log << " Log timestamp = " << log_date << " " << log_time << "\n"; - } - rest = line << 16; - i = rest.index(' '); - if (rest(0,i) == hostname(0,i)) - { - rest <<= i + 1; - if (verbose) - { - *log << " Hostname matches.\n"; - *log << " rest = " << rest << "\n"; - } - for (i = 0; isalpha(rest[i]) && i < ~rest; i++); - if (verbose) - { - *log << " Service name = " << rest(0,i) << "\n"; - } - - /* Insert a new record into the log table */ - - insertion += "'" + objectid + "',"; - insertion += "'" + rest(0,i) + "',"; - insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',"; - insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; - insertion += "'" + SQL_Escape(line) + "',FALSE"; - insertion += ")"; - - if (testmode) - { - *log << insertion << "\n"; - } - else - { - database.Query(insertion); - } - - if (verbose) - { - *log << "\n\n"; - } - - nr_lines++; - } - else - { - *log << " Hostname " << rest(0,i) << " does not match.\n"; - } - break; - - case SYSLOG_IRIX: - datestring = line(0,16); - log_date = datestring; - log_time = datestring; - if (log_date.Year() < 0 || log_date.Year() > 2500) - { - // The year is not in the log file. Assume the year of arrival, - // unless this puts the log entry at a later date than the arrival date. - // This happens e.g. when a log entry from December arrives in Januari. - - log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year()); - if (log_date > date(arrival)) - { - log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year() - 1); - } - } + case COOKER_OBJECT: +#ifdef DEBUG + std::cerr << "\ncooker check: " << pan->check_pattern(line) << "\n"; +#endif + pan->cook_this(line, arrival); - if (verbose) - { - *log << " Log timestamp = " << log_date << " " << log_time << "\n"; - } - rest = line << 19; - i = rest.index(' '); - if (rest(0,i) == hostname(0,i)) + if (pan->hostname() == hostname(0,~pan->hostname())) { - rest <<= i + 1; - if (verbose) - { - *log << " Hostname matches.\n"; - *log << " rest = " << rest << "\n"; - } - for (i = 0; isalpha(rest[i]) && i < ~rest; i++); - if (verbose) - { - *log << " Service name = " << rest(0,i) << "\n"; - } +#ifdef DEBUG + std::cerr << " Information from cooker:\n"; + std::cerr << " timestamp = " << pan->timestamp() << "\n"; + std::cerr << " hostname = " << pan->hostname() << "\n"; + std::cerr << " service = " << pan->service() << "\n"; +#endif /* Insert a new record into the log table */ insertion += "'" + objectid + "',"; - insertion += "'" + rest(0,i) + "',"; - insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',"; + insertion += "'" + pan->service() + "',"; + insertion += "'" + pan->timestamp().format("%Y-%m-%d %T") + "',"; insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; insertion += "'" + SQL_Escape(line) + "',FALSE"; insertion += ")"; @@ -878,78 +827,10 @@ int client_message::enter() } else { - *log << " Hostname " << rest(0,i) << " does not match.\n"; - } - break; - - case ACCESSLOG: - datestring = line(regex("\\[.+\\]")); - datestring <<= 1; - datestring >>= 1; - datestring[datestring.index(':')] = ' '; - log_date = datestring; - log_time = datestring; - if (verbose) - { - *log << " Log timestamp = " << log_date << " " << log_time << "\n"; - } - insertion += "'" + objectid + "',"; - insertion += "'" + service + "',"; - insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',"; - insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; - insertion += "'" + SQL_Escape(line) + "',FALSE"; - insertion += ")"; - - if (testmode) - { - *log << insertion << "\n"; - } - else - { - database.Query(insertion); - } - - if (verbose) - { - *log << "\n\n"; + *log << " Hostname " << pan->hostname() << " does not match.\n"; } - - nr_lines++; break; - case ERRORLOG: - datestring = line(regex("\\[.+\\]")); - datestring <<= 1; - datestring >>= 1; - log_date = datestring; - log_time = datestring; - if (verbose) - { - *log << " Log timestamp = " << log_date << " " << log_time << "\n"; - } - insertion += "'" + objectid + "',"; - insertion += "'" + service + "',"; - insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',"; - insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; - insertion += "'" + SQL_Escape(line) + "',FALSE"; - insertion += ")"; - - if (testmode) - { - *log << insertion << "\n"; - } - else - { - database.Query(insertion); - } - - if (verbose) - { - *log << "\n\n"; - } - - nr_lines++; - break; case RPMLIST: // Scan a list of packages and versions from "rpm -a". diff --git a/src/gcm_input/message.h b/src/gcm_input/message.h index 34c8eb8..eb32449 100644 --- a/src/gcm_input/message.h +++ b/src/gcm_input/message.h @@ -8,7 +8,7 @@ *********************** ** FILE NAME : message.h ** SYSTEM NAME : -** VERSION NUMBER : $Revision: 1.6 $ +** VERSION NUMBER : $Revision: 1.7 $ ** ** DESCRIPTION : Classes to for handling client messages ** @@ -20,13 +20,23 @@ ******************************** ** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl ** CREATION DATE : Sep 16, 2002 -** LAST UPDATE : Apr 28, 2003 +** LAST UPDATE : Aug 06, 2003 ** MODIFICATIONS : **************************************************************************/ /***************************** $Log: message.h,v $ - Revision 1.6 2003-04-29 09:16:44 arjen + Revision 1.7 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.6 2003/04/29 09:16:44 arjen Read XML input, Only cooked log entries for now. @@ -51,7 +61,7 @@ *****************************/ -/* static const char *RCSID = "$Id: message.h,v 1.6 2003-04-29 09:16:44 arjen Exp $"; */ +/* static const char *RCSID = "$Id: message.h,v 1.7 2003-08-11 16:56:16 arjen Exp $"; */ #include #include @@ -60,6 +70,7 @@ #include +#include "line_cooker.h" #include "database.h" /* @@ -141,7 +152,7 @@ public: // // RELATIONS : // SEE ALSO : -// LAST MODIFIED : Apr 28, 2003 +// LAST MODIFIED : Aug 06, 2003 /////////////////////////////////////////////////////////////////////////// */ @@ -151,6 +162,9 @@ class client_message UTC arrival; // When we got the message. String service; // Service that created the message + std::list kitchen; // The collection of line cookers + line_cooker * pan; // The one we cook this log with + bool mail_header; // Does the message contain a mail header ? bool gpg_encrypted; // Is the message encrypted ? @@ -159,8 +173,7 @@ class client_message double certainty; // How certain are we about the message enum { - UNKNOWN, SYSLOG, SYSLOG_IRIX, ACCESSLOG, ERRORLOG, RPMLIST, - XML + UNKNOWN, RPMLIST, XML, COOKER_OBJECT } classification; @@ -174,6 +187,11 @@ public: client_message(std::istream *in, gnucomo_database db); + void add_cooker(line_cooker *lc) + { + kitchen.push_back(lc); + } + double classify(String host, UTC arrival = Now(), String serv = ""); int enter(); }; diff --git a/src/gcm_input/syslog_cooker.cpp b/src/gcm_input/syslog_cooker.cpp new file mode 100644 index 0000000..30ed2d0 --- /dev/null +++ b/src/gcm_input/syslog_cooker.cpp @@ -0,0 +1,100 @@ + +/************************************************************************** +** (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 : syslog_cooker.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks system log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 06, 2003 +** LAST UPDATE : Aug 06, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: syslog_cooker.cpp,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: syslog_cooker.cpp,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include + +#include "syslog_cooker.h" + +static const String syslog_date_re("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}"); +static const regex re_syslog(syslog_date_re + " [[:alnum:]]+ [[:alpha:]]+.*:.+"); + +bool syslog_cooker::check_pattern(String logline) +{ + return logline == re_syslog; +} + +bool syslog_cooker::cook_this(String logline, UTC arrival) +{ + if (check_pattern(logline)) + { + String datestring = logline(0,16); + date log_date = datestring; + hour log_time = datestring; + String rest; // Rest of the line to be parsed + int i; + + if (log_date.Year() < 0 || log_date.Year() > 2500) + { + // The year is not in the log file. Assume the year of arrival, + // unless this puts the log entry at a later date than the arrival date. + // This happens e.g. when a log entry from December arrives in Januari. + + log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year()); + if (log_date > date(arrival)) + { + log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year() - 1); + } + } + + ts = UTC(log_date, log_time); + + // Extract the hostname + + rest = logline << 16; + i = rest.index(' '); + hn = rest(0,i); + + // Extract the service + + rest <<= i + 1; + for (i = 0; isalpha(rest[i]) && i < ~rest; i++); + srv = rest(0, i); + + return true; + } + else + { + return false; + } +} + + diff --git a/src/gcm_input/syslog_cooker.h b/src/gcm_input/syslog_cooker.h new file mode 100644 index 0000000..c108f6e --- /dev/null +++ b/src/gcm_input/syslog_cooker.h @@ -0,0 +1,81 @@ + +/************************************************************************** +** (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 : syslog_cooker.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Cooks system log lines +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 06, 2003 +** LAST UPDATE : Aug 06, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: syslog_cooker.h,v $ + Revision 1.1 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. + +*****************************/ + +/* static const char *RCSID = "$Id: syslog_cooker.h,v 1.1 2003-08-11 16:56:16 arjen Exp $"; */ + +#include "line_cooker.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : syslog_cooker +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Aug 06, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class syslog_cooker : public line_cooker +{ + +protected: + + +public: + + syslog_cooker() + { + } + + bool check_pattern(String logline); + bool cook_this(String logline, UTC arrival); + + String message_type() + { + return "system log"; + } + +}; -- 2.11.0