This is an automated email from the ASF dual-hosted git repository.
moonchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 990bd049aa Add per-plugin workload counters (#13278)
990bd049aa is described below
commit 990bd049aa67b2293c3334f8a28b9f80c2eb650b
Author: Mo Chen <[email protected]>
AuthorDate: Mon Jun 22 17:46:30 2026 -0500
Add per-plugin workload counters (#13278)
Add per-plugin metrics that allow us to track how much work each plugin is
doing
by counting their invocations, intercept bytes, and intercept transfers.
Add proxy.process.plugin.<name>.{invocations,bytes, transfers}, keyed by the
plugin DSO basename and bounded by the number of loaded plugins.
Global plugins load via raw dlopen and previously carried no identity, so
they
are given a PluginThreadContext around TSPluginInit; the continuations they
create then carry plugin identity the same way remap plugins already do.
---
include/proxy/PluginThreadContext.h | 61 +++++++++++
include/proxy/PluginVC.h | 6 ++
include/proxy/http/remap/PluginDso.h | 11 +-
src/api/InkContInternal.cc | 9 +-
src/proxy/CMakeLists.txt | 1 +
src/proxy/Plugin.cc | 38 +++++++
src/proxy/PluginThreadContext.cc | 65 ++++++++++++
src/proxy/PluginVC.cc | 16 +++
src/proxy/http/remap/PluginDso.cc | 7 ++
src/proxy/http/remap/RemapPlugins.cc | 2 +
src/proxy/unit_tests/stub.cc | 2 -
tests/gold_tests/pluginTest/lua/metrics.sh | 3 +-
.../per_plugin_metrics/per_plugin_metrics.test.py | 111 +++++++++++++++++++++
.../per_plugin_metrics/rules/global.conf | 20 ++++
.../pluginTest/regex_revalidate/metrics.sh | 3 +-
.../pluginTest/regex_revalidate/metrics_miss.sh | 3 +-
16 files changed, 344 insertions(+), 14 deletions(-)
diff --git a/include/proxy/PluginThreadContext.h
b/include/proxy/PluginThreadContext.h
new file mode 100644
index 0000000000..88db0d825d
--- /dev/null
+++ b/include/proxy/PluginThreadContext.h
@@ -0,0 +1,61 @@
+/** @file
+
+ Per-plugin identity carried on the continuations a plugin creates.
+
+ @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.
+ */
+
+#pragma once
+
+#include <string>
+#include <string_view>
+
+#include "tscore/Ptr.h"
+#include "tsutil/Metrics.h"
+
+/** Carries a plugin's identity on the continuations it creates so that
+ * proxy.process.plugin.<name>.* workload counters can be attributed back to
the originating
+ * plugin DSO.
+ *
+ * This lives in ts::proxy rather than ts::http_remap because it is shared by
both remap plugins
+ * (PluginDso) and global plugins (GlobalPluginContext, in Plugin.cc). The
library dependency only
+ * runs ts::http_remap -> ts::proxy, so putting it here lets both paths
resolve these symbols. */
+class PluginThreadContext : public RefCountObjInHeap
+{
+public:
+ virtual void acquire() = 0;
+ virtual void release() = 0;
+
+ /** Register this plugin's proxy.process.plugin.<name>.* metrics. @a
plugin_name is the DSO path;
+ * only its basename stem (extension removed) is used as <name>. */
+ void registerPluginMetrics(std::string_view plugin_name);
+
+ void countInvocation();
+
+ ts::Metrics::Counter::AtomicType *_invocations = nullptr;
+ ts::Metrics::Counter::AtomicType *_bytes = nullptr;
+ ts::Metrics::Counter::AtomicType *_transfers = nullptr;
+
+ static constexpr const char *const _tag = "plugin_context"; /** @brief log
tag used by this class */
+
+private:
+ /** Derive a metric-safe token from a plugin path: the basename with the
extension removed, then any
+ * character outside [A-Za-z0-9_-] replaced by '_' (e.g.
"/.../header_rewrite.so" -> "header_rewrite"). */
+ static std::string _metric_token(std::string_view name);
+};
diff --git a/include/proxy/PluginVC.h b/include/proxy/PluginVC.h
index bfa8b1aa5b..ba016754e1 100644
--- a/include/proxy/PluginVC.h
+++ b/include/proxy/PluginVC.h
@@ -38,6 +38,7 @@
#include "proxy/Plugin.h"
#include "iocore/net/NetVConnection.h"
#include "tscore/ink_atomic.h"
+#include "tsutil/Metrics.h"
class PluginVCCore;
@@ -253,6 +254,11 @@ private:
Continuation *connect_to = nullptr;
bool connected = false;
+ // Transport counters of the plugin that created this intercept, captured at
alloc(). Registry-owned
+ // (process-lifetime), so safe to hold raw. Null for core-internal PluginVCs.
+ ts::Metrics::Counter::AtomicType *_bytes = nullptr;
+ ts::Metrics::Counter::AtomicType *_transfers = nullptr;
+
IpEndpoint passive_addr_struct;
IpEndpoint active_addr_struct;
diff --git a/include/proxy/http/remap/PluginDso.h
b/include/proxy/http/remap/PluginDso.h
index d3ea8087a2..68b01f9058 100644
--- a/include/proxy/http/remap/PluginDso.h
+++ b/include/proxy/http/remap/PluginDso.h
@@ -46,17 +46,14 @@
namespace fs = swoc::file;
#include "tscore/Ptr.h"
+#include "tsutil/Metrics.h"
#include "iocore/eventsystem/EventSystem.h"
#include "proxy/Plugin.h"
+#include "proxy/PluginThreadContext.h"
-class PluginThreadContext : public RefCountObjInHeap
-{
-public:
- virtual void acquire() = 0;
- virtual void release() = 0;
- static constexpr const char *const _tag = "plugin_context"; /** @brief
log tag used by this class */
-};
+#include <string>
+#include <string_view>
class PluginDso : public PluginThreadContext
{
diff --git a/src/api/InkContInternal.cc b/src/api/InkContInternal.cc
index 5d5ac2cdc6..6c2da59d7a 100644
--- a/src/api/InkContInternal.cc
+++ b/src/api/InkContInternal.cc
@@ -157,8 +157,13 @@ INKContInternal::handle_event(int event, void *edata)
/* set the plugin context */
auto *previousContext = pluginThreadContext;
pluginThreadContext = reinterpret_cast<PluginThreadContext *>(m_context);
- int retval = m_event_func((TSCont)this, (TSEvent)event, edata);
- pluginThreadContext = previousContext;
+ // Every TSCont (continuation) callback dispatch flows through here; count
it against the owning
+ // plugin. (Remap doRemap dispatch does not, and is counted in
RemapPlugins::run_plugin instead.)
+ if (pluginThreadContext != nullptr) {
+ pluginThreadContext->countInvocation();
+ }
+ int retval = m_event_func((TSCont)this, (TSEvent)event, edata);
+ pluginThreadContext = previousContext;
if (edata && event == EVENT_INTERVAL) {
Event *e = reinterpret_cast<Event *>(edata);
if (e->period != 0) {
diff --git a/src/proxy/CMakeLists.txt b/src/proxy/CMakeLists.txt
index 34874f380f..c0814f6009 100644
--- a/src/proxy/CMakeLists.txt
+++ b/src/proxy/CMakeLists.txt
@@ -28,6 +28,7 @@ add_library(
ParentSelectionStrategy.cc
ParentSelection.cc
Plugin.cc
+ PluginThreadContext.cc
PluginVC.cc
ProtocolProbeSessionAccept.cc
ProxySession.cc
diff --git a/src/proxy/Plugin.cc b/src/proxy/Plugin.cc
index 0cdb620460..d6ebc46b48 100644
--- a/src/proxy/Plugin.cc
+++ b/src/proxy/Plugin.cc
@@ -25,12 +25,15 @@
#include <algorithm>
#include <filesystem>
#include <optional>
+#include <string_view>
+#include <vector>
#include "tscore/ink_platform.h"
#include "tscore/ink_file.h"
#include "tscore/ParseRules.h"
#include "records/RecCore.h"
#include "tscore/Layout.h"
#include "proxy/Plugin.h"
+#include "proxy/http/remap/RemapPluginInfo.h"
#include "tscore/ink_cap.h"
#include "tscore/Filenames.h"
#include <yaml-cpp/yaml.h>
@@ -94,6 +97,31 @@ plugin_dir_init()
using init_func_t = void (*)(int, char **);
+namespace
+{
+/** Plugin context for global plugins, which load via raw dlopen() rather than
the
+ * PluginFactory/PluginDso path and so would otherwise have no
PluginThreadContext to carry their
+ * identity. Installed as the thread-local pluginThreadContext around
TSPluginInit so the plugin's
+ * continuations are stamped with it. Global plugins are never unloaded, so
acquire()/release() are
+ * no-ops and instances live for the process lifetime. */
+class GlobalPluginContext : public PluginThreadContext
+{
+public:
+ explicit GlobalPluginContext(std::string_view name) {
registerPluginMetrics(name); }
+ void
+ acquire() override
+ {
+ }
+ void
+ release() override
+ {
+ }
+};
+
+// Keeps global-plugin contexts reachable for the process lifetime; mutated
single-threaded at startup.
+std::vector<GlobalPluginContext *> g_global_plugin_contexts;
+} // namespace
+
static PluginLoadSummary s_plugin_load_summary;
const PluginLoadSummary &
@@ -215,7 +243,17 @@ single_plugin_init(int argc, char *argv[], bool
validateOnly)
#endif
opterr = 0;
optarg = nullptr;
+
+ // Install this plugin's context around TSPluginInit so the continuations
it creates carry its
+ // identity (see GlobalPluginContext).
+ auto *global_context = new GlobalPluginContext(path);
+ g_global_plugin_contexts.push_back(global_context);
+ auto *prev_plugin_context = pluginThreadContext;
+ pluginThreadContext = global_context;
+
init(argc, argv);
+
+ pluginThreadContext = prev_plugin_context;
} // done elevating access
if (plugin_reg_current->plugin_registered) {
diff --git a/src/proxy/PluginThreadContext.cc b/src/proxy/PluginThreadContext.cc
new file mode 100644
index 0000000000..23575025e1
--- /dev/null
+++ b/src/proxy/PluginThreadContext.cc
@@ -0,0 +1,65 @@
+/** @file
+
+ Per-plugin identity carried on the continuations a plugin creates.
+
+ @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 "proxy/PluginThreadContext.h"
+
+#include <algorithm>
+#include <cctype>
+#include <string>
+#include <string_view>
+
+void
+PluginThreadContext::registerPluginMetrics(std::string_view plugin_name)
+{
+ std::string prefix = "proxy.process.plugin." + _metric_token(plugin_name) +
".";
+
+ _invocations = ts::Metrics::Counter::createPtr(prefix + "invocations");
+ _bytes = ts::Metrics::Counter::createPtr(prefix + "bytes");
+ _transfers = ts::Metrics::Counter::createPtr(prefix + "transfers");
+}
+
+void
+PluginThreadContext::countInvocation()
+{
+ if (_invocations != nullptr) {
+ _invocations->increment(1);
+ }
+}
+
+std::string
+PluginThreadContext::_metric_token(std::string_view name)
+{
+ if (auto slash = name.find_last_of('/'); slash != std::string_view::npos) {
+ name.remove_prefix(slash + 1);
+ }
+ if (auto dot = name.find_last_of('.'); dot != std::string_view::npos) {
+ name = name.substr(0, dot);
+ }
+
+ std::string token{name};
+ std::replace_if(token.begin(), token.end(), [](unsigned char c) { return
!(std::isalnum(c) || c == '_' || c == '-'); }, '_');
+ if (token.empty()) {
+ token = "unknown";
+ }
+ return token;
+}
diff --git a/src/proxy/PluginVC.cc b/src/proxy/PluginVC.cc
index 3caa8dc673..38cecb3f0b 100644
--- a/src/proxy/PluginVC.cc
+++ b/src/proxy/PluginVC.cc
@@ -72,6 +72,7 @@
****************************************************************************/
#include "proxy/PluginVC.h"
+#include "proxy/http/remap/RemapPluginInfo.h"
#include "../iocore/net/P_Net.h"
#include "tscore/Regression.h"
#if TS_HAS_TESTS
@@ -466,6 +467,11 @@ PluginVC::transfer_bytes(MIOBuffer *transfer_to,
IOBufferReader *transfer_from,
total_added += moved;
}
+ // Attribute the bytes moved across this intercept to the owning plugin.
+ if (core_obj->_bytes != nullptr && total_added > 0) {
+ core_obj->_bytes->increment(total_added);
+ }
+
return total_added;
}
@@ -564,6 +570,11 @@ PluginVC::process_write_side()
return;
}
+ // Count a write-side pass for the owning plugin only when data actually
moved to the peer.
+ if (core_obj->_transfers != nullptr && added > 0) {
+ core_obj->_transfers->increment(1);
+ }
+
write_state.vio.ndone += added;
other_side->read_state.vio.ndone += added;
@@ -1002,6 +1013,11 @@ PluginVCCore::alloc(Continuation *acceptor, int64_t
buffer_index, int64_t buffer
PluginVCCore *pvc = new PluginVCCore;
pvc->init(buffer_index, buffer_water_mark);
pvc->connect_to = acceptor;
+ // Capture the creating plugin's transport counters (registry-owned) for
per-plugin accounting.
+ if (pluginThreadContext != nullptr) {
+ pvc->_bytes = pluginThreadContext->_bytes;
+ pvc->_transfers = pluginThreadContext->_transfers;
+ }
return pvc;
}
diff --git a/src/proxy/http/remap/PluginDso.cc
b/src/proxy/http/remap/PluginDso.cc
index 4b75f4e475..7c3982358f 100644
--- a/src/proxy/http/remap/PluginDso.cc
+++ b/src/proxy/http/remap/PluginDso.cc
@@ -29,6 +29,7 @@
#include "proxy/http/remap/PluginDso.h"
#include "iocore/eventsystem/Freer.h"
+#include "tsutil/Metrics.h"
#ifdef PLUGIN_DSO_TESTS
#include "unit-tests/plugin_testing_common.h"
#else
@@ -38,6 +39,8 @@
#endif
#include <cstdlib>
+#include <string>
+#include <string_view>
#include <utility>
namespace
@@ -139,6 +142,10 @@ PluginDso::load(std::string &error, const fs::path
&compilerPath)
}
PluginDbg(_dbg_ctl(), "plugin '%s' finished loading DSO",
_configPath.c_str());
+ if (result) {
+ registerPluginMetrics(_effectivePath.string());
+ }
+
return result;
}
diff --git a/src/proxy/http/remap/RemapPlugins.cc
b/src/proxy/http/remap/RemapPlugins.cc
index 9c55ee2665..54c52c03be 100644
--- a/src/proxy/http/remap/RemapPlugins.cc
+++ b/src/proxy/http/remap/RemapPlugins.cc
@@ -59,6 +59,8 @@ RemapPlugins::run_plugin(RemapPluginInst *plugin)
_s->os_response_plugin_inst = plugin;
}
+ plugin->_plugin.countInvocation();
+
HttpTransact::milestone_start_api_time(_s);
plugin_retcode =
plugin->doRemap(reinterpret_cast<TSHttpTxn>(_s->state_machine), &rri);
HttpTransact::milestone_update_api_time(_s);
diff --git a/src/proxy/unit_tests/stub.cc b/src/proxy/unit_tests/stub.cc
index a1a95fe8cc..ba279051a3 100644
--- a/src/proxy/unit_tests/stub.cc
+++ b/src/proxy/unit_tests/stub.cc
@@ -22,5 +22,3 @@
*/
#include "proxy/IPAllow.h"
-
-uint8_t IpAllow::subjects[IpAllow::Subject::MAX_SUBJECTS];
diff --git a/tests/gold_tests/pluginTest/lua/metrics.sh
b/tests/gold_tests/pluginTest/lua/metrics.sh
index 6aec5bc03b..0d4c8d8617 100755
--- a/tests/gold_tests/pluginTest/lua/metrics.sh
+++ b/tests/gold_tests/pluginTest/lua/metrics.sh
@@ -18,7 +18,8 @@ N=60
while (( N > 0 ))
do
rm -f metrics.out metrics.txt
- traffic_ctl metric match lua > metrics.out
+ # Anchor to this plugin's own metrics; exclude the proxy.process.plugin.*
workload counters.
+ traffic_ctl metric match '^plugin\.lua\.' > metrics.out
sleep 1
sed 's/ [0-9][0-9]*//' metrics.out > metrics.txt
if diff metrics.txt ${AUTEST_TEST_DIR}/gold/metrics.gold
diff --git
a/tests/gold_tests/pluginTest/per_plugin_metrics/per_plugin_metrics.test.py
b/tests/gold_tests/pluginTest/per_plugin_metrics/per_plugin_metrics.test.py
new file mode 100644
index 0000000000..202412e621
--- /dev/null
+++ b/tests/gold_tests/pluginTest/per_plugin_metrics/per_plugin_metrics.test.py
@@ -0,0 +1,111 @@
+'''
+Verify the per-plugin workload counters
proxy.process.plugin.<name>.{invocations,bytes,transfers}.
+'''
+# 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.
+
+import re
+
+Test.Summary = '''
+Verify the per-plugin workload counters
proxy.process.plugin.<name>.invocations (global and remap
+dispatch), .bytes and .transfers (PluginVC intercept transport).
+'''
+
+Test.SkipUnless(
+ Condition.PluginExists('header_rewrite.so'),
Condition.PluginExists('conf_remap.so'), Condition.PluginExists('generator.so'))
+
+Test.ContinueOnFail = True
+
+
+class TestPerPluginWorkloadCounters:
+
+ def __init__(self):
+ self.setUpOriginServer()
+ self.setUpTS()
+
+ def setUpOriginServer(self):
+ self.server = Test.MakeOriginServer("server")
+ request_header = {"headers": "GET / HTTP/1.1\r\nHost:
test.example\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
+ response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection:
close\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
+ self.server.addResponse("sessionfile.log", request_header,
response_header)
+
+ def setUpTS(self):
+ self.ts = Test.MakeATSProcess("ts")
+
+ # header_rewrite (global) and conf_remap (remap) exercise the two
invocation-counter sites;
+ # generator serves its body through a PluginVC intercept, exercising
the bytes and transfers counters.
+ self.ts.Setup.CopyAs('rules/global.conf', Test.RunDirectory)
+ self.ts.Disk.plugin_config.AddLine(f'header_rewrite.so
{Test.RunDirectory}/global.conf')
+ self.ts.Disk.remap_config.AddLine(
+ f'map http://test.example
http://127.0.0.1:{self.server.Variables.Port} '
+ f'@plugin=conf_remap.so
@pparam=proxy.config.url_remap.pristine_host_hdr=1')
+ self.ts.Disk.remap_config.AddLine('map http://gen.example
http://127.0.0.1/ @plugin=generator.so')
+
+ self.ts.Disk.records_config.update({
+ 'proxy.config.diags.debug.enabled': 0,
+ 'proxy.config.diags.debug.tags': 'plugin',
+ })
+
+ def driveTraffic(self):
+ # curl as a forward proxy sends an absolute-URI request so the named
remap rule (conf_remap)
+ # matches; the 200 confirms it was served rather than 404'd.
+ tr = Test.AddTestRun("Drive traffic through global + remap plugins")
+ tr.Processes.Default.StartBefore(self.server)
+ tr.Processes.Default.StartBefore(self.ts)
+ tr.MakeCurlCommand(f'-s -D - -o /dev/null --proxy
127.0.0.1:{self.ts.Variables.port} "http://test.example/"', ts=self.ts)
+ tr.Processes.Default.ReturnCode = 0
+ tr.Processes.Default.Streams.stdout = Testers.ContainsExpression(
+ '200 OK', 'request should match the remap rule and be served')
+ tr.StillRunningAfter = self.server
+ tr.StillRunningAfter = self.ts
+
+ # Drive a generator request: it serves a 4096-byte body through a
PluginVC intercept.
+ tr = Test.AddTestRun("Drive traffic through a PluginVC intercept
plugin")
+ tr.MakeCurlCommand(
+ f'-s -o /dev/null --proxy 127.0.0.1:{self.ts.Variables.port}
"http://gen.example/nocache/4096"', ts=self.ts)
+ tr.Processes.Default.ReturnCode = 0
+ tr.StillRunningAfter = self.ts
+ tr.StillRunningAfter = self.server
+
+ def checkMetric(self, description, metric, message):
+ tr = Test.AddTestRun(description)
+ tr.Processes.Default.Env = self.ts.Env
+ tr.Processes.Default.Command = f'traffic_ctl metric get {metric}'
+ tr.Processes.Default.ReturnCode = 0
+ tr.Processes.Default.Streams.stdout =
Testers.ContainsExpression(f'{re.escape(metric)} [1-9]', message)
+ tr.StillRunningAfter = self.ts
+ tr.StillRunningAfter = self.server
+
+ def checkMetrics(self):
+ self.checkMetric(
+ "Global plugin invocation counter is non-zero",
'proxy.process.plugin.header_rewrite.invocations',
+ 'global header_rewrite invocations should be counted')
+ self.checkMetric(
+ "Remap plugin invocation counter is non-zero",
'proxy.process.plugin.conf_remap.invocations',
+ 'remap conf_remap invocations should be counted')
+ self.checkMetric(
+ "PluginVC intercept bytes counter is non-zero",
'proxy.process.plugin.generator.bytes',
+ 'generator PluginVC transport bytes should be counted')
+ self.checkMetric(
+ "PluginVC intercept transfers counter is non-zero",
'proxy.process.plugin.generator.transfers',
+ 'generator PluginVC transfer events should be counted')
+
+ def run(self):
+ self.driveTraffic()
+ self.checkMetrics()
+
+
+TestPerPluginWorkloadCounters().run()
diff --git a/tests/gold_tests/pluginTest/per_plugin_metrics/rules/global.conf
b/tests/gold_tests/pluginTest/per_plugin_metrics/rules/global.conf
new file mode 100644
index 0000000000..b715700328
--- /dev/null
+++ b/tests/gold_tests/pluginTest/per_plugin_metrics/rules/global.conf
@@ -0,0 +1,20 @@
+# 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.
+
+# Fire on every response so the global header_rewrite continuation is
dispatched (through
+# INKContInternal::handle_event) for each transaction, exercising the
per-plugin invocation counter.
+cond %{SEND_RESPONSE_HDR_HOOK}
+set-header X-Per-Plugin-Metrics "1"
diff --git a/tests/gold_tests/pluginTest/regex_revalidate/metrics.sh
b/tests/gold_tests/pluginTest/regex_revalidate/metrics.sh
index 4365a0e6e0..4b5afd2f99 100755
--- a/tests/gold_tests/pluginTest/regex_revalidate/metrics.sh
+++ b/tests/gold_tests/pluginTest/regex_revalidate/metrics.sh
@@ -18,7 +18,8 @@ N=60
while (( N > 0 ))
do
rm -f metrics.out
- traffic_ctl metric match regex_revalidate > metrics.out
+ # Anchor to this plugin's own metrics; exclude the proxy.process.plugin.*
workload counters.
+ traffic_ctl metric match '^plugin\.regex_revalidate\.' > metrics.out
sleep 1
if diff metrics.out ${AUTEST_TEST_DIR}/gold/metrics.gold
then
diff --git a/tests/gold_tests/pluginTest/regex_revalidate/metrics_miss.sh
b/tests/gold_tests/pluginTest/regex_revalidate/metrics_miss.sh
index 164a4e4527..c2b4db8634 100755
--- a/tests/gold_tests/pluginTest/regex_revalidate/metrics_miss.sh
+++ b/tests/gold_tests/pluginTest/regex_revalidate/metrics_miss.sh
@@ -18,7 +18,8 @@ N=60
while (( N > 0 ))
do
rm -f metrics.out
- traffic_ctl metric match regex_revalidate > metrics.out
+ # Anchor to this plugin's own metrics; exclude the proxy.process.plugin.*
workload counters.
+ traffic_ctl metric match '^plugin\.regex_revalidate\.' > metrics.out
sleep 1
if diff metrics.out ${AUTEST_TEST_DIR}/gold/metrics_miss.gold
then