[gnome-talos] Initial attempt at generating HTML report



commit 60bf12b7bcb6bc193513a6a9b0d536aaf2bb6919
Author: Colin Walters <walters verbum org>
Date:   Sun Sep 25 18:24:57 2011 -0400

    Initial attempt at generating HTML report

 Makefile-src.am   |    9 +++-
 configure.ac      |   23 +++++++
 src/gnome-talos.c |  178 ++++++++++++++++++++++++++++++++++++++++++++++------
 src/report.html   |   69 ++++++++++++++++++++
 4 files changed, 257 insertions(+), 22 deletions(-)
---
diff --git a/Makefile-src.am b/Makefile-src.am
index 0477e82..9672d63 100644
--- a/Makefile-src.am
+++ b/Makefile-src.am
@@ -14,6 +14,13 @@ gnome_talos_SOURCES = src/gnome-talos.c \
 	src/gnome-talos-procinfo.h \
 	src/gnome-talos-meta.c \
 	src/gnome-talos-meta.h
-gnome_talos_CPPFLAGS = $(GNOME_TALOS_CFLAGS)
+gnome_talos_CPPFLAGS = $(GNOME_TALOS_CFLAGS) -I $(top_srcdir) -I $(top_builddir)
 gnome_talos_LDADD = $(GNOME_TALOS_LIBS)
 
+report.html.h: src/report.html Makefile
+	echo -n "#define REPORT_HTML " > $  tmp && \
+	sed -e s,\\\\,\\\\\\\\,g < $< | sed -e s,\",\\\\\",g | sed -e s,^,\",g -e s,\$$,\\\\n\"\\\\,g >> $  tmp && \
+	echo "" >> $  tmp && mv $  tmp $@
+BUILT_SOURCES += report.html.h
+
+EXTRA_DIST += src/report.html
diff --git a/configure.ac b/configure.ac
index 8fb8ccd..6474c6c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,29 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 AC_PROG_CC
 AM_PROG_CC_C_O
 
+AC_ARG_WITH(jquery,
+            [AC_HELP_STRING([--with-jquery=@<:@path@:>@],
+                            [path to jquery library])])
+if test x"$with_jquery" = x; then
+   if test -f "${srcdir}/jquery.js"; then
+      with_jquery=${srcdir}/jquery.js
+   else
+      AC_MSG_ERROR([--with-jquery must be specified])
+   fi
+fi
+AC_DEFINE_UNQUOTED([JQUERY_PATH], "$with_jquery", [Path to jquery])
+AC_ARG_WITH(jquery-flot,
+            [AC_HELP_STRING([--with-jquery-flot=@<:@path@:>@],
+                            [path to jquery flot library])])
+if test x"$with_jquery_flot" = x; then
+   if test -f "${srcdir}/jquery.flot.js"; then
+      with_jquery_flot=${srcdir}/jquery.flot.js
+   else
+      AC_MSG_ERROR([--with-jquery-flot must be specified])
+   fi
+fi
+AC_DEFINE_UNQUOTED([JQUERY_FLOT_PATH], "$with_jquery_flot", [Path to jquery flot])
+
 AC_PATH_PROG(GIT, [git])
 GIT_VERSION=
 if test x$GIT != x && test -d ${srcdir}/.git; then
diff --git a/src/gnome-talos.c b/src/gnome-talos.c
index c08168e..d3667a9 100644
--- a/src/gnome-talos.c
+++ b/src/gnome-talos.c
@@ -21,6 +21,7 @@
 
 #include "config.h"
 
+#include <glib-unix.h>
 #include <gio/gio.h>
 #include <json-glib/json-glib.h>
 
@@ -29,8 +30,23 @@
 #include "gnome-talos-procinfo.h"
 #include "gnome-talos-meta.h"
 
+#include "report.html.h"
+
+static void
+fatal_gerror (GError **error) G_GNUC_NORETURN;
+
+static void
+fatal_gerror (GError **error)
+{
+  g_assert (*error != NULL);
+  g_printerr ("%s\n", (*error)->message);
+
+  exit (1);
+}
+
 static gint timeout = 5;
-static char *log_file = NULL;
+static char *log_file_path = NULL;
+static char *to_html_file_path = NULL;
 
 GVariant *
 gather_snapshot (void)
@@ -94,7 +110,7 @@ write_variant (GVariant       *variant,
 }
 
 typedef struct {
-  GFile *out_path;
+  GFile *log_file;
   GFileOutputStream *out;
   GMainLoop *loop;
 } GnomeTalosApp;
