Skip to content

Commit c1c2719

Browse files
committed
address comments and add integration test
1 parent 34cd10c commit c1c2719

File tree

6 files changed

+137
-37
lines changed

6 files changed

+137
-37
lines changed

api/pkg/filtermanager/config.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ func (conf *filterManagerConfig) InitOnce() {
177177
}
178178

179179
func (p *FilterManagerConfigParser) Parse(any *anypb.Any, callbacks capi.ConfigCallbackHandler) (interface{}, error) {
180+
if callbacks == nil {
181+
api.LogErrorf("no config callback handler provided")
182+
// the call back handler to be nil only affects plugin metrics, so we can continue
183+
}
180184
configStruct := &xds.TypedStruct{}
181185

182186
// No configuration
@@ -217,11 +221,6 @@ func (p *FilterManagerConfigParser) Parse(any *anypb.Any, callbacks capi.ConfigC
217221
for _, proto := range plugins {
218222
name := proto.Name
219223

220-
if registerMetrics := pkgPlugins.LoadMetricsCallback(name); registerMetrics != nil {
221-
registerMetrics(callbacks)
222-
api.LogInfof("loaded metrics definition for plugin %s", name)
223-
}
224-
225224
if plugin := pkgPlugins.LoadHTTPFilterFactoryAndParser(name); plugin != nil {
226225
config, err := plugin.ConfigParser.Parse(proto.Config)
227226
if err != nil {
@@ -252,6 +251,10 @@ func (p *FilterManagerConfigParser) Parse(any *anypb.Any, callbacks capi.ConfigC
252251
if _, ok := config.(pkgPlugins.Initer); ok {
253252
needInit = true
254253
}
254+
if register, ok := config.(pkgPlugins.MetricsRegister); ok {
255+
register.MetricsDefinition(callbacks)
256+
api.LogInfof("loaded metrics definition for plugin: %s", name)
257+
}
255258

256259
if name == "debugMode" {
257260
// we handle this plugin differently, so we can have debug behavior before

api/pkg/plugins/plugins.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -191,24 +191,6 @@ func (cp *PluginConfigParser) Parse(any interface{}) (res interface{}, err error
191191
return conf, nil
192192
}
193193

194-
func RegisterMetricsCallback(pluginName string, registerMetricFunc func(capi.ConfigCallbacks)) {
195-
if registerMetricFunc == nil {
196-
panic("registerMetricFunc should not be nil")
197-
}
198-
if pluginName == "" {
199-
panic("pluginName should not be empty")
200-
}
201-
if _, ok := metricsRegister[pluginName]; ok {
202-
logger.Error(errors.New("metrics for plugin already registered, overriding"), "name", pluginName)
203-
}
204-
metricsRegister[pluginName] = registerMetricFunc
205-
logger.Info("registered metrics for plugin", "name", pluginName)
206-
}
207-
208-
func LoadMetricsCallback(pluginName string) func(capi.ConfigCallbacks) {
209-
return metricsRegister[pluginName]
210-
}
211-
212194
// PluginMethodDefaultImpl provides reasonable implementation for optional methods
213195
type PluginMethodDefaultImpl struct{}
214196

api/pkg/plugins/type.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package plugins
1616

1717
import (
18+
capi "github.com/envoyproxy/envoy/contrib/golang/common/go/api"
19+
1820
"mosn.io/htnn/api/pkg/filtermanager/api"
1921
)
2022

@@ -149,6 +151,10 @@ type Initer interface {
149151
Init(cb api.ConfigCallbackHandler) error
150152
}
151153

154+
type MetricsRegister interface {
155+
MetricsDefinition(capi.ConfigCallbacks)
156+
}
157+
152158
type NativePlugin interface {
153159
Plugin
154160

api/plugins/tests/integration/dataplane/data_plane.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,27 @@ func (dp *DataPlane) do(method string, path string, header http.Header, body io.
543543
return resp, err
544544
}
545545

546+
func (dp *DataPlane) GetAdmin(path string) (*http.Response, error) {
547+
req, err := http.NewRequest("GET", "http://localhost:"+dp.adminAPIPort+path, nil)
548+
if err != nil {
549+
return nil, err
550+
}
551+
tr := &http.Transport{
552+
DialContext: func(ctx context.Context, proto, addr string) (conn net.Conn, err error) {
553+
return net.DialTimeout("tcp", ":"+dp.adminAPIPort, 1*time.Second)
554+
},
555+
}
556+
557+
client := &http.Client{Transport: tr,
558+
Timeout: 10 * time.Second,
559+
CheckRedirect: func(req *http.Request, via []*http.Request) error {
560+
return http.ErrUseLastResponse
561+
},
562+
}
563+
resp, err := client.Do(req)
564+
return resp, err
565+
}
566+
546567
func (dp *DataPlane) doWithTrailer(method string, path string, header http.Header, body io.Reader, trailer http.Header) (*http.Response, error) {
547568
req, err := http.NewRequest(method, "http://localhost:"+dp.dataPlanePort+path, body)
548569
if err != nil {

api/tests/integration/filtermanager_latest_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package integration
1919
import (
2020
"bytes"
2121
_ "embed"
22+
"io"
2223
"net/http"
2324
"os"
2425
"path/filepath"
@@ -339,3 +340,43 @@ func TestFilterManagerLogWithTrailers(t *testing.T) {
339340
require.Nil(t, err)
340341
assert.Equal(t, 200, resp.StatusCode)
341342
}
343+
344+
func TestMetricsEnabledPlugin(t *testing.T) {
345+
346+
dp, err := dataplane.StartDataPlane(t, &dataplane.Option{
347+
LogLevel: "debug",
348+
Bootstrap: dataplane.Bootstrap(),
349+
})
350+
if err != nil {
351+
t.Fatalf("failed to start data plane: %v", err)
352+
return
353+
}
354+
defer dp.Stop()
355+
356+
lp := &filtermanager.FilterManagerConfig{
357+
Plugins: []*model.FilterConfig{
358+
{
359+
Name: "metrics",
360+
Config: &Config{},
361+
},
362+
},
363+
}
364+
365+
controlPlane.UseGoPluginConfig(t, lp, dp)
366+
hdr := http.Header{}
367+
trailer := http.Header{}
368+
trailer.Add("Expires", "Wed, 21 Oct 2015 07:28:00 GMT")
369+
resp, err := dp.Get("/", hdr)
370+
require.Nil(t, err)
371+
body, err := io.ReadAll(resp.Body)
372+
require.Nil(t, err)
373+
assert.Equal(t, 200, resp.StatusCode, "response: %s", string(body))
374+
resp.Body.Close()
375+
376+
resp, err = dp.GetAdmin("/stats")
377+
require.Nil(t, err)
378+
body, err = io.ReadAll(resp.Body)
379+
require.Nil(t, err)
380+
assert.Contains(t, string(body), "metrics-test.usage.counter 1")
381+
assert.Contains(t, string(body), "metrics-test.usage.gauge 2")
382+
}

api/tests/integration/test_plugins.go

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ func (p *bufferPlugin) Factory() api.FilterFactory {
202202
type localReplyPlugin struct {
203203
plugins.PluginMethodDefaultImpl
204204
basePlugin
205-
usageCounter capi.CounterMetric
206205
}
207206

208207
func localReplyFactory(c interface{}, callbacks api.FilterCallbackHandler) api.Filter {
@@ -245,9 +244,6 @@ func (f *localReplyFilter) DecodeRequest(headers api.RequestHeaderMap, buf api.B
245244
f.reqHdr = headers
246245
f.runFilters = headers.Values("run")
247246
if f.config.Decode {
248-
if lrp.usageCounter != nil {
249-
lrp.usageCounter.Increment(1)
250-
}
251247
return f.NewLocalResponse("reply", true)
252248
}
253249
return api.Continue
@@ -315,11 +311,6 @@ func (p *localReplyPlugin) Factory() api.FilterFactory {
315311
return localReplyFactory
316312
}
317313

318-
func (p *localReplyPlugin) MetricsDefinition(c capi.ConfigCallbacks) {
319-
p.usageCounter = c.DefineCounterMetric("localreply.usage.counter")
320-
// Define more metrics here
321-
}
322-
323314
type badPlugin struct {
324315
plugins.PluginMethodDefaultImpl
325316
}
@@ -630,15 +621,70 @@ func (f *onLogFilter) OnLog(reqHeaders api.RequestHeaderMap, reqTrailers api.Req
630621
api.LogWarnf("receive request trailers: %+v", trailers)
631622
}
632623

633-
var lrp = &localReplyPlugin{}
624+
type metricsConfig struct {
625+
Config
626+
627+
usageCounter capi.CounterMetric
628+
gauge capi.GaugeMetric
629+
}
630+
631+
func (m *metricsConfig) MetricsDefinition(c capi.ConfigCallbacks) {
632+
if c == nil {
633+
api.LogErrorf("metrics config callback is nil")
634+
return
635+
}
636+
m.usageCounter = c.DefineCounterMetric("metrics-test.usage.counter")
637+
m.gauge = c.DefineGaugeMetric("metrics-test.usage.gauge")
638+
api.LogInfo("metrics config loaded for metrics-test")
639+
// Define more metrics here
640+
}
641+
642+
var _ plugins.MetricsRegister = &metricsConfig{}
643+
644+
type metricsPlugin struct {
645+
plugins.PluginMethodDefaultImpl
646+
}
647+
648+
func (p *metricsPlugin) Config() api.PluginConfig {
649+
return &metricsConfig{}
650+
}
651+
652+
func (p *metricsPlugin) Factory() api.FilterFactory {
653+
return metricsFactory
654+
}
655+
656+
func metricsFactory(c interface{}, callbacks api.FilterCallbackHandler) api.Filter {
657+
return &metricsFilter{
658+
callbacks: callbacks,
659+
config: c.(*metricsConfig),
660+
}
661+
}
662+
663+
type metricsFilter struct {
664+
api.PassThroughFilter
665+
666+
callbacks api.FilterCallbackHandler
667+
config *metricsConfig
668+
}
669+
670+
func (f *metricsFilter) DecodeHeaders(headers api.RequestHeaderMap, endStream bool) api.ResultAction {
671+
if f.config.usageCounter != nil {
672+
f.config.usageCounter.Increment(1)
673+
} else {
674+
return &api.LocalResponse{Code: 500, Msg: "metrics config counter is nil"}
675+
}
676+
if f.config.gauge != nil {
677+
f.config.gauge.Record(2)
678+
} else {
679+
return &api.LocalResponse{Code: 500, Msg: "metrics config gauge is nil"}
680+
}
681+
return &api.LocalResponse{Code: 200, Msg: "metrics works"}
682+
}
634683

635684
func init() {
636685
plugins.RegisterPlugin("stream", &streamPlugin{})
637686
plugins.RegisterPlugin("buffer", &bufferPlugin{})
638-
639-
plugins.RegisterPlugin("localReply", lrp)
640-
plugins.RegisterMetricsCallback("localReply", lrp.MetricsDefinition)
641-
687+
plugins.RegisterPlugin("localReply", &localReplyPlugin{})
642688
plugins.RegisterPlugin("bad", &badPlugin{})
643689
plugins.RegisterPlugin("consumer", &consumerPlugin{})
644690
plugins.RegisterPlugin("init", &initPlugin{})
@@ -647,4 +693,5 @@ func init() {
647693
plugins.RegisterPlugin("beforeConsumerAndHasOtherMethod", &beforeConsumerAndHasOtherMethodPlugin{})
648694
plugins.RegisterPlugin("beforeConsumerAndHasDecodeRequest", &beforeConsumerAndHasDecodeRequestPlugin{})
649695
plugins.RegisterPlugin("onLog", &onLogPlugin{})
696+
plugins.RegisterPlugin("metrics", &metricsPlugin{})
650697
}

0 commit comments

Comments
 (0)