Browse Source

Support for multiple graphs per plugin module. Sample plugin added.

- hook_munin_api_info() can now return multiple graphs insteaf of just one
- sample CURL-based plugin script added in plugins/
- new RRD drawing mode constants added
FGM 13 years ago
parent
commit
4df6de23da
4 changed files with 193 additions and 85 deletions
  1. 46 23
      modules/munin_apc/munin_apc.module
  2. 21 7
      modules/munin_core/munin_core.module
  3. 99 55
      munin_api.module
  4. 27 0
      plugins/munin-drupal_

+ 46 - 23
modules/munin_apc/munin_apc.module

@@ -15,7 +15,8 @@
  * Implements hook_munin_api_info().
  *
  * @return
- *   An array of Munin probes informations, index by probe name.
+ *   An array of Munin graph informations, index by graph name, each containing
+ *   an array of field information.
  */
 function munin_apc_munin_api_info() {
   $int = array(
@@ -23,9 +24,14 @@ function munin_apc_munin_api_info() {
   );
 
   $ret = array(
+    '#title'       => t('APC'),
+    '#description' => t('Graphs about PHP APC'),
+
     'munin_apc' => array(
-      '#title' => t('PHP APC'),
-      '#info' => t('Collect cache information for the Alternative PHP Cache'),
+      '#title'     => t('APC Caching'),
+      '#info'      => t('Collect cache information for the Alternative PHP Cache. This graph uses IEC binary sizes.'),
+      '#graph_args'=> '--base 1024 --lower-limit 0',
+
       'total_size' => $int + array(
         '#label'     => t('Bytes allocated'),
         '#type'      => MUNIN_API_GAUGE,
@@ -36,11 +42,6 @@ function munin_apc_munin_api_info() {
         '#type'      => MUNIN_API_GAUGE,
         '#info'      => t('Number of bytes actually used by APC, either cached or deleted'),
       ),
-      'uptime'     => $int + array(
-        '#label'     => t('Up-time of APC instance'),
-        '#type'      => MUNIN_API_GAUGE,
-        '#info'      => t('Seconds since last APC restart.'),
-      ),
       'num_hits'   => $int + array(
         '#label'     => t('Hits since last restart'),
         '#type'      => MUNIN_API_COUNTER,
@@ -67,6 +68,19 @@ function munin_apc_munin_api_info() {
         '#info'      => t('Deleted entries lingering until the garbage collection TTL elapses'),
       ),
     ),
+
+    'munin_apc_uptime' => array(
+      '#title'     => t('APC Uptime'),
+      '#info'      => t('Uptime information for the Alternative PHP Cache.'),
+      '#graph_vlabel' => t('Uptime in days'),
+
+      'uptime'     => $int + array(
+        '#label'     => t('Up-time of APC instance'),
+        '#type'      => MUNIN_API_GAUGE,
+        '#info'      => t('Days since last APC restart.'),
+        '#draw'      => MUNIN_API_DRAW_AREA,
+      ),
+    ),
   );
 
   return $ret;
@@ -74,25 +88,34 @@ function munin_apc_munin_api_info() {
 
 /**
  * Implements hook_munin_api_fetch().
+ *
+ * The static cache is useless at this point, but will likely become useful
+ * if module builds Munin multigraphs.
  */
-function munin_apc_munin_api_fetch() {
-  $info = apc_sma_info();
-  $ret = array();
+function munin_apc_munin_api_fetch($graph_name) {
 
-  // SMA Info
-  $total = $info['num_seg'] * $info['seg_size'];
-  $ret['total_size'] = (int) $total;
-  $ret['used_size'] = (int) ($total - $info['avail_mem']);
+  static $cache = array();
 
-  // Cache info
-  $info = apc_cache_info();
-  $ret['uptime']      = time() - $info['start_time'];
-  foreach (array('num_hits', 'num_misses', 'num_inserts') as $field) {
-    $ret[$field] = $info[$field];
-  }
+  if (empty($cache)) {
+    $info = apc_sma_info();
+    $ret = array();
+
+    // SMA Info
+    $total = $info['num_seg'] * $info['seg_size'];
+    $cache['munin_apc']['total_size'] = (int) $total;
+    $cache['munin_apc']['used_size'] = (int) ($total - $info['avail_mem']);
 
-  $ret['cache_entries']   = count($info['cache_list']);
-  $ret['deleted_entries'] = count($info['deleted_list']);
+    // Cache info
+    $info = apc_cache_info();
+    $cache['munin_apc_uptime']['uptime'] = (time() - $info['start_time']) / 86400;
+    foreach (array('num_hits', 'num_misses', 'num_inserts') as $field) {
+      $cache['munin_apc'][$field] = $info[$field];
+    }
+
+    $cache['munin_apc']['cache_entries']   = count($info['cache_list']);
+    $cache['munin_apc']['deleted_entries'] = count($info['deleted_list']);
+  }
 
+  $ret = $cache[$graph_name];
   return $ret;
 }

+ 21 - 7
modules/munin_core/munin_core.module

@@ -23,13 +23,22 @@ function munin_core_munin_api_info() {
   );
 
   $ret = array(
+    '#title'     => t('Drupal'),
+    '#description'  => t('Graphs about Drupal core'),
+
     'munin_core' => array(
-      '#title' => t('Drupal core'),
-      '#info' => t('Collect core information from a Drupal instance. All counters are integer-rounded.'),
+      '#title'     => t('Drupal core'),
+      '#info'      => t('Collect core information from a Drupal instance. All counters are integer-rounded.'),
+
       'user_current' => $int + array(
-        '#label'    => t('Currently logged-in users'),
-        '#type'     => MUNIN_API_GAUGE,
-        '#info'     => t('The number of sessions not older than 5 minutes. Only meaningful if you are not using an alternate sessions implementation not using the sessions table.'),
+        '#label'     => t('Logged-in sessions'),
+        '#type'      => MUNIN_API_GAUGE,
+        '#info'      => t('The number of logged-in sessions not older than 5 minutes. Only meaningful if you are not using an alternate sessions implementation not using the sessions table.'),
+      ),
+      'anon_current' => $int + array(
+        '#label'     => t('Anonymous sessions'),
+        '#type'      => MUNIN_API_GAUGE,
+        '#info'      => t('The number of anonymous sessions not older than 5 minutes. Only meaningful if you are not using an alternate sessions implementation not using the sessions table.'),
       ),
       'user_count' => $int + array(
         '#label'    => t('Number of users'),
@@ -64,8 +73,10 @@ function munin_core_munin_api_info() {
 
 /**
  * Implements hook_munin_api_fetch().
+ *
+ * Only one graph, so we can ignore the $graph_name parameter.
  */
-function munin_core_munin_api_fetch() {
+function munin_core_munin_api_fetch($graph_name) {
   $sq = 'SELECT COUNT(u.uid) cnt, u.status FROM {users} u GROUP BY 2';
   $result = db_query($sq);
   while ($row = db_fetch_object($result)) {
@@ -77,9 +88,12 @@ function munin_core_munin_api_fetch() {
   $ret['user_count'] = $users[0] + $users[1];
 
 
-  $sq = 'SELECT COUNT(*) cnt FROM {sessions} s WHERE s.timestamp >= UNIX_TIMESTAMP() - 5*60';
+  $sq = 'SELECT COUNT(*) cnt FROM {sessions} s WHERE s.uid != 0 AND s.timestamp >= UNIX_TIMESTAMP() - 5*60';
   $ret['user_current'] = db_result(db_query($sq));
 
+  $sq = 'SELECT COUNT(*) cnt FROM {sessions} s WHERE s.uid = 0 AND s.timestamp >= UNIX_TIMESTAMP() - 5*60';
+  $ret['anon_current'] = db_result(db_query($sq));
+
   $sq = 'SELECT COUNT(*) cnt FROM {node} n WHERE n.status = 1';
   // No db_rewrite_sql(): this is an administrative mechanism
   $ret['node_count'] = db_result(db_query($sq));

+ 99 - 55
munin_api.module

@@ -16,6 +16,19 @@ define('MUNIN_API_DERIVE',   'DERIVE');
 define('MUNIN_API_GAUGE',    'GAUGE');
 define('MUNIN_API_ABSOLUTE', 'ABSOLUTE'); // Counters reset upon reading (uncommon)
 
+define('MUNIN_API_DRAW_AREA',		'AREA');
+define('MUNIN_API_DRAW_LINE0',  'LINE0'); // Invisible line, but triggers graphs scaling
+define('MUNIN_API_DRAW_LINE1',  'LINE1'); // Default on Munin 2.0
+define('MUNIN_API_DRAW_LINE2',  'LINE2'); // Default on Munine < 2.0
+define('MUNIN_API_DRAW_LINE3',	'LINE3');
+define('MUNIN_API_DRAW_STACK',  'STACK');
+
+// Styles below are only supported on Munin >= 1.3.3
+define('MUNIN_API_DRAW_LINESTACK1',  'LINESTACK1');
+define('MUNIN_API_DRAW_LINESTACK2',  'LINESTACK2');
+define('MUNIN_API_DRAW_LINESTACK3',  'LINESTACK3');
+define('MUNIN_API_DRAW_AREASTACK',  	'AREASTACK');
+
 /**
  * Finalize result pages for Munin interactions.
  *
@@ -84,54 +97,60 @@ function munin_api_menu() {
     'weight' => -1,
   );
 
-  foreach (module_implements('munin_api_info') as $name) {
-    $module = module_invoke($name, 'munin_api_info');
-    $module = $module[$name];
-    $items['munin_api/'. $name] = array(
-      'type' => MENU_CALLBACK,
-      'page callback' => 'munin_api_page_fetch',
-      'page arguments' => array(1),
-      'access callback' => 'munin_api_access_fetch',
-      'access arguments' => array($name),
-    );
-    $items['munin_api/'. $name .'/config'] = array(
-      'type' => MENU_CALLBACK,
-      'page callback' => 'munin_api_page_config',
-      'page arguments' => array(1),
-      'access callback' => 'munin_api_access_config',
-      'access arguments' => array($name),
-    );
+  foreach (module_implements('munin_api_info') as $module_name) {
+    $module = module_invoke($module_name, 'munin_api_info');
+    $graphs = element_children($module);
 
-    $items['admin/reports/munin_api/'. $name] = array(
-      'type' => MENU_LOCAL_TASK,
-      'title' => $module['#title'],
-      'description' => $module['#description'],
-      'page callback' => 'munin_api_page_report_instance',
-      'page arguments' => array(3),
+    $items['admin/reports/munin_api/'. $module_name] = array(
+      'type'             => MENU_LOCAL_TASK,
+      'title'            => $module['#title'],
+      'description'      => $module['#description'],
+      'page callback'    => 'munin_api_page_report_instance',
+      'page arguments'   => array($module_name, $module),
       'access arguments' => array('access site reports'),
     );
-  }
 
+    foreach ($graphs as $graph_name) {
+      $items['munin_api/'. $graph_name] = array(
+        'type' => MENU_CALLBACK,
+        'page callback'    => 'munin_api_page_fetch',
+        'page arguments'   => array($module_name, $module, $graph_name),
+        'access callback'  => 'munin_api_access_fetch',
+        'access arguments' => array($module_name, $graph_name),
+      );
+      $items['munin_api/'. $graph_name .'/config'] = array(
+        'type' => MENU_CALLBACK,
+        'page callback' => 'munin_api_page_config',
+        'page arguments' => array($module_name, $graph_name),
+        'access callback' => 'munin_api_access_config',
+        'access arguments' => array($module_name, $graph_name),
+      );
+    }
+  }
 
+  ksort($items);
   return $items;
 }
 
 /**
  * Page callback for munin config fetches.
  */
-function munin_api_page_config($module) {
-  $module_info = module_invoke($module, 'munin_api_info');
-  if (!is_array($module_info) || count($module_info) != 1) {
+function munin_api_page_config($module_name, $graph_name) {
+  $module_info = module_invoke($module_name, 'munin_api_info');
+  if (!is_array($module_info)) {
     return _munin_report_hook_error('munin_api_info', $module);
   }
-  $info = reset($module_info);
-
+  $info = $module_info[$graph_name];
   $config = array(
     'graph_title'    => $info['#title'],
-    // 'graph_vlabel' => '',
     'graph_info'     => $info['#info'],
     'graph_category' => 'Drupal',
   );
+  foreach (element_properties($info) as $property_name) {
+    if (!in_array($property_name, array('#title', '#info'))) {
+      $config[drupal_substr($property_name, 1)] = $info[$property_name];
+    }
+  }
 
   foreach (element_children($info) as $field_name) {
     foreach (element_properties($info[$field_name]) as $property_name) {
@@ -149,8 +168,8 @@ function munin_api_page_config($module) {
 /**
  * Page callback for munin data fetches.
  */
-function munin_api_page_fetch($module) {
-  $data = module_invoke($module, 'munin_api_fetch');
+function munin_api_page_fetch($module_name, $module, $graph_name) {
+  $data = module_invoke($module_name, 'munin_api_fetch', $graph_name);
   if (!is_array($data)) {
     return _munin_report_hook_error('munin_api_fetch', $module);
   }
@@ -169,22 +188,38 @@ function munin_api_page_fetch($module) {
  * @return string
  */
 function munin_api_page_report_global() {
-  $items = module_invoke_all('munin_api_info');
-
   $header = array(
     t('Module'),
+    t('Graph'),
     t('Description'),
     t('Fields'),
   );
   $rows = array();
-  foreach ($items as $name => $item) {
-    $link_title = $item['#label'] ? $item['#label'] : $name;
+
+  foreach (module_implements('munin_api_info') as $module_name) {
+    $info = module_invoke($module_name, 'munin_api_info');
     $rows[] = array(
-      l($link_title, 'admin/reports/munin_api/'. $name),
-      isset($item['#info']) ? $item['#info'] : t('&lt;missing&gt;'),
-      count(element_children($item)),
+      array(
+        'data' => l($info['#title'], 'admin/reports/munin_api/'. $module_name),
+        'colspan' => 2,
+      ),
+      array(
+        'colspan' => 2,
+        'data' => $info['#description'],
+      ),
     );
+
+    foreach (element_children($info) as $name) {
+      $title = $info[$name]['#title'] ? $info[$name]['#title'] : $name;
+      $rows[] = array(
+        '&nbsp;',
+        $title,
+        isset($info[$name]['#info']) ? $info[$name]['#info'] : t('&lt;missing&gt;'),
+        count(element_children($info[$name])),
+      );
+    }
   }
+
   $ret = theme('table', $header, $rows);
   return $ret;
 }
@@ -194,30 +229,39 @@ function munin_api_page_report_global() {
  *
  * @return string
  */
-function munin_api_page_report_instance($module) {
-  $module_info = module_invoke($module, 'munin_api_info');
-  if (!is_array($module_info) || count($module_info) != 1) {
-    return _munin_report_hook_error('munin_api_info', $module);
-  }
-  $module_info = reset($module_info);
+function munin_api_page_report_instance($module_name, $module_info) {
   if (!is_array($module_info)) {
     return _munin_report_hook_error('munin_api_info', $module);
   }
 
-  $header = array(t('Name'), t('Description'), t('Type'));
+  $header = array(
+    t('Name'),
+    t('Title / Description'),
+    t('Type'),
+    array('data' => t('Debug'), 'colspan' => 2),
+  );
   $rows = array();
-  foreach (element_children($module_info) as $name) {
+  foreach (element_children($module_info) as $graph_name) {
     $rows[] = array(
-      $name,
-      isset($module_info[$name]['#label']) ? $module_info[$name]['#label'] : t('&lt;missing&gt;'),
-      $module_info[$name]['#type'],
+      array(
+        'data' => $module_info[$graph_name]['#title'] ? $module_info[$graph_name]['#title'] : $graph_name,
+        'colspan' => 3,
+      ),
+    l(t('config'), 'munin_api/'. $graph_name .'/config'),
+    l(t('data'), 'munin_api/'. $graph_name),
     );
+
+    foreach (element_children($module_info[$graph_name]) as $field_name) {
+      $rows[] = array(
+        '&nbsp;',
+        isset($module_info[$graph_name][$field_name]['#label']) ? $module_info[$graph_name][$field_name]['#label'] : t('&lt;missing&gt;'),
+        $module_info[$graph_name][$field_name]['#type'],
+        '&nbsp;',
+        '&nbsp;',
+        );
+    }
   }
+
   $ret = theme('table', $header, $rows);
-  $ret .= '<h3>Munin debug (text-only)</h3><p>'
-    . l(t('Fetch data'), 'munin_api/'. $module)
-    . ' '
-    . l(t('Fetch config'), 'munin_api/'. $module .'/config');
   return $ret;
 }
-

+ 27 - 0
plugins/munin-drupal_

@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Munin plugin using the munin_api module and submodules to log Drupal info.
+#
+# (c) 2011 Ouest Systèmes Informatiques (OSInet)
+#
+# Licensed under the General Public License version 2 or later.
+#
+# This plugin uses CURL to access the Drupal instance over HTTP. For most 
+# plugin modules, this could also work in CLI mode using Drush, and a Drush
+# plugin implementation is a no-brainer. However, in most cases, this will be a 
+# lower performance option, because CLI code is not cached in APC itself, 
+# causing extra server load to fetch the files from disk everytime, whereas they 
+# will normally be cache in APC itself when using HTTP access.
+
+SUB=$(basename $0 | sed s/drupal_/munin_/)
+
+CURL=/usr/bin/curl
+
+
+case $1 in
+  config)
+    $CURL http://$HOST/munin_api/$SUB/config
+    exit 0;;
+  esac
+
+$CURL http://$HOST/munin_api/$SUB