monit-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Preliminary log matching support


From: Martin Pala
Subject: Re: Preliminary log matching support
Date: Mon, 01 Aug 2005 23:41:28 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050513 Debian/1.7.8-1

It looks cool and is very useful :)


I tried just basic test, i have only few notes:

1.) it could be useful to describe in the event message which regular expression actualy matched. Currently the event just describes which service matched:

  --8<--
  'syslog' content line matches regular expression
  --8<--

however in the case that more then one expressions is defined it is needed to know which rule matched or what exactly the file contains. For example:
  --8<--
  check file syslog with path /var/log/syslog
     if match "FATAL" then alert
     if match "fail" then alert
  --8<--

The matching line can contain important informations too (such as which disk drive failed, etc.) so maybe it could be useful to include the whole matching line to the event message?


2.) Cosmetic - the label in the html output for service rule listing (print_service_rules_match) is 'Associated size' - should be 'Associated regex' or something similar.

3.) Another cosmetic - the plaintext output of service configuration in Util_printService should display regex rule too


I'm +1 to add the patch :)

Martin



Christian Hopp wrote:
Hi!

Good news everyone...

I have made a first version for "logfile matching".  It lacks
documentation and some verbose logging issues.  But it could be used
for testing.

Usage:

check file foobar.log with path /tmp/foobar.log
        if match "foo.*bar" then alert

You need regex support in order to use this (without regex it makes no
sense to me).  The initial read point is the file end. Upon inode
change or filesize reduction the read counter is reseted to zero.  In
case a file changes (increases) and is moved, the rest of the old one
is gone and is not matched!  Only lines with "\n" or lines with the
length of STRLEN are matched.

Please have a look at it and give me some feedback for further changes
or wishes.  As always the patch needs to applied agains todays CVS.

Bye,

Christian


------------------------------------------------------------------------

diff -ru --exclude CVS monit.orig/event.c monit/event.c
--- monit.orig/event.c  2005-01-06 21:51:49.000000000 +0100
+++ monit/event.c       2005-07-29 12:25:27.000000000 +0200
@@ -59,6 +59,7 @@
   {EVENT_PERMISSION, "Permission failed",      "Permission passed"},
   {EVENT_RESOURCE,   "Resource limit matched", "Resource limit passed"},
   {EVENT_SIZE,       "Size failed",            "Size passed"},
+  {EVENT_MATCH,      "Regex match",            "No regex match"},
   {EVENT_TIMEOUT,    "Timeout",                "Timeout recovery"},
   {EVENT_TIMESTAMP,  "Timestamp failed",       "Timestamp passed"},
   {EVENT_UID,        "UID failed",             "UID passed"},
diff -ru --exclude CVS monit.orig/event.h monit/event.h
--- monit.orig/event.h  2005-01-06 21:51:49.000000000 +0100
+++ monit/event.h       2005-07-29 12:24:29.000000000 +0200
@@ -38,6 +38,7 @@
 #define EVENT_EXEC         0x1000
 #define EVENT_CHANGED      0x2000
 #define EVENT_ICMP         0x4000
+#define EVENT_MATCH        0x8000
#define EVENT_DESCRIPTION(E) Event_get_description(E)
 #define IS_EVENT_SET(value, mask) ((value & mask) != 0)
diff -ru --exclude CVS monit.orig/gc.c monit/gc.c
--- monit.orig/gc.c     2005-01-24 02:04:36.000000000 +0100
+++ monit/gc.c  2005-07-29 13:25:34.000000000 +0200
@@ -50,6 +50,7 @@
 static void _gc_inf(Info_T *);
 static void _gcpdl(Dependant_T *);
 static void _gcso(Size_T *);
+static void _gcmatch(Match_T *);
 static void _gcchecksum(Checksum_T *);
 static void _gcperm(Perm_T *);
 static void _gcuid(Uid_T *);
@@ -173,6 +174,9 @@
   if((*s)->sizelist)
     _gcso(&(*s)->sizelist);
+ if((*s)->matchlist)
+    _gcmatch(&(*s)->matchlist);
+
   if((*s)->checksum)
     _gcchecksum(&(*s)->checksum);
