monit-general
[Top][All Lists]
Advanced

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

Re: Apache, rotatelogs & chroot environment


From: David Fletcher
Subject: Re: Apache, rotatelogs & chroot environment
Date: Tue, 7 Dec 2004 23:55:06 +0000

Hi all,

Here is a revised patch to implement the mod_status Apache 
server monitoring using its own protocol file called APACHE, 
as was suggested previously. 

Also, as suggested, I have added configuration, so that the 
trigger level for action can be set in the monitrc file. This
limit could be passed using the existing "request" parameter, 
but that could be confusing since in this case it is not a URL.
I have therefore added a new parameter called "limit". 

If adding "limit" is not a good idea, I am happy with using the
"request" paramter - let me know what you think. It is easy to 
change the patch, or remove remove parts from the it!

The syntax of /etc/monitrc becomes:

if failed host www.example.com port 80
   protocol APACHE limit 60 then restart

where the "limit" is the percentage of active servers which are 
locked in the logging state. Adding other status codes used by 
mod_status would be easy, for example to consider Apache
child processes which have locked becuase of a DNS look-up failure.

I have tested this on my server and it seems to work ok. The patch 
includes some documentation.

Best wishes,

David.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff -Naur monit-4.4/doc/monit.html monit-4.4-patched/doc/monit.html
--- monit-4.4/doc/monit.html    2004-09-23 20:00:25.000000000 +0100
+++ monit-4.4-patched/doc/monit.html    2004-12-07 23:10:40.000000000 +0000
@@ -1349,6 +1349,15 @@
 <p>As you can see, you may specify a request after the protocol, at
 the moment only the HTTP protocol supports the request option.
 See also below for an example.</p>
