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