@@ -435,6 +439,22 @@ } +static void _gcmatch(Match_T *s) { + + ASSERT(s);
+
+  if((*s)->next)
+    _gcmatch(&(*s)->next);
+
+  if((*s)->action)
+    _gc_eventaction(&(*s)->action);
+
+  FREE((*s)->regex_string);
+  FREE((*s)->regex_comp);
+  FREE(*s);
+
+}
+
static void _gcchecksum(Checksum_T *s) { diff -ru --exclude CVS monit.orig/http/cervlet.c monit/http/cervlet.c
--- monit.orig/http/cervlet.c   2005-04-05 21:52:57.000000000 +0200
+++ monit/http/cervlet.c        2005-07-29 13:36:12.000000000 +0200
@@ -111,6 +111,7 @@
 static void print_service_rules_timestamp(HttpResponse, Service_T);
 static void print_service_rules_device(HttpResponse, Service_T);
 static void print_service_rules_size(HttpResponse, Service_T);
+static void print_service_rules_match(HttpResponse, Service_T);
 static void print_service_rules_checksum(HttpResponse, Service_T);
 static void print_service_rules_process(HttpResponse, Service_T);
 static void print_service_params_port(HttpResponse, Service_T);
@@ -121,6 +122,7 @@
 static void print_service_params_timestamp(HttpResponse, Service_T);
 static void print_service_params_device(HttpResponse, Service_T);
 static void print_service_params_size(HttpResponse, Service_T);
+static void print_service_params_match(HttpResponse, Service_T);
 static void print_service_params_checksum(HttpResponse, Service_T);
 static void print_service_params_process(HttpResponse, Service_T);
 static void print_status(HttpRequest, HttpResponse);
@@ -774,6 +776,7 @@
     print_service_params_timestamp(res, s);
     print_service_params_device(res, s);
     print_service_params_size(res, s);
+    print_service_params_match(res, s);
     print_service_params_checksum(res, s);
     print_service_params_process(res, s);
@@ -786,6 +789,7 @@
     print_service_rules_timestamp(res, s);
     print_service_rules_device(res, s);
     print_service_rules_size(res, s);
+    print_service_rules_match(res, s);
     print_service_rules_checksum(res, s);
     print_service_rules_process(res, s);
@@ -1305,6 +1309,8 @@
          out_print(res, "Resource ");
       if(IS_EVENT_SET(r->events, EVENT_SIZE))
          out_print(res, "Size ");
+      if(IS_EVENT_SET(r->events, EVENT_MATCH))
+         out_print(res, "Match ");
       if(IS_EVENT_SET(r->events, EVENT_TIMEOUT))
          out_print(res, "Timeout ");
       if(IS_EVENT_SET(r->events, EVENT_TIMESTAMP))
@@ -1570,6 +1576,27 @@
   }
 }
+static void print_service_rules_match(HttpResponse res, Service_T s) {
+
+  if(s->matchlist) {
+
+    Match_T       ml;
+    EventAction_T a;
+
+    for(ml= s->matchlist; ml; ml= ml->next) {
+
+      a= ml->action;
+
+
+      out_print(res,
+        "<tr><td>Associated size</td><td>If match \"%s\" then %s</td></tr>",
+        ml->regex_string,
+        actionnames[a->failed->id]);
+
+    }
+  }
+}
+
static void print_service_rules_checksum(HttpResponse res, Service_T s) { @@ -1963,6 +1990,25 @@
   }
 }
