github.com/hellofresh/janus@v0.0.0-20230925145208-ce8de8183c67/pkg/plugin/cb/setup.go (about)

     1  package cb
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/afex/hystrix-go/hystrix"
    10  	metricCollector "github.com/afex/hystrix-go/hystrix/metric_collector"
    11  	"github.com/afex/hystrix-go/plugins"
    12  	"github.com/asaskevich/govalidator"
    13  	log "github.com/sirupsen/logrus"
    14  
    15  	"github.com/hellofresh/janus/pkg/plugin"
    16  	"github.com/hellofresh/janus/pkg/proxy"
    17  )
    18  
    19  const (
    20  	pluginName = "cb"
    21  )
    22  
    23  // Config represents the Body Limit configuration
    24  type Config struct {
    25  	hystrix.CommandConfig
    26  	Name      string `json:"name"`
    27  	Predicate string `json:"predicate"`
    28  }
    29  
    30  func init() {
    31  	plugin.RegisterEventHook(plugin.StartupEvent, onStartup)
    32  	plugin.RegisterEventHook(plugin.AdminAPIStartupEvent, onAdminAPIStartup)
    33  	plugin.RegisterPlugin(pluginName, plugin.Plugin{
    34  		Action:   setupCB,
    35  		Validate: validateConfig,
    36  	})
    37  }
    38  
    39  func setupCB(def *proxy.RouterDefinition, rawConfig plugin.Config) error {
    40  	var c Config
    41  	err := plugin.Decode(rawConfig, &c)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	log.WithFields(log.Fields{
    47  		"plugin_event": plugin.SetupEvent,
    48  		"plugin":       pluginName,
    49  		"name":         c.Name,
    50  	}).Debug("Configuring cb plugin")
    51  
    52  	hystrix.ConfigureCommand(c.Name, hystrix.CommandConfig{
    53  		Timeout:               c.Timeout,
    54  		MaxConcurrentRequests: c.MaxConcurrentRequests,
    55  		ErrorPercentThreshold: c.ErrorPercentThreshold,
    56  		SleepWindow:           c.SleepWindow,
    57  	})
    58  
    59  	def.AddMiddleware(NewCBMiddleware(c))
    60  	return nil
    61  }
    62  
    63  func validateConfig(rawConfig plugin.Config) (bool, error) {
    64  	var config Config
    65  	err := plugin.Decode(rawConfig, &config)
    66  	if err != nil {
    67  		return false, err
    68  	}
    69  
    70  	return govalidator.ValidateStruct(config)
    71  }
    72  
    73  func onAdminAPIStartup(event interface{}) error {
    74  	logger := log.WithFields(log.Fields{
    75  		"plugin_event": plugin.AdminAPIStartupEvent,
    76  		"plugin":       pluginName,
    77  	})
    78  
    79  	e, ok := event.(plugin.OnAdminAPIStartup)
    80  	if !ok {
    81  		return errors.New("could not convert event to admin startup type")
    82  	}
    83  
    84  	logger.Debug("Registering hystrix stream endpoint")
    85  	hystrixStreamHandler := hystrix.NewStreamHandler()
    86  	hystrixStreamHandler.Start()
    87  
    88  	e.Router.GET("/hystrix", hystrixStreamHandler.ServeHTTP)
    89  	return nil
    90  }
    91  
    92  func onStartup(event interface{}) error {
    93  	logger := log.WithFields(log.Fields{
    94  		"plugin_event": plugin.StartupEvent,
    95  		"plugin":       pluginName,
    96  	})
    97  
    98  	e, ok := event.(plugin.OnStartup)
    99  	if !ok {
   100  		return errors.New("could not convert event to startup type")
   101  	}
   102  
   103  	logger.WithField("metrics_dsn", e.Config.Stats.DSN).Debug("Statsd metrics enabled")
   104  
   105  	dsnURL, err := url.Parse(e.Config.Stats.DSN)
   106  	if err != nil {
   107  		return fmt.Errorf("could not parse stats dsn: %w", err)
   108  	}
   109  
   110  	c, err := plugins.InitializeStatsdCollector(&plugins.StatsdCollectorConfig{
   111  		StatsdAddr: dsnURL.Host,
   112  		Prefix:     strings.Trim(dsnURL.Path, "/"),
   113  	})
   114  	if err != nil {
   115  		return fmt.Errorf("could not initialize statsd client: %w", err)
   116  	}
   117  
   118  	metricCollector.Registry.Register(c.NewStatsdCollector)
   119  	logger.Debug("Metrics enabled")
   120  
   121  	return nil
   122  }