You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2014/09/11 21:20:52 UTC
git commit: TS-3071: optionally emit JSON numbers in stats_over_http
Repository: trafficserver
Updated Branches:
refs/heads/master a28621e47 -> 454a2e5be
TS-3071: optionally emit JSON numbers in stats_over_http
Add a new option to emit floats, counters and integers and JSON
numbers rather than strings. Since some systems (*cough* Java) don't
deal well with uint64_t, add another option to wrap integers and
counters to int64_t.
This closes #100.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/454a2e5b
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/454a2e5b
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/454a2e5b
Branch: refs/heads/master
Commit: 454a2e5be5e012bbf6080794edbae8bce7fbf354
Parents: a28621e
Author: James Peach <jp...@apache.org>
Authored: Thu Sep 11 09:30:33 2014 -0700
Committer: James Peach <jp...@apache.org>
Committed: Thu Sep 11 12:20:39 2014 -0700
----------------------------------------------------------------------
CHANGES | 3 +
doc/reference/plugins/stats_over_http.en.rst | 22 +++++-
plugins/stats_over_http/stats_over_http.c | 85 ++++++++++++++++++-----
3 files changed, 90 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/454a2e5b/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 64abe0f..0a2c782 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache Traffic Server 5.2.0
+ *) [TS-3071] Optionally emit JSON numbers in stats_over_http.
+ Thanks to Saltuk Alakus <sa...@gmail.com>
+
*) [TS-3069] Add mysql_remap to autoconf
*) [TS-3066] Fix various build issues for OmniOS, broken since 5.0.x.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/454a2e5b/doc/reference/plugins/stats_over_http.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/plugins/stats_over_http.en.rst b/doc/reference/plugins/stats_over_http.en.rst
index 89ec970..59ba7fc 100644
--- a/doc/reference/plugins/stats_over_http.en.rst
+++ b/doc/reference/plugins/stats_over_http.en.rst
@@ -35,10 +35,26 @@ default URL::
http://host:port/_stats
+where host and port is the hostname/IP and port number of the server.
-where host and port is the hostname/IP and port number of the server. You can
-optionally modify the path to use, and this is highly recommended in a public
-facing server. For example::
+Plugin Options
+--------------
+
+.. option:: --integer-counters
+
+This option causes the plugin to emit floating point and integral
+metric values as JSON numbers, rather then JSON strings. This can
+cause interoperability problems since integer metrics have a 64-bit
+unsigned range.
+
+.. option:: --wrap-counters
+
+This option wraps 64-bit unsigned values to the 64-bit signed range.
+This aids interoperability with Java, since prior to the Java SE 8
+release, Java did not have a 64-bit unsigned type.
+
+You can optionally modify the path to use, and this is highly
+recommended in a public facing server. For example::
stats_over_http.so 81c075bc0cca1435ea899ba4ad72766b
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/454a2e5b/plugins/stats_over_http/stats_over_http.c
----------------------------------------------------------------------
diff --git a/plugins/stats_over_http/stats_over_http.c b/plugins/stats_over_http/stats_over_http.c
index 7e6071a..96fb63a 100644
--- a/plugins/stats_over_http/stats_over_http.c
+++ b/plugins/stats_over_http/stats_over_http.c
@@ -26,19 +26,25 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <ctype.h>
#include <limits.h>
#include <ts/ts.h>
#include <string.h>
-
#include <inttypes.h>
+#include <getopt.h>
#include "ink_defs.h"
+#define PLUGIN_NAME "stats_over_http"
+
/* global holding the path used for access to this JSON data */
static const char* url_path = "_stats";
static int url_path_len;
+static bool integer_counters = false;
+static bool wrap_counters = false;
+
typedef struct stats_state_t
{
TSVConn net_vc;
@@ -102,7 +108,7 @@ stats_add_resp_header(stats_state * my_state)
static void
stats_process_read(TSCont contp, TSEvent event, stats_state * my_state)
{
- TSDebug("istats", "stats_process_read(%d)", event);
+ TSDebug(PLUGIN_NAME, "stats_process_read(%d)", event);
if (event == TS_EVENT_VCONN_READ_READY) {
my_state->output_bytes = stats_add_resp_header(my_state);
TSVConnShutdown(my_state->net_vc, 1, 0);
@@ -126,6 +132,26 @@ stats_process_read(TSCont contp, TSEvent event, stats_state * my_state)
if(snprintf(b, sizeof(b), "\"%s\": \"" fmt "\",\n", a, v) < sizeof(b)) \
APPEND(b); \
} while(0)
+#define APPEND_STAT_NUMERIC(a, fmt, v) do { \
+ char b[256]; \
+ if (integer_counters) { \
+ if (snprintf(b, sizeof(b), "\"%s\": " fmt ",\n", a, v) < sizeof(b)) { APPEND(b); } \
+ } else { \
+ if (snprintf(b, sizeof(b), "\"%s\": \"" fmt "\",\n", a, v) < sizeof(b)) { APPEND(b); } \
+ } \
+} while(0)
+
+// This wraps uint64_t values to the int64_t range to fit into a Java long. Java 8 has an unsigned long which
+// can interoperate with a full uint64_t, but it's unlikely that much of the ecosystem supports that yet.
+static uint64_t
+wrap_unsigned_counter(uint64_t value)
+{
+ if (wrap_counters) {
+ return (value > INT64_MAX) ? value % INT64_MAX : value;
+ } else {
+ return value;
+ }
+}
static void
json_out_stat(TSRecordType rec_type ATS_UNUSED, void *edata, int registered ATS_UNUSED,
@@ -135,15 +161,15 @@ json_out_stat(TSRecordType rec_type ATS_UNUSED, void *edata, int registered ATS_
switch(data_type) {
case TS_RECORDDATATYPE_COUNTER:
- APPEND_STAT(name, "%" PRIu64, datum->rec_counter); break;
+ APPEND_STAT_NUMERIC(name, "%" PRIu64, wrap_unsigned_counter(datum->rec_counter)); break;
case TS_RECORDDATATYPE_INT:
- APPEND_STAT(name, "%" PRIu64, datum->rec_int); break;
+ APPEND_STAT_NUMERIC(name, "%" PRIu64, wrap_unsigned_counter(datum->rec_int)); break;
case TS_RECORDDATATYPE_FLOAT:
- APPEND_STAT(name, "%f", datum->rec_float); break;
+ APPEND_STAT_NUMERIC(name, "%f", datum->rec_float); break;
case TS_RECORDDATATYPE_STRING:
APPEND_STAT(name, "%s", datum->rec_string); break;
default:
- TSDebug("istats", "unknown type for %s: %d", name, data_type);
+ TSDebug(PLUGIN_NAME, "unknown type for %s: %d", name, data_type);
break;
}
}
@@ -166,7 +192,7 @@ stats_process_write(TSCont contp, TSEvent event, stats_state * my_state)
{
if (event == TS_EVENT_VCONN_WRITE_READY) {
if (my_state->body_written == 0) {
- TSDebug("istats", "plugin adding response body");
+ TSDebug(PLUGIN_NAME, "plugin adding response body");
my_state->body_written = 1;
json_out_stats(my_state);
TSVIONBytesSet(my_state->write_vio, my_state->output_bytes);
@@ -208,7 +234,7 @@ stats_origin(TSCont contp ATS_UNUSED, TSEvent event ATS_UNUSED, void *edata)
TSMLoc hdr_loc = NULL, url_loc = NULL;
TSEvent reenable = TS_EVENT_HTTP_CONTINUE;
- TSDebug("istats", "in the read stuff");
+ TSDebug(PLUGIN_NAME, "in the read stuff");
if (TSHttpTxnClientReqGet(txnp, &reqp, &hdr_loc) != TS_SUCCESS)
goto cleanup;
@@ -218,7 +244,7 @@ stats_origin(TSCont contp ATS_UNUSED, TSEvent event ATS_UNUSED, void *edata)
int path_len = 0;
const char* path = TSUrlPathGet(reqp,url_loc,&path_len);
- TSDebug("istats","Path: %.*s",path_len,path);
+ TSDebug(PLUGIN_NAME, "Path: %.*s", path_len,path);
if (! (path_len != 0 && path_len == url_path_len && !memcmp(path,url_path,url_path_len)) ) {
goto notforme;
@@ -227,7 +253,7 @@ stats_origin(TSCont contp ATS_UNUSED, TSEvent event ATS_UNUSED, void *edata)
TSSkipRemappingSet(txnp,1); //not strictly necessary, but speed is everything these days
/* This is us -- register our intercept */
- TSDebug("istats", "Intercepting request");
+ TSDebug(PLUGIN_NAME, "Intercepting request");
icontp = TSContCreate(stats_dostuff, TSMutexCreate());
my_state = (stats_state *) TSmalloc(sizeof(*my_state));
@@ -239,9 +265,6 @@ stats_origin(TSCont contp ATS_UNUSED, TSEvent event ATS_UNUSED, void *edata)
notforme:
cleanup:
-#if (TS_VERSION_NUMBER < 2001005)
- if(path) TSHandleStringRelease(reqp, url_loc, path);
-#endif
if(url_loc) TSHandleMLocRelease(reqp, hdr_loc, url_loc);
if(hdr_loc) TSHandleMLocRelease(reqp, TS_NULL_MLOC, hdr_loc);
@@ -254,12 +277,40 @@ TSPluginInit(int argc, const char *argv[])
{
TSPluginRegistrationInfo info;
- info.plugin_name = "stats";
+ static const char usage[] = PLUGIN_NAME ".so [--integer-counters] [PATH]";
+ static const struct option longopts[] = {
+ { (char *)("integer-counters"), required_argument, NULL, 'i' },
+ { (char *)("wrap-counters"), required_argument, NULL, 'w' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ info.plugin_name = PLUGIN_NAME;
info.vendor_name = "Apache Software Foundation";
info.support_email = "dev@trafficserver.apache.org";
- if (TSPluginRegister(TS_SDK_VERSION_2_0, &info) != TS_SUCCESS)
- TSError("Plugin registration failed. \n");
+ if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+ TSError("[%s] registration failed", PLUGIN_NAME);
+ }
+
+ optind = 0;
+ for (;;) {
+ switch (getopt_long(argc, (char * const *)argv, "i", longopts, NULL)) {
+ case 'i':
+ integer_counters = true;
+ break;
+ case 'i':
+ wrap_counters = true;
+ break;
+ case -1:
+ goto init;
+ default:
+ TSError("[%s] usage: %s", PLUGIN_NAME, usage);
+ }
+ }
+
+init:
+ argc -= optind;
+ argv += optind;
if (argc > 1) {
url_path = TSstrdup(argv[1] + ('/' == argv[1][0] ? 1 : 0)); /* Skip leading / */
@@ -269,5 +320,5 @@ TSPluginInit(int argc, const char *argv[])
/* Create a continuation with a mutex as there is a shared global structure
containing the headers to add */
TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(stats_origin, NULL));
- TSDebug("istats", "stats module registered");
+ TSDebug(PLUGIN_NAME, "stats module registered");
}