+static void print_service_params_match(HttpResponse res, Service_T s) {
+
+  if(s->type == TYPE_FILE) {
+
+    if(!Util_hasServiceStatus(s)) {
+
+      out_print(res,
+        "<tr><td>Match regex</td><td>-</font></td></tr>");
+
+    } else {
+
+      out_print(res,
+        "<tr><td>Match regex</td><td><font%s>%s</td></tr>",
+        (s->error & EVENT_MATCH)?" color='#ff0000'":"",
+        (s->error & EVENT_MATCH)?"yes":"no");
+    }
+  }
+}
+
static void print_service_params_checksum(HttpResponse res, Service_T s) { diff -ru --exclude CVS monit.orig/l.l monit/l.l
--- monit.orig/l.l      2005-04-03 13:56:51.000000000 +0200
+++ monit/l.l   2005-07-29 11:57:24.000000000 +0200
@@ -234,6 +234,7 @@
 perm(ission)?     { return PERMISSION; }
 exec(ute)?        { return EXEC; }
 size              { return SIZE; }
+match             { return MATCH; }
 connection        { return CONNECTION; }
 unmonitor         { return UNMONITOR; }
 icmp              { return ICMP; }
diff -ru --exclude CVS monit.orig/monit.pod monit/monit.pod
--- monit.orig/monit.pod        2005-04-05 21:52:57.000000000 +0200
+++ monit/monit.pod     2005-07-29 17:15:13.000000000 +0200
@@ -1237,6 +1237,13 @@
  check file su with path /bin/su
        if size != 95564 then exec "/sbin/ifconfig eth0 down"
+=over 4
+
+=item IF MATCH regex THEN action
+
+=back
+
+... blah ...
=head2 SPACE TESTING
diff -ru --exclude CVS monit.orig/monitor.h monit/monitor.h
--- monit.orig/monitor.h        2005-04-23 02:48:40.000000000 +0200
+++ monit/monitor.h     2005-07-29 14:13:22.000000000 +0200
@@ -553,6 +553,18 @@
   EventAction_T action;  /**< Description of the action upon event occurence */
 } *Perm_T;
+/** Defines match object */
+typedef struct mymatch {
+  char    *regex_string;                                   /**< Match string */
+#ifdef HAVE_REGEX_H
+  regex_t *regex_comp;                                    /**< Match compile */
+#endif
+  EventAction_T action;  /**< Description of the action upon event occurence */
+ + /** For internal use */
+  struct mymatch *next;                             /**< next match in chain */
+} *Match_T;
+
/** Defines uid object */
 typedef struct myuid {
@@ -588,6 +600,7 @@
   mode_t  st_mode;                                           /**< Permission */
   uid_t   st_uid;                                           /**< Owner's uid */
   gid_t   st_gid;                                           /**< Owner's gid */
+  ino_t   st_ino;                                                 /**< Inode */
   time_t  timestamp;                                          /**< Timestamp */
/* Device specific */
@@ -605,6 +618,8 @@
/* File specific */
   size_t st_size;                                                  /**< Size */
+  size_t readpos;                           /**< Position for regex matching */
+  ino_t  st_ino_prev;                 /**< Previous inode for regex matching */
   char  *cs_sum;                                               /**< Checksum */
/* Process specific */
@@ -621,7 +636,6 @@
   int    cpu_percent;                                    /**< pecentage * 10 */
   int    total_cpu_percent;                              /**< pecentage * 10 */
   time_t uptime;                                         /**< Process uptime */
-
 } *Info_T;
@@ -660,6 +674,7 @@
   Port_T      portlist; /**< Portnumbers to check, either local or at a host */
   Resource_T  resourcelist;                          /**< Resouce check list */
   Size_T      sizelist;                                 /**< Size check list */
+  Match_T     matchlist;                             /**< Content Match list */
   Timestamp_T timestamplist;                       /**< Timestamp check list */
   Uid_T       uid;                                            /**< Uid check */
diff -ru --exclude CVS monit.orig/monitrc monit/monitrc
--- monit.orig/monitrc  2005-04-01 10:07:33.000000000 +0200
+++ monit/monitrc       2005-07-29 17:28:55.000000000 +0200
@@ -121,6 +121,8 @@
# # size -- Must be followed by compare operator, number, optional # a size unit and an action. +# +# match -- Must be followed by a regular expression and an action. # # every -- Only check the service at every n cycles.
 #
diff -ru --exclude CVS monit.orig/p.y monit/p.y
--- monit.orig/p.y      2005-04-03 13:56:51.000000000 +0200
+++ monit/p.y   2005-07-29 13:27:00.000000000 +0200
@@ -150,6 +150,7 @@
   static struct myuid uidset;
   static struct myperm permset;
   static struct mysize sizeset;