+<p>In addition to the standard protocols, the <em>APACHE</em> protocol 
+is a test of a specific server product, rather than a generic protocol. 
+Server performance is examined using the status page generated by Apache's 
+mod_status, which is expected to be at its default addesss of 
+http://www.example.com/server-status. Currently the <em>APACHE</em> protocol 
+examines the percentage of Apache child processes writing to the server logs, 
and 
+will take action if the percentage exceeds the LIMIT value which is set as 
shown 
+below. A limit of 50% is assumed if none is specified.</p>
+<pre>[PROTO(COL) APACHE [LIMIT {percentage limit}]</pre>
 <p><strong>send/expect: {SEND|EXPECT} ``string'' ...</strong>.  If monit does 
not
 support the protocol spoken by the server, you can write your own
 protocol-test using <em>send</em> and <em>expect</em> strings. The 
<em>SEND</em>
@@ -2329,6 +2338,15 @@
           send &quot;GET / HTTP/1.0\r\nHost: www.sol.no\r\n\r\n&quot;
           expect &quot;HTTP/[0-9\.]{3} 200 .*\r\n&quot;
           then alert</pre>
+<p>To make sure that Apache is logging successfully (i.e. no more 
+than 60% of child servers are logging), use its mod_status 
+page at www.sol.no/server-status with this special protocol test:</p>
+<pre>
+ check process apache with pidfile /var/run/httpd.pid
+       start &quot;/etc/init.d/httpd start&quot;
+       stop  &quot;/etc/init.d/httpd stop&quot;
+       if failed host www.sol.no port 80
+       protocol APACHE limit 60 then restart</pre>
 <p>Here we use an icmp ping test to check if a remote host is up and
 if not send an alert:</p>
 <pre>
diff -Naur monit-4.4/l.l monit-4.4-patched/l.l
--- monit-4.4/l.l       2004-05-06 00:06:51.000000000 +0100
+++ monit-4.4-patched/l.l       2004-12-07 17:13:00.000000000 +0000
@@ -174,6 +174,7 @@
 host              { return HOST; }
 default           { return DEFAULT; }
 http              { return HTTP; }
+apache            { return APACHE; }
 ftp               { return FTP; }
 smtp              { return SMTP; }
 pop               { return POP; }
@@ -193,6 +194,7 @@
 uid               { return UID; }
 gid               { return GID; }
 request           { return REQUEST; }
+limit             { return LIMIT; }
 cpuusage          { return CPUUSAGE; }
 memusage          { return MEMUSAGE; }
 memkbyte          { return MEMKBYTE; }
diff -Naur monit-4.4/monitor.h monit-4.4-patched/monitor.h
--- monit-4.4/monitor.h 2004-09-10 20:13:58.000000000 +0100
+++ monit-4.4-patched/monitor.h 2004-12-07 17:13:00.000000000 +0000
@@ -381,6 +381,7 @@
   char *request;                              /**< Specific protocol request */
   char *request_checksum;     /**< The optional checksum for a req. document */
   int  request_hashtype;  /**< The optional type of hash for a req. document */
+  int  limit;         /**< Apache protocol. Max percentatge locked processes */
   char *pathname;                   /**< Pathname, in case of an UNIX socket */
   char *address;               /**< Human readable destination of the socket */
   Generic_T generic;                                /**< Generic test handle */
diff -Naur monit-4.4/monitrc monit-4.4-patched/monitrc
--- monit-4.4/monitrc   2004-07-15 20:08:09.000000000 +0100
+++ monit-4.4-patched/monitrc   2004-12-07 21:05:00.000000000 +0000
@@ -89,6 +89,10 @@
 #                     document or entity to fetch from the server. Currently 
 #                     only the HTTP protocol module supports the request 
 #                     statement, such as: "/data/show.php?a=b&c=d"
+#   limit          -- Currently only supported by the APACHE protocol. Must 
+#                     be followed by a number specifying the maximum 
+#                     percentage of Apache child processes allowed to be 
+#                     logging before action is taken. 
 #   send/expect    -- These keywords specify a generic protocol.  Both require
 #                     a string whether to be sent or to be matched against (as 
 #                     extended regex if supported). 
@@ -277,6 +281,8 @@
 #       and request "/monit/next.html" then restart
 #    if failed port 443 type tcpssl proto http with timeout 15 seconds
 #       then restart
+#    if failed host www.tildeslash.com port 80
+#        protocol APACHE limit 50 then restart 
 #    if cpu is greater than 60% for 2 cycles then alert
 #    if cpu > 80% for 5 cycles then restart
 #    if totalmem > 200.0 MB for 5 cycles then restart
diff -Naur monit-4.4/p.y monit-4.4-patched/p.y
--- monit-4.4/p.y       2004-09-17 19:59:44.000000000 +0100
+++ monit-4.4-patched/p.y       2004-12-07 17:22:00.000000000 +0000
@@ -129,6 +129,7 @@
     char *pathname;
     char *request;
     char *request_checksum;
+    int  limit;
     Generic_T generic;
     Protocol_T protocol;
     EventAction_T action;
@@ -224,7 +225,7 @@
   static Service_T depend_list= NULL;
   static struct IHavePrecedence ihp= {FALSE, FALSE, FALSE};
   static struct PortSet portset= {-1, 0, SOCK_STREAM, AF_INET, FALSE,
-    SSL_VERSION_AUTO, NET_TIMEOUT, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    SSL_VERSION_AUTO, NET_TIMEOUT, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL,
     NULL};
   static struct ResourceSet resourceset= {0, 0, OPERATOR_EQUAL, 1, NULL};
   static struct TimestampSet timestampset= {OPERATOR_EQUAL, 0, FALSE, TRUE, 
NULL};
@@ -309,10 +310,10 @@
 %token HOST PORT TYPE UDP TCP TCPSSL PROTOCOL CONNECTION
 %token ALERT MAILFORMAT UNIXSOCKET SIGNATURE
 %token TIMEOUT RESTART CHECKSUM EXPECT EVERY 
-%token DEFAULT HTTP FTP SMTP POP IMAP NNTP SSH DWP LDAP2 LDAP3 RDATE RSYNC
+%token DEFAULT HTTP APACHE FTP SMTP POP IMAP NNTP SSH DWP LDAP2 LDAP3 RDATE 
RSYNC
 %token <string> STRING PATH MAILADDR MAILFROM MAILSUBJECT
 %token <string> MAILBODY SERVICENAME
-%token <number> NUMBER PERCENT
+%token <number> NUMBER PERCENT LIMIT
 %token <real> REAL
 %token CHECKPROC CHECKDEV CHECKFILE CHECKDIR CHECKHOST
 %token CPUUSAGE MEMUSAGE MEMKBYTE CHILDREN 
@@ -780,6 +781,7 @@
 protocol        : /* EMPTY */  { portset.protocol= addprotocol(P_DEFAULT);}
                 | PROTOCOL DEFAULT { portset.protocol= addprotocol(P_DEFAULT); 
}
                 | PROTOCOL HTTP request {portset.protocol= 
addprotocol(P_HTTP);}
+                | PROTOCOL APACHE limit {portset.protocol= 
addprotocol(P_APACHE);}
                 | PROTOCOL FTP { portset.protocol= addprotocol(P_FTP); }
                 | PROTOCOL SMTP { portset.protocol= addprotocol(P_SMTP); }
                 | PROTOCOL POP { portset.protocol= addprotocol(P_POP); }
@@ -810,6 +812,12 @@
                  }
                 ;
 
