blob: 6f1b7ae25754f9ae4684637def02fef3313cc581 [file] [log] [blame]
// Licensed to 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. Apache Software Foundation (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.
package plugin
import (
"fmt"
"reflect"
"strings"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"github.com/apache/skywalking-satellite/internal/pkg/config"
"github.com/apache/skywalking-satellite/internal/pkg/log"
)
// the global plugin registry
var (
Reg map[reflect.Type]map[string]reflect.Value
)
func init() {
Reg = make(map[reflect.Type]map[string]reflect.Value)
}
// RegisterPluginCategory register the RegInfo to the global type registry.
func RegisterPluginCategory(pluginType reflect.Type) {
Reg[pluginType] = map[string]reflect.Value{}
}
// RegisterPlugin registers the pluginType as plugin.
// If the plugin is a pointer receiver, please pass a pointer. Otherwise, please pass a value.
func RegisterPlugin(plugin Plugin) {
v := reflect.ValueOf(plugin)
success := false
for pCategory, pReg := range Reg {
if v.Type().Implements(pCategory) {
pReg[plugin.Name()] = v
log.Logger.WithFields(logrus.Fields{
"category": v.Type().String(),
"plugin_name": plugin.Name(),
}).Debug("register plugin success")
success = true
}
}
if !success {
log.Logger.WithFields(logrus.Fields{
"category": v.Type().String(),
"plugin_name": plugin.Name(),
}).Error("plugin is not allowed to register")
}
}
// Get an initialized specific plugin according to the pluginCategory and config.
func Get(category reflect.Type, cfg Config) Plugin {
pluginName := nameFinder(cfg)
value, ok := Reg[category][pluginName]
if !ok {
panic(fmt.Errorf("cannot find %s plugin, and the category of plugin is %s", pluginName, category))
}
t := value.Type()
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
plugin := reflect.New(t).Interface().(Plugin)
initializing(plugin, cfg)
return plugin
}
// nameFinder is used to get the plugin name in Config.
func nameFinder(cfg interface{}) string {
c, ok := cfg.(Config)
if !ok {
panic(fmt.Errorf("nameFinder only supports Config"))
}
name, ok := c[NameField]
if !ok {
panic(fmt.Errorf("%s is requeired in Config", NameField))
}
return name.(string)
}
// initializing initialize the fields by fields mapping.
func initializing(plugin Plugin, cfg Config) {
v := viper.New()
v.SetConfigType("yaml")
if plugin.DefaultConfig() != "" {
if err := v.ReadConfig(strings.NewReader(plugin.DefaultConfig())); err != nil {
panic(fmt.Errorf("cannot read default config in the plugin: %s, the error is %v", plugin.Name(), err))
}
}
if err := v.MergeConfigMap(cfg); err != nil {
panic(fmt.Errorf("%s plugin cannot merge the custom configuration, the error is %v", plugin.Name(), err))
}
if err := v.Unmarshal(plugin); err != nil {
panic(fmt.Errorf("cannot inject the config to the %s plugin, the error is %v", plugin.Name(), err))
}
cf := reflect.ValueOf(plugin).Elem().FieldByName(config.CommonFieldsName)
if !cf.IsValid() {
panic(fmt.Errorf("%s plugin must have a field named CommonField", plugin.Name()))
}
for i := 0; i < cf.NumField(); i++ {
tagVal := cf.Type().Field(i).Tag.Get(config.TagName)
if tagVal != "" {
if val := cfg[strings.ToLower(config.CommonFieldsName)+"_"+tagVal]; val != nil {
cf.Field(i).Set(reflect.ValueOf(val))
}
}
}
}