This is an automated email from the ASF dual-hosted git repository. cmcfarlen pushed a commit to branch 10.2.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit bf218ea66a09218300e37f3ad0811213ba6ff9a5 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. (cherry picked from commit 990bd049aa67b2293c3334f8a28b9f80c2eb650b) --- 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 93c1669784..c295837730 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 5e2d1e6bb7..23a05a1b9d 100644 --- a/src/proxy/Plugin.cc +++ b/src/proxy/Plugin.cc @@ -22,12 +22,15 @@ */ #include <cstdio> +#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" @@ -79,6 +82,31 @@ static const char *plugin_dir = "."; 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 + // Plugin registration vars // // plugin_reg_list has an entry for each plugin @@ -192,7 +220,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