+  static struct mymatch matchset;
   static struct myicmp icmpset;
   static struct mymail mailset;
   static struct myport portset;
@@ -188,6 +189,7 @@
   static gid_t get_gid(char *, gid_t);
   static void  addchecksum(Checksum_T);
   static void  addperm(Perm_T);
+  static void  addmatch(Match_T);
   static void  adduid(Uid_T);
   static void  addgid(Gid_T);
   static void  addeuid(uid_t);
@@ -257,7 +259,7 @@
 %token TIMESTAMP CHANGED SECOND MINUTE HOUR DAY
 %token SSLAUTO SSLV2 SSLV3 TLSV1 CERTMD5
 %token BYTE KILOBYTE MEGABYTE GIGABYTE
-%token INODE SPACE PERMISSION SIZE
+%token INODE SPACE PERMISSION SIZE MATCH
 %token EXEC UNMONITOR ICMP ICMPECHO NONEXIST INVALID DATA RECOVERED
 %token URL CONTENT PID PPID
 %token <url> URLOBJECT
@@ -325,6 +327,7 @@
                | gid
                | checksum
                 | size
+                | match
                | mode
                | group
                 | depend
@@ -970,6 +973,7 @@
                 | PERMISSION { eventset |= EVENT_PERMISSION; }
                 | RESOURCE   { eventset |= EVENT_RESOURCE; }
                 | SIZE       { eventset |= EVENT_SIZE; }
+                | MATCH      { eventset |= EVENT_MATCH; }
                 | TIMEOUT    { eventset |= EVENT_TIMEOUT; }
                 | TIMESTAMP  { eventset |= EVENT_TIMESTAMP; }
                 | UID        { eventset |= EVENT_UID; }
@@ -1249,8 +1253,15 @@
                  }
                 ;
+match : IF MATCH STRING THEN action1 recovery {
+                    matchset.regex_string= xstrdup($3);
+                    addeventaction(&(matchset).action, $<number>5, $<number>6);
+                    addmatch(&matchset);
+                 }
+                ;
+
 size            : IF SIZE operator NUMBER unit THEN action1 recovery {
-                   sizeset.operator= $<number>3;
+                   sizeset.operator= $<number>4;
                    sizeset.size= ((unsigned long)$4 * $<number>5);
                     addeventaction(&(sizeset).action, $<number>7, $<number>8);
                    addsize(&sizeset, FALSE);
@@ -1897,6 +1908,37 @@
} +/*
+ * Set Perm object in the current service
+ */
+static void addmatch(Match_T ms) {
+
+  Match_T m;
+  int     reg_return;
+ + ASSERT(ms);
+
+#ifdef HAVE_REGEX_H
+  NEW(m);
+  NEW(m->regex_comp);
+
+  m->regex_string= ms->regex_string;
+  m->action= ms->action;
+  reg_return= regcomp(m->regex_comp, ms->regex_string, REG_NOSUB|REG_EXTENDED);
+
+  if (reg_return!=0) {
+    char errbuf[STRLEN];
+    regerror(reg_return, ms->regex_comp, errbuf, STRLEN);
+    yyerror2("regex parsing error:%s", errbuf);
+  }
+
+  m->next= current->matchlist;
+  current->matchlist= m;
+#else
+  yyerror2("regex matching requires regex support!", );
+#endif
+}
+
/*
  * Set Uid object in the current service
diff -ru --exclude CVS monit.orig/util.c monit/util.c
--- monit.orig/util.c   2005-04-12 00:27:53.000000000 +0200
+++ monit/util.c        2005-07-29 15:45:42.000000000 +0200
@@ -1529,10 +1529,12 @@
  */
 void Util_resetInfo(Service_T s) {
   memset(s->inf, 0, sizeof *(s->inf));
-  s->inf->_pid=  -1;
-  s->inf->_ppid= -1;
-  s->inf->pid=   -1;
-  s->inf->ppid=  -1;
+  s->inf->_pid=        -1;
+  s->inf->_ppid=       -1;
+  s->inf->pid=         -1;
+  s->inf->ppid=        -1;
+  s->inf->st_ino_prev=  0;
+  s->inf->readpos=      0;
 }
