youtubebeat/vendor/github.com/elastic/beats/metricbeat/mb/registry.go

317 lines
9.7 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. 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 mb
import (
"fmt"
"sort"
"strings"
"sync"
"github.com/elastic/beats/libbeat/logp"
)
const initialSize = 20 // initialSize specifies the initial size of the Register.
// Registry is the singleton Register instance where all ModuleFactory's and
// MetricSetFactory's should be registered.
var Registry = NewRegister()
// DefaultModuleFactory returns the given BaseModule and never returns an error.
// If a MetricSets are registered without an associated ModuleFactory, then
// the DefaultModuleFactory will be used to instantiate a Module.
var DefaultModuleFactory = func(base BaseModule) (Module, error) {
return &base, nil
}
// ModuleFactory accepts a BaseModule and returns a Module. If there was an
// error creating the Module then an error will be returned.
type ModuleFactory func(base BaseModule) (Module, error)
// MetricSetFactory accepts a BaseMetricSet and returns a MetricSet. If there
// was an error creating the MetricSet then an error will be returned. The
// returned MetricSet must also implement either EventFetcher or EventsFetcher
// (but not both).
type MetricSetFactory func(base BaseMetricSet) (MetricSet, error)
// HostParser is a function that parses a host value from the configuration
// and returns a HostData object. The module is provided in case additional
// configuration values are required to parse and build the HostData object.
// An error should be returned if the host or configuration is invalid.
type HostParser func(module Module, host string) (HostData, error)
// MetricSetRegistration contains the parameters that were used to register
// a MetricSet.
type MetricSetRegistration struct {
Name string
Factory MetricSetFactory
// Options
IsDefault bool
HostParser HostParser
Namespace string
}
// MetricSetOption sets an option for a MetricSetFactory that is being
// registered.
type MetricSetOption func(info *MetricSetRegistration)
// WithHostParser specifies the HostParser that should be used with the
// MetricSet.
func WithHostParser(p HostParser) MetricSetOption {
return func(r *MetricSetRegistration) {
r.HostParser = p
}
}
// DefaultMetricSet specifies that the MetricSetFactory will be the default
// when no MetricSet names are specified in the configuration.
func DefaultMetricSet() MetricSetOption {
return func(r *MetricSetRegistration) {
r.IsDefault = true
}
}
// WithNamespace specifies the fully qualified namespace under which MetricSet
// data will be added. If no namespace is specified then [module].[metricset]
// will be used.
func WithNamespace(namespace string) MetricSetOption {
return func(r *MetricSetRegistration) {
r.Namespace = namespace
}
}
// Register contains the factory functions for creating new Modules and new
// MetricSets. Registers are thread safe for concurrent usage.
type Register struct {
// Lock to control concurrent read/writes
lock sync.RWMutex
// A map of module name to ModuleFactory.
modules map[string]ModuleFactory
// A map of module name to nested map of MetricSet name to MetricSetRegistration.
metricSets map[string]map[string]MetricSetRegistration
}
// NewRegister creates and returns a new Register.
func NewRegister() *Register {
return &Register{
modules: make(map[string]ModuleFactory, initialSize),
metricSets: make(map[string]map[string]MetricSetRegistration, initialSize),
}
}
// AddModule registers a new ModuleFactory. An error is returned if the
// name is empty, factory is nil, or if a factory has already been registered
// under the name.
func (r *Register) AddModule(name string, factory ModuleFactory) error {
r.lock.Lock()
defer r.lock.Unlock()
if name == "" {
return fmt.Errorf("module name is required")
}
name = strings.ToLower(name)
_, exists := r.modules[name]
if exists {
return fmt.Errorf("module '%s' is already registered", name)
}
if factory == nil {
return fmt.Errorf("module '%s' cannot be registered with a nil factory", name)
}
r.modules[name] = factory
logp.Info("Module registered: %s", name)
return nil
}
// AddMetricSet registers a new MetricSetFactory. Optionally it accepts a single
// HostParser function for parsing the 'host' configuration data. An error is
// returned if any parameter is empty or nil or if a factory has already been
// registered under the name.
//
// Use MustAddMetricSet for new code.
func (r *Register) AddMetricSet(module string, name string, factory MetricSetFactory, hostParser ...HostParser) error {
var opts []MetricSetOption
if len(hostParser) > 0 {
opts = append(opts, WithHostParser(hostParser[0]))
}
return r.addMetricSet(module, name, factory, opts...)
}
// MustAddMetricSet registers a new MetricSetFactory. It panics if any parameter
// is empty or nil OR if a factory has already been registered under this name.
func (r *Register) MustAddMetricSet(module, name string, factory MetricSetFactory, options ...MetricSetOption) {
if err := r.addMetricSet(module, name, factory, options...); err != nil {
panic(err)
}
}
// addMetricSet registers a new MetricSetFactory. An error is returned if any
// parameter is empty or nil or if a factory has already been registered under
// the name.
func (r *Register) addMetricSet(module, name string, factory MetricSetFactory, options ...MetricSetOption) error {
r.lock.Lock()
defer r.lock.Unlock()
if module == "" {
return fmt.Errorf("module name is required")
}
if name == "" {
return fmt.Errorf("metricset name is required")
}
module = strings.ToLower(module)
name = strings.ToLower(name)
if metricsets, ok := r.metricSets[module]; !ok {
r.metricSets[module] = map[string]MetricSetRegistration{}
} else if _, exists := metricsets[name]; exists {
return fmt.Errorf("metricset '%s/%s' is already registered", module, name)
}
if factory == nil {
return fmt.Errorf("metricset '%s/%s' cannot be registered with a nil factory", module, name)
}
// Set the options.
msInfo := MetricSetRegistration{Name: name, Factory: factory}
for _, opt := range options {
opt(&msInfo)
}
r.metricSets[module][name] = msInfo
logp.Info("MetricSet registered: %s/%s", module, name)
return nil
}
// moduleFactory returns the registered ModuleFactory associated with the
// given name. It returns nil if no ModuleFactory is registered.
func (r *Register) moduleFactory(name string) ModuleFactory {
r.lock.RLock()
defer r.lock.RUnlock()
return r.modules[strings.ToLower(name)]
}
// metricSetRegistration returns the registration data associated with the given
// metricset name. It returns an error if no metricset is registered.
func (r *Register) metricSetRegistration(module, name string) (MetricSetRegistration, error) {
r.lock.RLock()
defer r.lock.RUnlock()
module = strings.ToLower(module)
name = strings.ToLower(name)
metricSets, exists := r.metricSets[module]
if !exists {
return MetricSetRegistration{}, fmt.Errorf("metricset '%s/%s' is not registered, module not found", module, name)
}
registration, exists := metricSets[name]
if !exists {
return MetricSetRegistration{}, fmt.Errorf("metricset '%s/%s' is not registered, metricset not found", module, name)
}
return registration, nil
}
// DefaultMetricSets returns the names of the default MetricSets for a module.
// An error is returned if no default MetricSet is declared or the module does
// not exist.
func (r *Register) DefaultMetricSets(module string) ([]string, error) {
r.lock.RLock()
defer r.lock.RUnlock()
module = strings.ToLower(module)
metricSets, exists := r.metricSets[module]
if !exists {
return nil, fmt.Errorf("module '%s' not found", module)
}
var defaults []string
for _, reg := range metricSets {
if reg.IsDefault {
defaults = append(defaults, reg.Name)
}
}
if len(defaults) == 0 {
return nil, fmt.Errorf("no default metricset exists for module '%s'", module)
}
return defaults, nil
}
// Modules returns the list of module names that are registered
func (r *Register) Modules() []string {
r.lock.RLock()
defer r.lock.RUnlock()
modules := make([]string, 0, len(r.modules))
for module := range r.modules {
modules = append(modules, module)
}
return modules
}
// MetricSets returns the list of MetricSets registered for a given module
func (r *Register) MetricSets(module string) []string {
r.lock.RLock()
defer r.lock.RUnlock()
var metricsets []string
sets, ok := r.metricSets[strings.ToLower(module)]
if ok {
metricsets = make([]string, 0, len(sets))
for name := range sets {
metricsets = append(metricsets, name)
}
}
return metricsets
}
// String return a string representation of the registered ModuleFactory's and
// MetricSetFactory's.
func (r *Register) String() string {
r.lock.RLock()
defer r.lock.RUnlock()
var modules []string
for module := range r.modules {
modules = append(modules, module)
}
sort.Strings(modules)
var metricSets []string
for module, m := range r.metricSets {
for name := range m {
metricSets = append(metricSets, fmt.Sprintf("%s/%s", module, name))
}
}
sort.Strings(metricSets)
return fmt.Sprintf("Register [ModuleFactory:[%s], MetricSetFactory:[%s]]",
strings.Join(modules, ", "), strings.Join(metricSets, ", "))
}