You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by so...@apache.org on 2013/10/20 21:23:20 UTC
git commit: TS-2291: Add remap_state plugin to experimental.
Updated Branches:
refs/heads/master 2c3f7c5e9 -> c3518560e
TS-2291: Add remap_state plugin to experimental.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/c3518560
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/c3518560
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/c3518560
Branch: refs/heads/master
Commit: c3518560e3ca80b870cd24a99b1bb54179cfa980
Parents: 2c3f7c5
Author: Phil Sorber <so...@apache.org>
Authored: Sun Oct 20 13:22:56 2013 -0600
Committer: Phil Sorber <so...@apache.org>
Committed: Sun Oct 20 13:22:56 2013 -0600
----------------------------------------------------------------------
CHANGES | 2 +
NOTICE | 8 +-
configure.ac | 1 +
plugins/experimental/Makefile.am | 3 +-
plugins/experimental/remap_stats/Makefile.am | 21 ++
plugins/experimental/remap_stats/remap_stats.c | 329 ++++++++++++++++++++
6 files changed, 362 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 1446547..30c1354 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
-*- coding: utf-8 -*-
Changes with Apache Traffic Server 4.1.0
+ *) [TS-2291] Add remap_state plugin to experimental.
+
*) [TS-2242] Update core plugins' support_email and vendor_name for
consistency.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
index b486b5e..55084b6 100644
--- a/NOTICE
+++ b/NOTICE
@@ -6,6 +6,7 @@ This product includes software developed at
- Yahoo! Inc
- Network Geographics (http://network-geographics.com)
- OmniTI
+ - Comcast
~~~
@@ -42,4 +43,9 @@ Copyright (C) 2012 GoDaddy.
~~~
lib/atscppapi developed by LinkedIn
-Copyright (c) 2013 LinkedIn
\ No newline at end of file
+Copyright (c) 2013 LinkedIn
+
+~~~
+
+remap_stats plugin developed by Comcast.
+Copyright (C) 2013 Comcast
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index bb2f373..439a6e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1896,6 +1896,7 @@ AC_CONFIG_FILES([
plugins/experimental/spdy/Makefile
plugins/experimental/tcp_info/Makefile
plugins/experimental/healthchecks/Makefile
+ plugins/experimental/remap_stats/Makefile
plugins/gzip/Makefile
plugins/libloader/Makefile
plugins/header_filter/Makefile
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/Makefile.am
----------------------------------------------------------------------
diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am
index bb97af1..eb807f8 100644
--- a/plugins/experimental/Makefile.am
+++ b/plugins/experimental/Makefile.am
@@ -27,5 +27,6 @@ SUBDIRS = \
channel_stats \
authproxy \
geoip_acl \
- healthchecks
+ healthchecks \
+ remap_stats
endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/remap_stats/Makefile.am
----------------------------------------------------------------------
diff --git a/plugins/experimental/remap_stats/Makefile.am b/plugins/experimental/remap_stats/Makefile.am
new file mode 100644
index 0000000..4033fa4
--- /dev/null
+++ b/plugins/experimental/remap_stats/Makefile.am
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+include $(top_srcdir)/build/plugins.mk
+
+pkglib_LTLIBRARIES = remap_stats.la
+remap_stats_la_SOURCES = remap_stats.c
+remap_stats_la_LDFLAGS = $(TS_PLUGIN_LDFLAGS)
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/remap_stats/remap_stats.c
----------------------------------------------------------------------
diff --git a/plugins/experimental/remap_stats/remap_stats.c b/plugins/experimental/remap_stats/remap_stats.c
new file mode 100644
index 0000000..23c93cd
--- /dev/null
+++ b/plugins/experimental/remap_stats/remap_stats.c
@@ -0,0 +1,329 @@
+/** @file
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "ink_config.h"
+#include "ink_defs.h"
+
+#include "ts/ts.h"
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <search.h>
+
+#define PLUGIN_NAME "remap_stats"
+#define DEBUG_TAG PLUGIN_NAME
+
+typedef struct
+{
+ bool post_remap_host;
+ int txn_slot;
+ TSStatPersistence persist_type;
+ TSMutex stat_creation_mutex;
+} config_t;
+
+typedef struct
+{
+ char *hostname;
+ bool remap_success;
+} txn_data_t;
+
+static void
+stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
+{
+ int stat_id = -1, *statp;
+ ENTRY search, *result = NULL;
+ static __thread struct hsearch_data stat_cache;
+ static __thread bool hash_init = false;
+
+ if (unlikely(!hash_init))
+ {
+ hcreate_r(TS_MAX_API_STATS << 1, &stat_cache);
+ hash_init = true;
+ TSDebug(DEBUG_TAG, "stat cache hash init");
+ }
+
+ search.key = name;
+ hsearch_r(search, FIND, &result, &stat_cache);
+
+ if (unlikely(result == NULL))
+ {
+ // This is an unlikely path because we most likely have the stat cached
+ // so this mutex won't be much overhead and it fixes a race condition
+ // in the RecCore. Hopefully this can be removed in the future.
+ TSMutexLock(create_mutex);
+ if (TS_ERROR == TSStatFindName((const char *) name, &stat_id))
+ {
+ stat_id = TSStatCreate((const char *) name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
+ if (stat_id == TS_ERROR)
+ TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
+ else
+ TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
+ }
+ TSMutexUnlock(create_mutex);
+
+ search.key = TSstrdup(name);
+ statp = TSmalloc(sizeof(int));
+ *statp = stat_id;
+ search.data = (void *) statp;
+ hsearch_r(search, ENTER, &result, &stat_cache);
+ TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
+ }
+ else
+ stat_id = *((int *) result->data);
+
+ if (likely(stat_id >= 0))
+ TSStatIntIncrement(stat_id, amount);
+ else
+ TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
+}
+
+static char *
+get_effective_host(TSHttpTxn txn)
+{
+ char *effective_url, *tmp;
+ const char *host;
+ int len;
+ TSMBuffer buf;
+ TSMLoc url_loc;
+
+ effective_url = TSHttpTxnEffectiveUrlStringGet(txn, &len);
+ buf = TSMBufferCreate();
+ TSUrlCreate(buf, &url_loc);
+ tmp = effective_url;
+ TSUrlParse(buf, url_loc, (const char **) (&tmp), (const char *) (effective_url + len));
+ TSfree(effective_url);
+ host = TSUrlHostGet(buf, url_loc, &len);
+ tmp = TSstrndup(host, len);
+ TSHandleMLocRelease(buf, TS_NULL_MLOC, url_loc);
+ TSMBufferDestroy(buf);
+ return tmp;
+}
+
+static char *
+create_stat_name(char *hostname, char *basename)
+{
+ char *stat_name;
+ size_t stat_len;
+
+ stat_len = strlen(hostname) + strlen(basename) + strlen(PLUGIN_NAME) + 3 + strlen("plugin.");
+ stat_name = TSmalloc(stat_len * sizeof(char));
+ snprintf(stat_name, stat_len, "plugin.%s.%s.%s", PLUGIN_NAME, hostname, basename);
+ return stat_name;
+}
+
+static int
+handle_read_req_hdr(TSCont cont, TSEvent event, void *edata)
+{
+ TSHttpTxn txn = (TSHttpTxn) edata;
+ config_t *config;
+ txn_data_t *txnd;
+
+ config = (config_t *) TSContDataGet(cont);
+ txnd = TSmalloc(sizeof(txn_data_t));
+ txnd->remap_success = false;
+ txnd->hostname = get_effective_host(txn);
+ TSHttpTxnArgSet(txn, config->txn_slot, (void *) txnd);
+
+ TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+ TSDebug(DEBUG_TAG, "Read Req Handler Finished");
+ return 0;
+}
+
+static int
+handle_post_remap(TSCont cont, TSEvent event, void *edata)
+{
+ TSHttpTxn txn = (TSHttpTxn) edata;
+ config_t *config;
+ txn_data_t *txnd;
+
+ config = (config_t *) TSContDataGet(cont);
+
+ if (config->post_remap_host)
+ {
+ txnd = TSmalloc(sizeof(txn_data_t));
+ txnd->remap_success = true;
+ txnd->hostname = NULL;
+ TSHttpTxnArgSet(txn, config->txn_slot, (void *) txnd);
+ }
+ else
+ {
+ txnd = (txn_data_t *) TSHttpTxnArgGet(txn, config->txn_slot);
+ txnd->remap_success = true;
+ }
+
+ TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+ TSDebug(DEBUG_TAG, "Post Remap Handler Finished");
+ return 0;
+}
+
+static int
+handle_txn_close(TSCont cont, TSEvent event, void *edata)
+{
+ TSHttpTxn txn = (TSHttpTxn) edata;
+ config_t *config;
+ txn_data_t *txnd;
+ TSHttpStatus status_code = 0;
+ TSMBuffer buf;
+ TSMLoc hdr_loc;
+ uint64_t out_bytes, in_bytes;
+ char *remap, *stat_name;
+
+ config = (config_t *) TSContDataGet(cont);
+ txnd = (txn_data_t *) TSHttpTxnArgGet(txn, config->txn_slot);
+
+ if (txnd)
+ {
+ if (txnd->remap_success)
+ {
+ if (!config->post_remap_host)
+ remap = txnd->hostname;
+ else
+ remap = get_effective_host(txn);
+
+ if (!remap)
+ remap = TSstrdup("unknown");
+
+ in_bytes = TSHttpTxnClientReqHdrBytesGet(txn);
+ in_bytes += TSHttpTxnClientReqBodyBytesGet(txn);
+
+ stat_name = create_stat_name(remap, "in_bytes");
+ stat_add(stat_name, (TSMgmtInt) in_bytes, config->persist_type, config->stat_creation_mutex);
+ TSfree(stat_name);
+
+ out_bytes = TSHttpTxnClientRespHdrBytesGet(txn);
+ out_bytes += TSHttpTxnClientRespBodyBytesGet(txn);
+
+ stat_name = create_stat_name(remap, "out_bytes");
+ stat_add(stat_name, (TSMgmtInt) out_bytes, config->persist_type, config->stat_creation_mutex);
+ TSfree(stat_name);
+
+ if (TSHttpTxnClientRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS)
+ {
+ status_code = TSHttpHdrStatusGet(buf, hdr_loc);
+ TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);
+
+ if ((status_code >= 200) && (status_code <= 299))
+ stat_name = create_stat_name(remap, "status_2xx");
+ else if ((status_code >= 300) && (status_code <= 399))
+ stat_name = create_stat_name(remap, "status_3xx");
+ else if ((status_code >= 400) && (status_code <= 499))
+ stat_name = create_stat_name(remap, "status_4xx");
+ else if ((status_code >= 500) && (status_code <= 599))
+ stat_name = create_stat_name(remap, "status_5xx");
+ else
+ stat_name = create_stat_name(remap, "status_other");
+
+ stat_add(stat_name, 1, config->persist_type, config->stat_creation_mutex);
+ TSfree(stat_name);
+ }
+ else
+ {
+ stat_name = create_stat_name(remap, "status_unknown");
+ stat_add(stat_name, 1, config->persist_type, config->stat_creation_mutex);
+ TSfree(stat_name);
+ }
+
+ TSfree(remap);
+
+ }
+ else if (txnd->hostname)
+ TSfree(txnd->hostname);
+
+ TSfree(txnd);
+ }
+
+ TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+ TSDebug(DEBUG_TAG, "Handler Finished");
+ return 0;
+}
+
+void
+TSPluginInit (int argc, const char *argv[])
+{
+ TSPluginRegistrationInfo info;
+ TSCont pre_remap_cont, post_remap_cont, global_cont;
+ config_t *config;
+
+ info.plugin_name = PLUGIN_NAME;
+ info.vendor_name = "Apache Software Foundation";
+ info.support_email = "dev@trafficserver.apache.org";
+
+ if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS)
+ {
+ TSError("Plugin registration failed.");
+ return;
+ }
+ else
+ TSDebug(DEBUG_TAG, "Plugin registration succeeded.");
+
+ config = TSmalloc(sizeof(config_t));
+ config->post_remap_host = false;
+ config->persist_type = TS_STAT_NON_PERSISTENT;
+ config->stat_creation_mutex = TSMutexCreate();
+
+ if (argc > 1)
+ {
+ int c;
+ optind = 1;
+ static const struct option longopts[] = {
+ { "post-remap-host", no_argument, NULL, 'P' },
+ { "persistent", no_argument, NULL, 'p' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, (char * const*) argv, "Pp", longopts, NULL)) != -1)
+ {
+ switch (c)
+ {
+ case 'P':
+ config->post_remap_host = true;
+ TSDebug(DEBUG_TAG, "Using post remap hostname");
+ break;
+ case 'p':
+ config->persist_type = TS_STAT_PERSISTENT;
+ TSDebug(DEBUG_TAG, "Using persistent stats");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ TSHttpArgIndexReserve(PLUGIN_NAME, "txn data", &(config->txn_slot));
+
+ if (!config->post_remap_host)
+ {
+ pre_remap_cont = TSContCreate(handle_read_req_hdr, NULL);
+ TSContDataSet(pre_remap_cont, (void *) config);
+ TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, pre_remap_cont);
+ }
+
+ post_remap_cont = TSContCreate(handle_post_remap, NULL);
+ TSContDataSet(post_remap_cont, (void *) config);
+ TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, post_remap_cont);
+
+ global_cont = TSContCreate(handle_txn_close, NULL);
+ TSContDataSet(global_cont, (void *) config);
+ TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_cont);
+
+ TSDebug(DEBUG_TAG, "Init complete");
+}
Re: git commit: TS-2291: Add remap_state plugin to experimental.
Posted by James Peach <jp...@apache.org>.
Hi Phil,
- please check jenkins, this is broken on a couple of platforms
- any chance of documentation for this?
- do you have a plan to resolve this plugin with channel_stats?
On Oct 20, 2013, at 12:23 PM, sorber@apache.org wrote:
> Updated Branches:
> refs/heads/master 2c3f7c5e9 -> c3518560e
>
>
> TS-2291: Add remap_state plugin to experimental.
>
>
> Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
> Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/c3518560
> Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/c3518560
> Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/c3518560
>
> Branch: refs/heads/master
> Commit: c3518560e3ca80b870cd24a99b1bb54179cfa980
> Parents: 2c3f7c5
> Author: Phil Sorber <so...@apache.org>
> Authored: Sun Oct 20 13:22:56 2013 -0600
> Committer: Phil Sorber <so...@apache.org>
> Committed: Sun Oct 20 13:22:56 2013 -0600
>
> ----------------------------------------------------------------------
> CHANGES | 2 +
> NOTICE | 8 +-
> configure.ac | 1 +
> plugins/experimental/Makefile.am | 3 +-
> plugins/experimental/remap_stats/Makefile.am | 21 ++
> plugins/experimental/remap_stats/remap_stats.c | 329 ++++++++++++++++++++
> 6 files changed, 362 insertions(+), 2 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/CHANGES
> ----------------------------------------------------------------------
> diff --git a/CHANGES b/CHANGES
> index 1446547..30c1354 100644
> --- a/CHANGES
> +++ b/CHANGES
> @@ -1,6 +1,8 @@
> -*- coding: utf-8 -*-
> Changes with Apache Traffic Server 4.1.0
>
> + *) [TS-2291] Add remap_state plugin to experimental.
> +
> *) [TS-2242] Update core plugins' support_email and vendor_name for
> consistency.
>
>
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/NOTICE
> ----------------------------------------------------------------------
> diff --git a/NOTICE b/NOTICE
> index b486b5e..55084b6 100644
> --- a/NOTICE
> +++ b/NOTICE
> @@ -6,6 +6,7 @@ This product includes software developed at
> - Yahoo! Inc
> - Network Geographics (http://network-geographics.com)
> - OmniTI
> + - Comcast
>
> ~~~
>
> @@ -42,4 +43,9 @@ Copyright (C) 2012 GoDaddy.
> ~~~
>
> lib/atscppapi developed by LinkedIn
> -Copyright (c) 2013 LinkedIn
> \ No newline at end of file
> +Copyright (c) 2013 LinkedIn
> +
> +~~~
> +
> +remap_stats plugin developed by Comcast.
> +Copyright (C) 2013 Comcast
>
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/configure.ac
> ----------------------------------------------------------------------
> diff --git a/configure.ac b/configure.ac
> index bb2f373..439a6e1 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1896,6 +1896,7 @@ AC_CONFIG_FILES([
> plugins/experimental/spdy/Makefile
> plugins/experimental/tcp_info/Makefile
> plugins/experimental/healthchecks/Makefile
> + plugins/experimental/remap_stats/Makefile
> plugins/gzip/Makefile
> plugins/libloader/Makefile
> plugins/header_filter/Makefile
>
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/Makefile.am
> ----------------------------------------------------------------------
> diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am
> index bb97af1..eb807f8 100644
> --- a/plugins/experimental/Makefile.am
> +++ b/plugins/experimental/Makefile.am
> @@ -27,5 +27,6 @@ SUBDIRS = \
> channel_stats \
> authproxy \
> geoip_acl \
> - healthchecks
> + healthchecks \
> + remap_stats
> endif
>
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/remap_stats/Makefile.am
> ----------------------------------------------------------------------
> diff --git a/plugins/experimental/remap_stats/Makefile.am b/plugins/experimental/remap_stats/Makefile.am
> new file mode 100644
> index 0000000..4033fa4
> --- /dev/null
> +++ b/plugins/experimental/remap_stats/Makefile.am
> @@ -0,0 +1,21 @@
> +# Licensed to the Apache Software Foundation (ASF) under one
> +# or more contributor license agreements. See the NOTICE file
> +# distributed with this work for additional information
> +# regarding copyright ownership. The ASF licenses this file
> +# to you under the Apache License, Version 2.0 (the
> +# "License"); you may not use this file except in compliance
> +# with the License. You may obtain a copy of the License at
> +#
> +# http://www.apache.org/licenses/LICENSE-2.0
> +#
> +# Unless required by applicable law or agreed to in writing, software
> +# distributed under the License is distributed on an "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +# See the License for the specific language governing permissions and
> +# limitations under the License.
> +
> +include $(top_srcdir)/build/plugins.mk
> +
> +pkglib_LTLIBRARIES = remap_stats.la
> +remap_stats_la_SOURCES = remap_stats.c
> +remap_stats_la_LDFLAGS = $(TS_PLUGIN_LDFLAGS)
>
> http://git-wip-us.apache.org/repos/asf/trafficserver/blob/c3518560/plugins/experimental/remap_stats/remap_stats.c
> ----------------------------------------------------------------------
> diff --git a/plugins/experimental/remap_stats/remap_stats.c b/plugins/experimental/remap_stats/remap_stats.c
> new file mode 100644
> index 0000000..23c93cd
> --- /dev/null
> +++ b/plugins/experimental/remap_stats/remap_stats.c
> @@ -0,0 +1,329 @@
> +/** @file
> +
> + @section license License
> +
> + Licensed to the Apache Software Foundation (ASF) under one
> + or more contributor license agreements. See the NOTICE file
> + distributed with this work for additional information
> + regarding copyright ownership. The ASF licenses this file
> + to you under the Apache License, Version 2.0 (the
> + "License"); you may not use this file except in compliance
> + with the License. You may obtain a copy of the License at
> +
> + http://www.apache.org/licenses/LICENSE-2.0
> +
> + Unless required by applicable law or agreed to in writing, software
> + distributed under the License is distributed on an "AS IS" BASIS,
> + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + See the License for the specific language governing permissions and
> + limitations under the License.
> + */
> +
> +#include "ink_config.h"
> +#include "ink_defs.h"
> +
> +#include "ts/ts.h"
> +#include <stdbool.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <getopt.h>
> +#include <search.h>
> +
> +#define PLUGIN_NAME "remap_stats"
> +#define DEBUG_TAG PLUGIN_NAME
> +
> +typedef struct
> +{
> + bool post_remap_host;
> + int txn_slot;
> + TSStatPersistence persist_type;
> + TSMutex stat_creation_mutex;
> +} config_t;
> +
> +typedef struct
> +{
> + char *hostname;
> + bool remap_success;
> +} txn_data_t;
> +
> +static void
> +stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
> +{
> + int stat_id = -1, *statp;
> + ENTRY search, *result = NULL;
> + static __thread struct hsearch_data stat_cache;
> + static __thread bool hash_init = false;
> +
> + if (unlikely(!hash_init))
> + {
> + hcreate_r(TS_MAX_API_STATS << 1, &stat_cache);
> + hash_init = true;
> + TSDebug(DEBUG_TAG, "stat cache hash init");
> + }
> +
> + search.key = name;
> + hsearch_r(search, FIND, &result, &stat_cache);
> +
> + if (unlikely(result == NULL))
> + {
> + // This is an unlikely path because we most likely have the stat cached
> + // so this mutex won't be much overhead and it fixes a race condition
> + // in the RecCore. Hopefully this can be removed in the future.
> + TSMutexLock(create_mutex);
> + if (TS_ERROR == TSStatFindName((const char *) name, &stat_id))
> + {
> + stat_id = TSStatCreate((const char *) name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
> + if (stat_id == TS_ERROR)
> + TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
> + else
> + TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
> + }
> + TSMutexUnlock(create_mutex);
> +
> + search.key = TSstrdup(name);
> + statp = TSmalloc(sizeof(int));
> + *statp = stat_id;
> + search.data = (void *) statp;
> + hsearch_r(search, ENTER, &result, &stat_cache);
> + TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
> + }
> + else
> + stat_id = *((int *) result->data);
> +
> + if (likely(stat_id >= 0))
> + TSStatIntIncrement(stat_id, amount);
> + else
> + TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
> +}
> +
> +static char *
> +get_effective_host(TSHttpTxn txn)
> +{
> + char *effective_url, *tmp;
> + const char *host;
> + int len;
> + TSMBuffer buf;
> + TSMLoc url_loc;
> +
> + effective_url = TSHttpTxnEffectiveUrlStringGet(txn, &len);
> + buf = TSMBufferCreate();
> + TSUrlCreate(buf, &url_loc);
> + tmp = effective_url;
> + TSUrlParse(buf, url_loc, (const char **) (&tmp), (const char *) (effective_url + len));
> + TSfree(effective_url);
> + host = TSUrlHostGet(buf, url_loc, &len);
> + tmp = TSstrndup(host, len);
> + TSHandleMLocRelease(buf, TS_NULL_MLOC, url_loc);
> + TSMBufferDestroy(buf);
> + return tmp;
> +}
> +
> +static char *
> +create_stat_name(char *hostname, char *basename)
> +{
> + char *stat_name;
> + size_t stat_len;
> +
> + stat_len = strlen(hostname) + strlen(basename) + strlen(PLUGIN_NAME) + 3 + strlen("plugin.");
> + stat_name = TSmalloc(stat_len * sizeof(char));
> + snprintf(stat_name, stat_len, "plugin.%s.%s.%s", PLUGIN_NAME, hostname, basename);
> + return stat_name;
> +}
> +
> +static int
> +handle_read_req_hdr(TSCont cont, TSEvent event, void *edata)
> +{
> + TSHttpTxn txn = (TSHttpTxn) edata;
> + config_t *config;
> + txn_data_t *txnd;
> +
> + config = (config_t *) TSContDataGet(cont);
> + txnd = TSmalloc(sizeof(txn_data_t));
> + txnd->remap_success = false;
> + txnd->hostname = get_effective_host(txn);
> + TSHttpTxnArgSet(txn, config->txn_slot, (void *) txnd);
> +
> + TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
> + TSDebug(DEBUG_TAG, "Read Req Handler Finished");
> + return 0;
> +}
> +
> +static int
> +handle_post_remap(TSCont cont, TSEvent event, void *edata)
> +{
> + TSHttpTxn txn = (TSHttpTxn) edata;
> + config_t *config;
> + txn_data_t *txnd;
> +
> + config = (config_t *) TSContDataGet(cont);
> +
> + if (config->post_remap_host)
> + {
> + txnd = TSmalloc(sizeof(txn_data_t));
> + txnd->remap_success = true;
> + txnd->hostname = NULL;
> + TSHttpTxnArgSet(txn, config->txn_slot, (void *) txnd);
> + }
> + else
> + {
> + txnd = (txn_data_t *) TSHttpTxnArgGet(txn, config->txn_slot);
> + txnd->remap_success = true;
> + }
> +
> + TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
> + TSDebug(DEBUG_TAG, "Post Remap Handler Finished");
> + return 0;
> +}
> +
> +static int
> +handle_txn_close(TSCont cont, TSEvent event, void *edata)
> +{
> + TSHttpTxn txn = (TSHttpTxn) edata;
> + config_t *config;
> + txn_data_t *txnd;
> + TSHttpStatus status_code = 0;
> + TSMBuffer buf;
> + TSMLoc hdr_loc;
> + uint64_t out_bytes, in_bytes;
> + char *remap, *stat_name;
> +
> + config = (config_t *) TSContDataGet(cont);
> + txnd = (txn_data_t *) TSHttpTxnArgGet(txn, config->txn_slot);
> +
> + if (txnd)
> + {
> + if (txnd->remap_success)
> + {
> + if (!config->post_remap_host)
> + remap = txnd->hostname;
> + else
> + remap = get_effective_host(txn);
> +
> + if (!remap)
> + remap = TSstrdup("unknown");
> +
> + in_bytes = TSHttpTxnClientReqHdrBytesGet(txn);
> + in_bytes += TSHttpTxnClientReqBodyBytesGet(txn);
> +
> + stat_name = create_stat_name(remap, "in_bytes");
> + stat_add(stat_name, (TSMgmtInt) in_bytes, config->persist_type, config->stat_creation_mutex);
> + TSfree(stat_name);
> +
> + out_bytes = TSHttpTxnClientRespHdrBytesGet(txn);
> + out_bytes += TSHttpTxnClientRespBodyBytesGet(txn);
> +
> + stat_name = create_stat_name(remap, "out_bytes");
> + stat_add(stat_name, (TSMgmtInt) out_bytes, config->persist_type, config->stat_creation_mutex);
> + TSfree(stat_name);
> +
> + if (TSHttpTxnClientRespGet(txn, &buf, &hdr_loc) == TS_SUCCESS)
> + {
> + status_code = TSHttpHdrStatusGet(buf, hdr_loc);
> + TSHandleMLocRelease(buf, TS_NULL_MLOC, hdr_loc);
> +
> + if ((status_code >= 200) && (status_code <= 299))
> + stat_name = create_stat_name(remap, "status_2xx");
> + else if ((status_code >= 300) && (status_code <= 399))
> + stat_name = create_stat_name(remap, "status_3xx");
> + else if ((status_code >= 400) && (status_code <= 499))
> + stat_name = create_stat_name(remap, "status_4xx");
> + else if ((status_code >= 500) && (status_code <= 599))
> + stat_name = create_stat_name(remap, "status_5xx");
> + else
> + stat_name = create_stat_name(remap, "status_other");
> +
> + stat_add(stat_name, 1, config->persist_type, config->stat_creation_mutex);
> + TSfree(stat_name);
> + }
> + else
> + {
> + stat_name = create_stat_name(remap, "status_unknown");
> + stat_add(stat_name, 1, config->persist_type, config->stat_creation_mutex);
> + TSfree(stat_name);
> + }
> +
> + TSfree(remap);
> +
> + }
> + else if (txnd->hostname)
> + TSfree(txnd->hostname);
> +
> + TSfree(txnd);
> + }
> +
> + TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
> + TSDebug(DEBUG_TAG, "Handler Finished");
> + return 0;
> +}
> +
> +void
> +TSPluginInit (int argc, const char *argv[])
> +{
> + TSPluginRegistrationInfo info;
> + TSCont pre_remap_cont, post_remap_cont, global_cont;
> + config_t *config;
> +
> + info.plugin_name = PLUGIN_NAME;
> + info.vendor_name = "Apache Software Foundation";
> + info.support_email = "dev@trafficserver.apache.org";
> +
> + if (TSPluginRegister(TS_SDK_VERSION_3_0 , &info) != TS_SUCCESS)
> + {
> + TSError("Plugin registration failed.");
> + return;
> + }
> + else
> + TSDebug(DEBUG_TAG, "Plugin registration succeeded.");
> +
> + config = TSmalloc(sizeof(config_t));
> + config->post_remap_host = false;
> + config->persist_type = TS_STAT_NON_PERSISTENT;
> + config->stat_creation_mutex = TSMutexCreate();
> +
> + if (argc > 1)
> + {
> + int c;
> + optind = 1;
> + static const struct option longopts[] = {
> + { "post-remap-host", no_argument, NULL, 'P' },
> + { "persistent", no_argument, NULL, 'p' },
> + { NULL, 0, NULL, 0 }
> + };
> +
> + while ((c = getopt_long(argc, (char * const*) argv, "Pp", longopts, NULL)) != -1)
> + {
> + switch (c)
> + {
> + case 'P':
> + config->post_remap_host = true;
> + TSDebug(DEBUG_TAG, "Using post remap hostname");
> + break;
> + case 'p':
> + config->persist_type = TS_STAT_PERSISTENT;
> + TSDebug(DEBUG_TAG, "Using persistent stats");
> + break;
> + default:
> + break;
> + }
> + }
> + }
> +
> + TSHttpArgIndexReserve(PLUGIN_NAME, "txn data", &(config->txn_slot));
> +
> + if (!config->post_remap_host)
> + {
> + pre_remap_cont = TSContCreate(handle_read_req_hdr, NULL);
> + TSContDataSet(pre_remap_cont, (void *) config);
> + TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, pre_remap_cont);
> + }
> +
> + post_remap_cont = TSContCreate(handle_post_remap, NULL);
> + TSContDataSet(post_remap_cont, (void *) config);
> + TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, post_remap_cont);
> +
> + global_cont = TSContCreate(handle_txn_close, NULL);
> + TSContDataSet(global_cont, (void *) config);
> + TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, global_cont);
> +
> + TSDebug(DEBUG_TAG, "Init complete");
> +}
>