You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2016/11/23 17:00:42 UTC

qpid-dispatch git commit: DISPATCH-553 - From Mick Goulish - Added counters for log source X level. This closes #115.

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master bb4769aec -> cf2431622


DISPATCH-553 - From Mick Goulish - Added counters for log source X level.  This closes #115.


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/cf243162
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/cf243162
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/cf243162

Branch: refs/heads/master
Commit: cf2431622ac1acf44f22b7c01f2168274e211d2a
Parents: bb4769a
Author: Ted Ross <tr...@redhat.com>
Authored: Wed Nov 23 11:58:28 2016 -0500
Committer: Ted Ross <tr...@redhat.com>
Committed: Wed Nov 23 11:58:28 2016 -0500

----------------------------------------------------------------------
 python/qpid_dispatch/management/qdrouter.json   | 35 +++++++++++
 .../qpid_dispatch_internal/management/agent.py  |  8 +++
 src/log.c                                       | 61 +++++++++++++++++++-
 tests/system_tests_qdmanage.py                  | 34 ++++++++++-
 4 files changed, 136 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cf243162/python/qpid_dispatch/management/qdrouter.json
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index 2bd21ac..53b171d 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -845,6 +845,41 @@
             }
         },
 
+        "logStats": {
+            "description": "histogram of the different severity-levels of events on the given log.",
+            "extends": "operationalEntity",
+            "attributes": {
+                "traceCount": {
+                    "description": "How many trace-level events have happened on this log.",
+                    "type": "integer"
+                } ,
+                "debugCount": {
+                    "description": "How many debug-level events have happened on this log.",
+                    "type": "integer"
+                } ,
+                "infoCount": {
+                    "description": "How many info-level events have happened on this log.",
+                    "type": "integer"
+                } ,
+                "noticeCount": {
+                    "description": "How many notice-level events have happened on this log.",
+                    "type": "integer"
+                } ,
+                "warningCount": {
+                    "description": "How many warning-level events have happened on this log.",
+                    "type": "integer"
+                } ,
+                "errorCount": {
+                    "description": "How many error-level events have happened on this log.",
+                    "type": "integer"
+                } ,
+                "criticalCount": {
+                    "description": "How many critical-level events have happened on this log.",
+                    "type": "integer"
+                }
+            }
+        },
+
         "router.config.address": {
             "description": "Entity type for address configuration.  This is used to configure the treatment of message-routed deliveries within a particular address-space.  The configuration controls distribution and address phasing.",
             "extends": "configurationEntity",

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cf243162/python/qpid_dispatch_internal/management/agent.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/agent.py b/python/qpid_dispatch_internal/management/agent.py
index 370dc36..7f50cb8 100644
--- a/python/qpid_dispatch_internal/management/agent.py
+++ b/python/qpid_dispatch_internal/management/agent.py
@@ -515,6 +515,14 @@ class ConnectionEntity(EntityAdapter):
         return super(ConnectionEntity, self).__str__().replace("Entity(", "ConnectionEntity(")
 
 
+class LogStatsEntity(EntityAdapter):
+    def _identifier(self):
+        return self.attributes.get('identity')
+
+    def __str__(self):
+        return super(LogStatsEntity, self).__str__().replace("Entity(", "LogStatsEntity(")
+
+
 class AllocatorEntity(EntityAdapter):
     def _identifier(self):
         return self.attributes.get('typeName')

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cf243162/src/log.c
----------------------------------------------------------------------
diff --git a/src/log.c b/src/log.c
index 3e5aca6..434115f 100644
--- a/src/log.c
+++ b/src/log.c
@@ -21,6 +21,7 @@
 
 #include "log_private.h"
 #include "entity.h"
+#include "entity_cache.h"
 #include "aprintf.h"
 #include <qpid/dispatch/ctools.h>
 #include <qpid/dispatch/dispatch.h>
@@ -37,6 +38,8 @@
 #define LOG_MAX (QD_LOG_TEXT_MAX+128)
 #define LIST_MAX 1000
 
+const char *QD_LOG_STATS_TYPE = "logStats";
+
 static qd_log_source_t      *default_log_source=0;
 static qd_log_source_t      *logging_log_source=0;
 
@@ -149,6 +152,12 @@ static log_sink_t* log_sink_lh(const char* name) {
 }
 
 
+typedef enum {DEFAULT, NONE, TRACE, DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, N_LEVELS} level_index_t;
+#define MIN_VALID_LEVEL_INDEX TRACE
+#define MAX_VALID_LEVEL_INDEX CRITICAL
+#define N_LEVEL_INDICES (MAX_VALID_LEVEL_INDEX - MIN_VALID_LEVEL_INDEX + 1)
+#define LEVEL_INDEX(LEVEL) ((LEVEL) - TRACE)
+
 struct qd_log_source_t {
     DEQ_LINKS(qd_log_source_t);
     char *module;
@@ -157,6 +166,7 @@ struct qd_log_source_t {
     int source;                 /* boolean or -1 means not set */
     bool syslog;
     log_sink_t *sink;
+    uint64_t severity_histogram[N_LEVEL_INDICES];
 };
 
 DEQ_DECLARE(qd_log_source_t, qd_log_source_list_t);
@@ -165,7 +175,6 @@ static sys_mutex_t          *log_lock = 0;
 static sys_mutex_t          *log_source_lock = 0;
 static qd_log_source_list_t  source_list = {0};
 
-typedef enum {DEFAULT, NONE, TRACE, DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, N_LEVELS} level_index_t;
 
 typedef struct level_t {
     const char* name;
@@ -215,6 +224,22 @@ static const level_t* level_for_name(const char *name, int len) {
     return &levels[i];
 }
 
+/*
+  Return -1 and set qd_error if not a valid bit.
+  Translate so that the min valid level index is 0.
+*/
+static int level_index_for_bit(int bit) {
+    level_index_t i = MIN_VALID_LEVEL_INDEX;
+    while ( i <= MAX_VALID_LEVEL_INDEX ) {
+        if ( levels[i].bit == bit )
+            return (int) (i - MIN_VALID_LEVEL_INDEX);
+        ++ i;
+    }
+
+    qd_error(QD_ERROR_CONFIG, "'%d' is not a valid log level bit.", bit);
+    return -1;
+}
+
 /// Return the name of log level or 0 if not found.
 static const char* level_name(int level) {
     return (0 <= level && level < N_LEVELS) ? levels[level].name : NULL;
@@ -304,6 +329,7 @@ static void qd_log_source_defaults(qd_log_source_t *log_source) {
     log_source->timestamp = -1;
     log_source->source = -1;
     log_source->sink = 0;
+    memset ( log_source->severity_histogram, 0, sizeof(uint64_t) * (N_LEVEL_INDICES) );
 }
 
 /// Caller must hold the log_source_lock
@@ -319,6 +345,7 @@ static qd_log_source_t *qd_log_source_lh(const char *module)
         strcpy(log_source->module, module);
         qd_log_source_defaults(log_source);
         DEQ_INSERT_TAIL(source_list, log_source);
+        qd_entity_cache_add(QD_LOG_STATS_TYPE, log_source);
     }
     return log_source;
 }
@@ -355,6 +382,18 @@ bool qd_log_enabled(qd_log_source_t *source, qd_log_level_t level) {
 
 void qd_log_impl(qd_log_source_t *source, qd_log_level_t level, const char *file, int line, const char *fmt, ...)
 {
+    /*-----------------------------------------------
+      Count this log-event in this log's histogram
+      whether or not this log is currently enabled.
+      We can always decide not to look at it later,
+      based on its used/unused status.
+    -----------------------------------------------*/
+    level_index_t level_index = level_index_for_bit(level);
+    if (level_index < 0)
+        qd_error_clear();
+    else
+        source->severity_histogram[level_index]++;
+
     if (!qd_log_enabled(source, level)) return;
 
     qd_log_entry_t *entry = new_qd_log_entry_t();
@@ -508,3 +547,23 @@ qd_error_t qd_log_entity(qd_entity_t *entity) {
 
     return qd_error_code();
 }
+
+
+qd_error_t qd_entity_refresh_logStats(qd_entity_t* entity, void *impl)
+{
+    qd_log_source_t *log = (qd_log_source_t*)impl;
+    char identity_str[TEXT_MAX];
+    snprintf(identity_str, TEXT_MAX - 1,"logStats/%s", log->module);
+
+    qd_entity_set_long(entity,   "traceCount",    log->severity_histogram[LEVEL_INDEX(TRACE)]);
+    qd_entity_set_long(entity,   "debugCount",    log->severity_histogram[LEVEL_INDEX(DEBUG)]);
+    qd_entity_set_long(entity,   "infoCount",     log->severity_histogram[LEVEL_INDEX(INFO)]);
+    qd_entity_set_long(entity,   "noticeCount",   log->severity_histogram[LEVEL_INDEX(NOTICE)]);
+    qd_entity_set_long(entity,   "warningCount",  log->severity_histogram[LEVEL_INDEX(WARNING)]);
+    qd_entity_set_long(entity,   "errorCount",    log->severity_histogram[LEVEL_INDEX(ERROR)]);
+    qd_entity_set_long(entity,   "criticalCount", log->severity_histogram[LEVEL_INDEX(CRITICAL)]);
+    qd_entity_set_string(entity, "name",          log->module);
+    qd_entity_set_string(entity, "identity",      identity_str);
+
+    return QD_ERROR_NONE;
+}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cf243162/tests/system_tests_qdmanage.py
----------------------------------------------------------------------
diff --git a/tests/system_tests_qdmanage.py b/tests/system_tests_qdmanage.py
index 346bd72..0c70e66 100644
--- a/tests/system_tests_qdmanage.py
+++ b/tests/system_tests_qdmanage.py
@@ -178,13 +178,45 @@ class QdmanageTest(TestCase):
 
     def test_get_types(self):
         out = json.loads(self.run_qdmanage("get-types"))
-        self.assertEqual(len(out), 27)
+        self.assertEqual(len(out), 28)
 
     def test_get_log(self):
         log = json.loads(self.run_qdmanage("get-log limit=1"))[0]
         self.assertEquals(['AGENT', 'trace'], log[0:2])
         self.assertRegexpMatches(log[2], 'get-log')
 
+    def test_get_logstats(self):
+        query_command = 'QUERY --type=logStats'
+        logs = json.loads(self.run_qdmanage(query_command))
+        # Each value returned by the above query should be
+        # a log, and each log should contain an entry for each
+        # log level.
+        log_levels = [ 'criticalCount',
+                       'debugCount',
+                       'errorCount',
+                       'infoCount',
+                       'noticeCount',
+                       'traceCount',
+                       'warningCount'
+                     ]
+        n_log_levels = len ( log_levels )
+
+        good_logs = 0
+
+        for log_dict in logs:
+            log_levels_present = 0
+            log_levels_missing = 0
+            for log_level in log_levels:
+                if log_level in log_dict:
+                    log_levels_present += 1
+                else:
+                    log_levels_missing += 1
+            
+            if log_levels_present == n_log_levels:
+                good_logs += 1
+
+        self.assertEquals ( good_logs, len(logs) )
+
     def test_ssl(self):
         """Simple test for SSL connection. Note system_tests_qdstat has a more complete SSL test"""
         url = Url(self.router_1.addresses[1], scheme="amqps")


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org