diff -ru --exclude CVS monit.orig/validate.c monit/validate.c
--- monit.orig/validate.c       2005-05-11 23:28:02.000000000 +0200
+++ monit/validate.c    2005-08-01 14:32:47.000000000 +0200
@@ -102,6 +102,7 @@
 static void check_gid(Service_T);
 static void check_size(Service_T);
 static void check_perm(Service_T);
+static void check_match(Service_T);
 static int  check_skip(Service_T);
 static int  check_timeout(Service_T);
 static void check_checksum(Service_T);
@@ -282,6 +283,13 @@
     return FALSE;
   } else {
     s->inf->st_mode= stat_buf.st_mode;
+    if (s->inf->st_ino==0) {
+      s->inf->st_ino_prev= stat_buf.st_ino;
+      s->inf->readpos= stat_buf.st_size;
+    } else {
+      s->inf->st_ino_prev= s->inf->st_ino;
+    }
+    s->inf->st_ino= stat_buf.st_ino;
     s->inf->st_uid= stat_buf.st_uid;
     s->inf->st_gid= stat_buf.st_gid;
     s->inf->st_size= stat_buf.st_size;
@@ -319,6 +327,9 @@
   if(s->timestamplist)
     check_timestamp(s);
+ if(s->matchlist)
+    check_match(s);
+
   return TRUE;
}
@@ -950,6 +961,95 @@
   }
 }
+/**
+ * Match content
+ */
+static void check_match(Service_T s) {
+  Match_T ml;
+  char    line[STRLEN];
+  FILE    *file;
+  int     regex_return;
+  int     inode_checked=FALSE;
+ + ASSERT(s && s->matchlist);
+
+  while (TRUE) {
+    /* did inode change -> read position = 0 */
+    if((inode_checked==FALSE) && (s->inf->st_ino != s->inf->st_ino_prev)) {
+      s->inf->readpos= 0;
+    }
+    inode_checked= TRUE;
+ + /* did file decrease (readpos > file_size) -> read position = 0 */
+    if(s->inf->readpos > s->inf->st_size) {
+      s->inf->readpos= 0;
+    }
+
+    /* Do we need to match? (readpos < file_size) */
+    if(!(s->inf->readpos < s->inf->st_size)){
+      break;
+    }
+
+    /* Open the file */
+    if(NULL==(file=fopen(s->path, "r"))) {
+      /* We can't open the file */
+      /* ==> ERROR */
+      break;
+    }
+ + /* Seek to the read position */
+    if (fseek(file, s->inf->readpos, SEEK_SET)!=0) {
+      /* We can not seek to the read position */
+      /* ==> ERROR */
+      fclose(file);
+      break;
+    }
+
+    if(NULL==fgets(line, STRLEN-1, file)) {
+      /* We can not read the content! */
+      /* ==> ERROR */
+      fclose(file);
+      break;
+    }
+ + /* Close the file */
+    fclose(file);
+ + /* Empty line? Should not happen... but who knows */
+    if (strlen(line) == 0) {
+      /* ==> ERROR */
+      break;
+    }
+
+    /* Complete line oder just beginning? (igore full buffers) */
+    if ((strlen(line)<(STRLEN-1)) && (line[strlen(line)-1] != '\n')) {
+      /* we gonna read it next time */
+      break;
+    }
+ + for(ml= s->matchlist; ml; ml= ml->next) {
+      regex_return=regexec(ml->regex_comp,
+                          line,
+                          0,
+                          NULL,
+                          0);
+
+      if(regex_return==0) {
+        /* We match! */
+        Event_post(s, EVENT_MATCH, TRUE, ml->action,
+                   "'%s' content line matches regular expression",
+                   s->name);
+
+        /* ==> more talkative! */
+      } else {
+        DEBUG("FILE: Regular expression does not match on content line\n");
+      }
+    }
+
+    /* Set read position to the end of last read */
+    s->inf->readpos+=strlen(line);
+  }
+}
/**
  * Device test


------------------------------------------------------------------------

_______________________________________________
monit-dev mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/monit-dev




reply via email to

[Prev in Thread] Current Thread [Next in Thread]