Hi,
I'm not a C coder by any means but I thought it would be easier to
write the code to handle _status?format=json requests than spending
my life with XML parsing.
It's a plain translation of xml.c so I don't claim authorship or
anything. The code is known to yield valid JSON on my box (tested
with pythons json parser) but far from completely tested.
The patch is against 5.0beta7, I hope someone finds it useful.
cheers
Paul
diff -Naur monit-5.0_beta7/http/cervlet.c monit-5.0_beta7.patched/
http/cervlet.c
--- monit-5.0_beta7/http/cervlet.c 2009-02-15 13:46:18.000000000 +0100
+++ monit-5.0_beta7.patched/http/cervlet.c 2009-03-14
23:03:13.000000000 +0100
@@ -2473,6 +2473,13 @@
FREE(D);
set_content_type(res, "text/xml");
}
+ else if(stringFormat && Util_startsWith(stringFormat, "json"))
+ {
+ char *D = status_json(NULL, level);
+ out_print(res, "%s", D);
+ FREE(D);
+ set_content_type(res, "application/json");
+ }
else
{
char *uptime =
Util_getUptime(Util_getProcessUptime(Run.pidfile), " ");
diff -Naur monit-5.0_beta7/json.c monit-5.0_beta7.patched/json.c
--- monit-5.0_beta7/json.c 1970-01-01 01:00:00.000000000 +0100
+++ monit-5.0_beta7.patched/json.c 2009-03-14 23:03:13.000000000 +0100
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2009 Tildeslash Ltd. 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 version 3.
+ *
+ * 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, see <http://www.gnu.org/licenses/
>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If
you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+
+#include <config.h>
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "monitor.h"
+#include "event.h"
+#include "process.h"
+
+
+/**
+ * JSON routines for status and event notification message handling.
+ *
+ * @author Martin Pala, <address@hidden>
+ *
+ * @version \$Id: json.c,v 1.54 2009/02/13 09:18:12 hauk Exp $
+ *
+ * @file
+ */
+
+
+/* -------------------------------------------------------------
Definitions */
+
+
+/** Defines an output buffer object */
+typedef struct mybuffer {
+ char *buf; /**< Output
buffer */
+ size_t bufsize; /**< Output
buffer size */
+ size_t bufused; /**< Output
buffer usage */
+} Buffer_T;
+
+
+/* --------------------------------------------------------------
Prototypes */
+
+
+static void document_head(Buffer_T *);
+static void document_foot(Buffer_T *);
+static void status_service(Service_T, Buffer_T *, short);
+static void status_event(Event_T, Buffer_T *);
+static void buf_print(Buffer_T *, const char *, ...);
+
+
+/*
------------------------------------------------------------------
Public */
+
+
+/**
+ * Return JSON formated message for event notification or general
status
+ * of monitored services and resources.
+ * @param E An event object or NULL for general status
+ * @param L Status information level
+ * @return JSON document or NULL in the case of error. The caller
must free
+* the memory.
+ */
+char *status_json(Event_T E, short L) {
+
+ Buffer_T B;
+ Service_T S;
+
+ memset(&B, 0, sizeof(Buffer_T));
+
+ document_head(&B);
+
+ if(E)
+ {
+ /* there is no use for status level in the event (at least now)
*/
+ status_event(E, &B);
+ }
+ else
+ {
+ buf_print(&B, ", \"servicelist\":[ ");
+ for(S = servicelist_conf; S; S = S->next_conf)
+ {
+ status_service(S, &B, L);
+ S->next_conf ? buf_print(&B, ", ") : buf_print(&B, " ");
+ }
+ buf_print(&B, " ]");
+ }
+ document_foot(&B);
+
+ return B.buf;
+
+}
+
+
+/*
-----------------------------------------------------------------
Private */
+
+
+/**
+ * Prints a document header into the given buffer.
+ * @param B Buffer object
+ */
+static void document_head(Buffer_T *B) {
+
+
+ buf_print(B,
+ "{\"monit\": "
+ "{\"server\": {"
+ "\"id\":\"%s\", "
+ "\"incarnation\":%ld, "
+ "\"version\":\"%s\", "
+ "\"uptime\":%ld, "
+ "\"poll\":%d, "
+ "\"startdelay\":%d, "
+ "\"localhostname\":\"%s\", "
+ "\"controlfile\":\"%s\"",
+ Run.id,
+ Run.incarnation,
+ VERSION,
+ (long)Util_getProcessUptime(Run.pidfile),
+ Run.polltime,
+ Run.startdelay,
+ Run.localhostname ? Run.localhostname : "",
+ Run.controlfile ? Run.controlfile : "");
+
+ if(Run.dohttpd)
+ {
+ buf_print(B,
+ ", \"httpd\": {"
+ "\"address\":\"%s\","
+ "\"port\":%d,"
+ "\"ssl\":%d }",
+ Run.bind_addr?Run.bind_addr:"",
+ Run.httpdport,
+ Run.httpdssl);
+ }
+
+ buf_print(B,
+ ", \"platform\": {"
+ "\"name\":\"%s\", \"release\":\"%s\", \"version\":\"%s\","
+ "\"machine\":\"%s\", \"cpu\":%d, \"memory\":%lu }}}",
+ systeminfo.uname.sysname,
+ systeminfo.uname.release,
+ systeminfo.uname.version,
+ systeminfo.uname.machine,
+ systeminfo.cpus,
+ systeminfo.mem_kbyte_max);
+
+}
+
+
+/**
+ * Prints a document footer into the given buffer.
+ * @param B Buffer object
+ */
+static void document_foot(Buffer_T *B) {
+
+ buf_print(B, "}"); //closing monit
+
+}
+
+
+/**
+ * Prints a service status into the given buffer.
+ * @param S Service object
+ * @param B Buffer object
+ * @param L Status information level
+ */
+static void status_service(Service_T S, Buffer_T *B, short L) {
+ Event_T E = S->eventlist;
+ buf_print(B,
+ "{"
+ "\"type\":%d, \"collected_sec\":%ld, "
+ "\"collected_usec\":%ld, \"name\":\"%s\", \"status\":%llu, "
+ "\"monitor\":%d, \"monitormode\":%d, \"pendingaction\":%d, "
+ "\"group\":\"%s\"",
+ S->type,
+ S->collected.tv_sec,
+ S->collected.tv_usec,
+ S->name?S->name:"",
+ S->error,
+ S->monitor,
+ S->mode,
+ S->doaction,
+ S->group?S->group:"");
+ /* if the service is in error state, display first active error
message to provide more details */
+ while (E) {
+ if (E->state == STATE_FAILED && (S->error & E->id) && E-
>message) {
+ buf_print(B, ", \"status_message\":\"%s\"", E->message);
+ break;
+ }
+ E = E->next;
+ }
+ if(L == LEVEL_FULL)
+ {
+ if(Util_hasServiceStatus(S)) {
+ if(S->type == TYPE_FILE ||
+ S->type == TYPE_DIRECTORY ||
+ S->type == TYPE_FIFO ||
+ S->type == TYPE_FILESYSTEM) {
+ buf_print(B,
+ ", \"mode\":%o, \"uid\":%d, \"gid\":%d",
+ S->inf->st_mode & 07777,
+ (int)S->inf->st_uid,
+ (int)S->inf->st_gid);
+ }
+ if(S->type == TYPE_FILE ||
+ S->type == TYPE_FIFO ||
+ S->type == TYPE_DIRECTORY) {
+ buf_print(B,
+ ", \"timestamp\":%ld",
+ (long)S->inf->timestamp);
+ }
+ if(S->type == TYPE_FILE) {
+ buf_print(B,
+ ", \"size\":%llu",
+ (unsigned long long) S->inf->st_size);
+ if(S->checksum) {
+ buf_print(B,
+ ", \"checksum_type\":\"%s\", \"checksum\":\"%s\"",
+ checksumnames[S->checksum->type], S->inf->cs_sum);
+ }
+ }
+ if(S->type == TYPE_FILESYSTEM) {
+ buf_print(B,
+ ", \"flags\":%ld, "
+ "\"block\": { \"percent\":%.1f, \"usage\":%.1f MB, "
+ "\"total\":%.1f MB }",
+ S->inf->flags,
+ S->inf->space_percent/10.,
+ (float)S->inf->space_total / (float)1048576 * (float)S->inf-
>f_bsize,
+ (float)S->inf->f_blocks / (float)1048576 * (float)S-
>inf->f_bsize);
+ if(S->inf->f_files > 0) {
+ buf_print(B,
+ ", \"inode:\": {"
+ "\"percent\":%.1f, \"usage\":%ld, "
+ "\"total\":%ld }",
+ S->inf->inode_percent/10.,
+ S->inf->inode_total,
+ S->inf->f_files);
+ }
+ }
+ if(S->type == TYPE_PROCESS) {
+ buf_print(B,
+ ", \"pid\":%d, \"ppid\":%d, \"uptime\":%ld",
+ S->inf->pid,
+ S->inf->ppid,
+ (long)S->inf->uptime);
+ if(Run.doprocess) {
+ buf_print(B,
+ ", \"children\":%d, "
+ "\"memory\": {"
+ "\"percent\":%.1f, \"percenttotal\":%.1f, "
+ "\"kilobyte\":%ld, \"kilobytetotal\":%ld }, "
+ "\"cpu\": {\"percent\":%.1f, \"percenttotal\":%.1f }",
+ S->inf->children,
+ S->inf->mem_percent/10.0,
+ S->inf->total_mem_percent/10.0,
+ S->inf->mem_kbyte,
+ S->inf->total_mem_kbyte,
+ S->inf->cpu_percent/10.0,
+ S->inf->total_cpu_percent/10.0);
+ }
+ }
+ if(S->type == TYPE_HOST && S->icmplist) {
+ Icmp_T i;
+ buf_print(B, ", [");
+ for(i= S->icmplist; i; i= i->next) {
+ buf_print(B,
+ "\"icmp\": {"
+ "\"type\":\"%s\", \"responsetime\":%.3f }%s",
+ icmpnames[i->type],
+ i->is_available?i->response:-1.,
+ i->next?", ":" ");
+ }
+ buf_print(B, "]");
+ }
+ if((S->type == TYPE_HOST || S->type == TYPE_PROCESS) && S->
portlist) {
+ Port_T p;
+ buf_print(B, "[");
+ for(p= S->portlist; p; p= p->next) {
+ if(p->family == AF_INET) {
+ buf_print(B,
+ "\"port\": { "
+ "\"hostname\":\"%s\", \"portnumber\":%d, \"request\":
\"%s\", "
+ "\"protocol\":\"%s\", \"type\":\"%s\", \"responsetime\":
%.3f }%s",
+ p->hostname?p->hostname:"",
+ p->port,
+ p->request?p->request:"",
+ p->protocol->name?p->protocol->name:"",
+ Util_portTypeDescription(p),
+ p->is_available?p->response:-1.,
+ p->next?", ":" ");
+
+ } else if(p->family == AF_UNIX) {
+ buf_print(B,
+ "\"unix\": { "
+ "\"path\":\"%s\", \"protocol\":\"%s\", \"responsetime\":
%.3f }%s",
+ p->pathname?p->pathname:"",
+ p->protocol->name?p->protocol->name:"",
+ p->is_available?p->response:-1.,
+ p->next?", ":" ");
+ }
+ }
+ buf_print(B, "]");
+ }
+ if(S->type == TYPE_SYSTEM && Run.doprocess) {
+ buf_print(B,
+ ", \"system\": {"
+ "\"load\": { \"avg01\":%.2f, \"avg05\":%.2f, "
+ "\"avg15\":%.2f }, "
+ "\"cpu\": { \"user\":%.1f, \"system\":%.1f"
+#ifdef HAVE_CPU_WAIT
+ ", \"wait\":%.1f"
+#endif
+ "}, \"memory\": {"
+ "\"percent\":%.1f, \"kilobyte\":%.ld }}",
+ systeminfo.loadavg[0],
+ systeminfo.loadavg[1],
+ systeminfo.loadavg[2],
+ systeminfo.total_cpu_user_percent/10.,
+ systeminfo.total_cpu_syst_percent/10.,
+ #ifdef HAVE_CPU_WAIT
+ systeminfo.total_cpu_wait_percent/10.,
+ #endif
+ systeminfo.total_mem_percent/10.,
+ systeminfo.total_mem_kbyte);
+ }
+ }
+ }
+ buf_print(B, "}"); //closing service
+}
+
+
+/**
+ * Prints a event description into the given buffer.
+ * @param E Event object
+ * @param B Buffer object
+ */
+static void status_event(Event_T E, Buffer_T *B) {
+
+ Service_T s;
+ struct timeval *tv;
+
+ ASSERT(E);
+
+ if(!(s = Event_get_source(E)))
+ return;
+
+ tv = Event_get_collected(E);
+
+ buf_print(B,
+ "{"
+ "\"collected_sec\":%ld, \"collected_usec\":%ld, "
+ "\"service\":\"%s\", \"type\":%d, \"group\":\"%s\", \"id\":%d, "
+ "\"state\":%d, \"action\":%d, \"message\":\"%s\"",
+ tv->tv_sec,
+ tv->tv_usec,
+ Event_get_source_name(E),
+ Event_get_source_type(E),
+ Event_get_source_group(E),
+ Event_get_id(E),
+ Event_get_state(E),
+ Event_get_action(E),
+ Event_get_message(E));
+ if (s->token) {
+ buf_print(B,
+ ", \"token\":\"%s\"",
+ s->token);
+ }
+ buf_print(B,
+ "}");
+}
+
+
+/**
+ * Prints a string into the given buffer.
+ * @param B Buffer object
+ * @param m A formated string to be written to the buffer
+ */
+static void buf_print(Buffer_T *B, const char *m, ...) {
+ if(m)
+ {
+ va_list ap;
+ char *buf;
+ long need= 0;
+ ssize_t have= 0;
+
+ va_start(ap, m);
+ buf = Util_formatString(m, ap, &need);
+ va_end(ap);
+
+ have = (*B).bufsize - (*B).bufused;
+ if(have <= need)
+ {
+ (*B).bufsize += (need + STRLEN);
+ (*B).buf = xresize((*B).buf, (*B).bufsize);
+ if(!(*B).bufused)
+ {
+ memset((*B).buf, 0, (*B).bufsize);
+ }
+ }
+ memcpy(&(*B).buf[(*B).bufused], buf, need);
+ (*B).bufused += need;
+ (*B).buf[(*B).bufused]= 0;
+ FREE(buf);
+ }
+}
+
diff -Naur monit-5.0_beta7/monitor.h monit-5.0_beta7.patched/monitor.h
--- monit-5.0_beta7/monitor.h 2009-02-15 13:46:17.000000000 +0100
+++ monit-5.0_beta7.patched/monitor.h 2009-03-14 23:03:13.000000000
+0100
@@ -908,6 +908,7 @@
int check_service_status(Service_T);
void printhash(char *);
char *status_xml(Event_T, short);
+char *status_json(Event_T, short);
int handle_mmonit(Event_T);
int do_wakeupcall();
_______________________________________________
monit-dev mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/monit-dev