+limit           : /* EMPTY */
+                | LIMIT NUMBER {
+                   portset.limit = $2;
+                  }
+                ;
+
 nettimeout      : /* EMPTY */ {
                    $<number>$= NET_TIMEOUT;
                   }
@@ -1567,6 +1575,7 @@
   p->pathname= pp->pathname;
   p->hostname= pp->hostname;
   p->request_checksum= pp->request_checksum;
+  p->limit= pp->limit;
 
   if (p->request_checksum) {
     cleanup_hash_string(p->request_checksum);
@@ -1929,6 +1938,7 @@
 
   switch (protocol) {
   case P_HTTP:    return create_http();
+  case P_APACHE:  return create_apache();
   case P_FTP:     return create_ftp();
   case P_SMTP:    return create_smtp();
   case P_POP:     return create_pop();
@@ -2462,6 +2472,7 @@
   portset.sslversion= SSL_VERSION_AUTO;
   portset.request= NULL;
   portset.request_checksum= NULL;
+  portset.limit= 0;
   portset.generic= NULL;
   portset.protocol= NULL;
   portset.pathname= NULL;
diff -Naur monit-4.4/protocols/apache.c monit-4.4-patched/protocols/apache.c
--- monit-4.4/protocols/apache.c        1970-01-01 01:00:00.000000000 +0100
+++ monit-4.4-patched/protocols/apache.c        2004-12-07 23:00:00.000000000 
+0000
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C), 2000-2004 by the monit project group.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "protocol.h"
+
+#undef   READ_SIZE
+#define  READ_SIZE  8192
+
+/* Private prototypes */
+static char *get_host_header(Socket_T s, char * host);
+static int check_apache_status(Socket_T s, int limit);
+
+/**
+ * Check an Apache server to monitor its status.
+ * Do this using the server-status report from mod_status, which 
+ * will only be available if the server is responding to 
+ * some extent.
+ * Currently only logging processes are considered, but the 
+ * method can easily be expanded to other server-status messages.
+ * 
+ */
+int check_apache(Socket_T s) {
+
+  char host[STRLEN];
+  char *request= NULL;
+  int limit= 50;
+
+  ASSERT(s);
+
+  if(socket_get_Port(s)) {
+    limit= ((Port_T)(socket_get_Port(s)))->limit;
+  }
+
+  request= "/server-status/?auto";
+ 
+  if(socket_print(s, "GET %s HTTP/1.1\r\n"
+                 "Host: %s\r\n"
+                 "Accept: */*\r\n"
+                 "User-Agent: %s/%s\r\n"
+                 "Connection: close\r\n\r\n",
+                 request, get_host_header(s, host), prog, VERSION) < 0) {
+    log("HTTP: error sending data -- %s\n", STRERROR);
+    return FALSE;
+  }
+
+  return check_apache_status(s, limit);
+  
+}
+
+
+/* ----------------------------------------------------------------- Private */
+
+
+/**
+ * @return a "hostname:port" or a void string if host
+ * equals LOCALHOST or if it is an IP address
+ */
+static char *get_host_header(Socket_T s, char *hostbuf) {
+
+  if(! strcmp(LOCALHOST, socket_get_remote_host(s)) ||
+     inet_aton(socket_get_remote_host(s), NULL)) {
+
+    *hostbuf= 0;
+
+  } else {
+
+    snprintf(hostbuf, STRLEN, "%s:%d",
+            socket_get_remote_host(s),
+            socket_get_remote_port(s));
+    
+  }
+
+  return hostbuf;
+
+}
+
+
+/**
+ * Extract the Scoreboard line from the mod_status response.
+ * Count the active apache child processes, and those which are
+ * logging. If the percentage logging exceeds a limit, then
+ * return FALSE.
+ * Other scoreboard codes could also be considered.
+ * @param s A socket
+ * @param limit The maximum percentage of logging processes
+ * @return TRUE if logging is OK otherwise FALSE
+ */
+static int check_apache_status(Socket_T s, int limit) {
+  
+  char line[STRLEN];
+  char search_string[STRLEN];
+  int scored = 0;
+  int no_L = 0;
+  int active_servers = 0;
+  double logging;
+  char *p;
+
+  while(NULL != socket_readln(s, line, STRLEN)) {
+    if(starts_with(line, "Scoreboard:")) {   
+      if(1 != sscanf(line, "%*s%*[: ]%s", search_string)) {
+       chomp(line, STRLEN);
+       log("APACHE error: parsing Apache status response '%s'\n", line);
+       return FALSE;
+      }else{
+        scored = 1;
+      }
+    }
+  }
+  
+  DEBUG("Scoreboard: %s\n", search_string);
+  
+  /*Check that some scoreboard line was found, if not return an error*/
+  if(!scored){
+    log("APACHE error: no scoreboard line returned by Apache server-status\n");
+    return FALSE;
+  }
+  
+  /*Currently only logging processes, further types could be added*/
+  for(p = search_string ; *p ; p++){
+    active_servers++;
+    switch(*p){
+    case 'L':
+      no_L++;
+      break;
+    case '.':
+      active_servers--;
+      break;
+    }
+  }
+
+  if(active_servers <= 0){
+    log("APACHE error: No active servers found\n");
+    return FALSE;
+  }
+  
+  logging = 100 * no_L / active_servers;
+  
+  if(logging > limit){
+    log("APACHE error: %3.0f percent of Apache processes are logging\n", 
logging);
+    return FALSE;
+  }  
+  return TRUE;
+}
diff -Naur monit-4.4/protocols/protocol.c monit-4.4-patched/protocols/protocol.c
--- monit-4.4/protocols/protocol.c      2004-01-29 17:52:12.000000000 +0000
+++ monit-4.4-patched/protocols/protocol.c      2004-12-07 17:12:00.000000000 
+0000
@@ -36,6 +36,7 @@
 /* Private variables */
 static Protocol_T mydefault= NULL;
 static Protocol_T myhttp= NULL;
+static Protocol_T myapache= NULL;
 static Protocol_T myftp= NULL;
 static Protocol_T mysmtp= NULL;
 static Protocol_T mypop= NULL;
@@ -81,6 +82,7 @@
   FREE(myrdate);   
   FREE(myrsync);   
   FREE(mygeneric); 
+  FREE(myapache);
 
 }
 
