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

Reply via email to