@@ -104,9 +120,11 @@ timeout_gather_data (gpointer user_data)
 {
   GnomeTalosApp *app = user_data;
   GVariant *snapshot;
+  GError *error = NULL;
 
   snapshot = gather_snapshot ();
-  write_variant (snapshot, NULL, (GOutputStream*)app->out, NULL);
+  if (!write_variant (snapshot, NULL, (GOutputStream*)app->out, &error))
+    fatal_gerror (&error);
   g_variant_unref (snapshot);
 
   if (timeout > 0)
@@ -117,17 +135,145 @@ timeout_gather_data (gpointer user_data)
   return FALSE;
 }
 
+static gboolean
+on_interrupt_received (gpointer user_data)
+{
+  GnomeTalosApp *app = user_data;
+  GError *error = NULL;
+
+  if (!g_output_stream_write_all ((GOutputStream*)app->out,
+				  "]", 1, NULL, NULL, &error))
+    fatal_gerror (&error);
+
+  if (!g_output_stream_close ((GOutputStream*)app->out, NULL, &error))
+    fatal_gerror (&error);
+  
+  g_main_loop_quit (app->loop);
+}
+
+static void
+run_collection (GnomeTalosApp *app)
+{
+  GError *error = NULL;
+  GVariant *sysinfo;
+
+  g_unix_signal_add (SIGINT,
+                     on_interrupt_received,
+                     &app);
+  g_unix_signal_add (SIGTERM,
+                     on_interrupt_received,
+                     &app);
+
+  app->out = g_file_replace (app->log_file, NULL, FALSE,
+                             G_FILE_CREATE_REPLACE_DESTINATION,
+                             NULL, &error);
+  if (app->out == NULL)
+    fatal_gerror (&error);
+
+  if (!g_output_stream_write_all ((GOutputStream*)app->out,
+                                  "[", 1, NULL, NULL, &error))
+    fatal_gerror (&error);
+
+  sysinfo = gnome_talos_acquire_meta ();
+  if (!write_variant (sysinfo, NULL, (GOutputStream*)app->out, &error))
+    fatal_gerror (&error);
+  g_variant_unref (sysinfo);
+
+  if (!g_output_stream_write_all ((GOutputStream*)app->out,
+                                  ",\n", 2, NULL, NULL, &error))
+    fatal_gerror (&error);
+
+  g_idle_add (timeout_gather_data, &app);
+}
+
+static char *
+replace_key (char *buf,
+             const char *key,
+             const char *value)
+{
+  GRegex *regex;
+  char *escaped_key;
+  char *key_regex;
+  char *new_buf;
+
+  escaped_key = g_regex_escape_string (key, -1);
+  key_regex = g_strconcat ("@", escaped_key, "@", NULL);
+  g_free (escaped_key);
+
+  regex = g_regex_new (key_regex, 0, 0, NULL);
+  g_assert (regex != NULL);
+
+  new_buf = g_regex_replace (regex, buf, -1, 0, value, 0, NULL);
+  g_free (buf);
+
+  g_regex_unref (regex);
+
+  return new_buf;
+}
+             
+static void
+convert_to_html (GnomeTalosApp *app)
+{
+  GError *error = NULL;
+  JsonParser *parser;
+  JsonGenerator *generator;
+  JsonNode *root;
+  GFile *to_html_file;
+  GFileOutputStream *out;
+  char *data_string;
+  char *buf;
+  GRegex *regex;
+
+  parser = json_parser_new ();
+
+  if (!json_parser_load_from_file (parser, log_file_path, &error))
+    fatal_gerror (&error);
+
+  root = json_parser_get_root (parser);
+
+  to_html_file = g_file_new_for_path (to_html_file_path);
+
+  if ((out = g_file_replace (to_html_file, NULL, FALSE,
+                             G_FILE_CREATE_REPLACE_DESTINATION,
+                             NULL, &error)) == NULL)
+    fatal_gerror (&error);
+
+  generator = json_generator_new ();
+  json_generator_set_pretty (generator, TRUE);
+  json_generator_set_root (generator, root);
+  data_string = json_generator_to_data (generator, NULL);
+  g_object_unref (generator);
+  json_node_free (root);
+
+  buf = g_strdup (REPORT_HTML);
+  buf = replace_key (buf, "SRC_FILE", log_file_path);
+  buf = replace_key (buf, "JQUERY_PATH", JQUERY_PATH);
+  buf = replace_key (buf, "JQUERY_FLOT_PATH", JQUERY_FLOT_PATH);
+  buf = replace_key (buf, "DATA", data_string);
+  g_free (data_string);
+
+  if (!g_output_stream_write_all ((GOutputStream*)out,
+                                  buf, strlen (buf), NULL, NULL, &error))
+    fatal_gerror (&error);
+  g_free (buf);
+
+  if (!g_output_stream_close ((GOutputStream*)out, NULL, &error))
+    fatal_gerror (&error);
+
+  g_idle_add ((GSourceFunc)g_main_loop_quit, app->loop);
+}
+
 int
 main (int    argc,
       char **argv)
 {
   GnomeTalosApp app;
-  GVariant *sysinfo;
   GError *error = NULL;
   GOptionContext *context;
   static const GOptionEntry options[] = {
     { "timeout", 0, 0, G_OPTION_ARG_INT, &timeout, "Time between data snapshots, in seconds (default=5)", "seconds" },
-    { "log-file", 0, 0, G_OPTION_ARG_FILENAME, &log_file, "Log file path", "path" },
+    { "log-file", 0, 0, G_OPTION_ARG_FILENAME, &log_file_path, "Log file path", "path" },
+    { "to-html-file", 0, 0, G_OPTION_ARG_FILENAME, &to_html_file_path, "Convert log file to HTML", "path" },
     { NULL }
   };
 
@@ -142,29 +288,19 @@ main (int    argc,
       g_printerr ("%s\n", error->message);
       return 1;
     }
-  if (log_file == NULL)
+  if (log_file_path == NULL)
     {
       g_printerr ("--log-file is required\n");
       return 1;
     }
 
-  app.out_path = g_file_new_for_path (log_file);
-  app.out = g_file_replace (app.out_path, NULL, FALSE,
-			    G_FILE_CREATE_REPLACE_DESTINATION,
-			    NULL, &error);
-  if (app.out == NULL)
-    {
-      g_printerr ("%s\n", error->message);
-      return 1;
-    }
-
-  sysinfo = gnome_talos_acquire_meta ();
-  write_variant (sysinfo, NULL, (GOutputStream*)app.out, NULL);
-  g_variant_unref (sysinfo);
-
   app.loop = g_main_loop_new (NULL, TRUE);
+  app.log_file = g_file_new_for_path (log_file_path);
 
-  g_idle_add (timeout_gather_data, &app);
+  if (to_html_file_path == NULL)
+    run_collection (&app);
+  else
+    convert_to_html (&app);
 
   g_main_loop_run (app.loop);
   
diff --git a/src/report.html b/src/report.html
new file mode 100644
index 0000000..fe66885
--- /dev/null
+++ b/src/report.html
@@ -0,0 +1,69 @@
+<!-- -*- mode: HTML -*-; indent-tabs-mode: nil; tab-width: 2 -*- -->
+<!-- Copyright (C) 2011 Red Hat, Inc.
+ 
+ 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.
+
+ Author: Colin Walters <walters verbum org>
+-->
+
+<html>
+  <head>
+    <title>Report for @SRC_FILE@</title>
+    <script type="text/javascript" src="@JQUERY_PATH@"></script>
+    <script type="text/javascript" src="@JQUERY_FLOT_PATH@"></script>
+    <script type="text/javascript">
+      var data = @DATA@;
+
+      function getRSSForSnapshot(snapshot) {
+        var meta = snapshot[0];
+        var processes = snapshot[1].processes[0];
+        var system = 0;
+        var user = 0;
+
+        for (var pid in processes) {
+          var process = processes[pid];
+          var real_uid = process['real-uid'];
+          if (real_uid >= 500) 
+            system += process['rss'];
+          else
+            user += process['rss'];
+        }
+        
+        return [system, user];
+      }
+ 
+      $(document).ready(function () {
+        $("#system-uuid")[0].appendChild(document.createTextNode(data[0].uuid));
+        $("#system-ram")[0].appendChild(document.createTextNode(data[0].memtotal));
+
+        var systemRSS = [];
+        var userRSS = [];
+        for (var i = 1; i < data.length; i++) {
+          var rssData = getRSSForSnapshot(data[i]);
+          systemRSS.push([i, rssData[0]]);
+          userRSS.push([i, rssData[1]]);
+        }
+      $.plot($("#rss-graph"), [ systemRSS, userRSS ]);
+     });
+    </script>
+  </head>
+  <body>
+    <h1>Report for @SRC_FILE@:</h1>
+    <p><tt>System UUID: <span id="system-uuid"></span></tt></p>
+    <p><tt>System Total RAM: <span id="system-ram"></span></tt></p>
+    <div id="rss-graph" style="width:800px;height:500px;"></div>
+  </body>
+</html>
+      



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