@@ -111,6 +113,19 @@
 }
 
 
+void *create_apache() {
+
+  if(myapache == NULL) {
+    NEW(myapache);
+    myapache->name= "APACHE";
+    myapache->check= check_apache;
+  }
+
+  return myapache;
+
+}
+
+
 void *create_ftp() {
 
   if(myftp == NULL) {
diff -Naur monit-4.4/protocols/protocol.h monit-4.4-patched/protocols/protocol.h
--- monit-4.4/protocols/protocol.h      2004-01-29 17:52:12.000000000 +0000
+++ monit-4.4-patched/protocols/protocol.h      2004-12-07 17:12:00.000000000 
+0000
@@ -41,11 +41,13 @@
 #define P_RDATE    12
 #define P_RSYNC    13
 #define P_GENERIC  14
+#define P_APACHE   15
 
 /* Protocol Factory routines */
 void  gc_protocols();
 void* create_default();
 void* create_http();
+void* create_apache();
 void* create_ftp();
 void* create_smtp();
 void* create_pop();
@@ -66,6 +68,7 @@
 int check_pop(Socket_T);
 int check_ftp(Socket_T);
 int check_http(Socket_T);
+int check_apache(Socket_T);
 int check_smtp(Socket_T);
 int check_imap(Socket_T);
 int check_nntp(Socket_T);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- 
-------------------------------------------------
Email: address@hidden
-------------------------------------------------




reply via email to

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