viperutil

package
v0.19.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2024 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package viperutil provides a utility layer to streamline and standardize interacting with viper-backed configuration values across vitess components.

The common pattern is for a given module to declare their values by declaring variables that are the result of calling Configure, for example in package trace:

package trace

import "vitess.io/vitess/go/viperutil"

var (
	modulePrefix = viperutil.KeyPrefixFunc("trace")

	tracingServer = viperutil.Configure(
		modulePrefix("service"),
		viperutil.Options[string]{
			Default: "noop",
			FlagName: "tracer",
		}
	)
	enableLogging = viperutil.Configure(
		modulePrefix("enable-logging"),
		viperutil.Options[bool]{
			FlagName: "tracing-enable-logging",
		}
	)
)

Then, in an OnParseFor or OnParse hook, declare any flags, and bind viper values to those flags, as appropriate:

package trace

import (
	"github.com/spf13/pflag"

	"vitess.io/vitess/go/viperutil"
	"vitess.io/vitess/go/vt/servenv"
)

func init() {
	servenv.OnParse(func(fs *pflag.FlagSet) {
		fs.String("tracer", tracingServer.Default(), "<usage for flag goes here>")
		fs.Bool("tracing-enable-logging", enableLogging.Default(), "<usage for flag goes here>")

		viperutil.BindFlags(fs, tracingServer, enableLogging)
	})
}

Finally, after a call to `viperutil.LoadConfig` (which is done as a part of `servenv.ParseFlags`), values may be accessed by calling their `.Get()` methods.

For more details, refer to the package documentation, as well as the documents in doc/viper/.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDuplicateWatch is returned when Watch is called multiple times on a
	// single synced viper. Viper only supports reading/watching a single
	// config file.
	ErrDuplicateWatch = sync.ErrDuplicateWatch
	// ErrNoFlagDefined is returned from Value's Flag method when the value was
	// configured to bind to a given FlagName but the provided flag set does not
	// define a flag with that name.
	ErrNoFlagDefined = value.ErrNoFlagDefined
)

Functions

func BindFlags

func BindFlags(fs *pflag.FlagSet, values ...value.Registerable)

BindFlags binds a set of Registerable values to the given flag set.

This function will panic if any of the values was configured to map to a flag which is not defined on the flag set. Therefore, this function should usually be called in an OnParse or OnParseFor hook after defining the flags for the values in question.

func GetFuncForType

func GetFuncForType[T any]() func(v *viper.Viper) func(key string) T

GetFuncForType returns the default getter function for a given type T. A getter function is a function which takes a viper and returns a function that takes a key and (finally!) returns a value of type T.

For example, the default getter for a value of type string is a function that takes a viper instance v and calls v.GetString with the provided key.

In most cases, callers of Configure should be able to rely on the defaults provided here (and may refer to get_func_test.go for an up-to-date example of the provided functionalities), but if more fine-grained control is needed (this should be an **exceptional** circumstance), they may provide their own GetFunc as an option to Configure.

This function may panic if called for an unsupported type. This is captured in the test code as well.

func KeyPrefixFunc

func KeyPrefixFunc(prefix string) func(subkey string) (fullkey string)

KeyPrefixFunc is a helper function to allow modules to extract a common key prefix used by that module to avoid repitition (and typos, missed updates, and so on).

For example, package go/vt/vttablet/schema may want to do:

moduleKey := viperutil.KeyPrefixFunc("vttablet.schema")
watch := viperutil.Configure(moduleKey("watch_interval"), ...) // => "vttablet.schema.watch_interval"
// ... and so on

func LoadConfig

func LoadConfig() (context.CancelFunc, error)

LoadConfig attempts to find, and then load, a config file for viper-backed config values to use.

Config searching follows the behavior used by viper 1, namely:

  • --config-file (full path, including extension) if set will be used to the exclusion of all other flags.
  • --config-type is required if the config file does not have one of viper's supported extensions (.yaml, .yml, .json, and so on)

An additional --config-file-not-found-handling flag controls how to treat the situation where viper cannot find any config files in any of the provided paths (for ex, users may want to exit immediately if a config file that should exist doesn't for some reason, or may wish to operate with flags and environment variables alone, and not use config files at all).

If a config file is successfully loaded, then the dynamic registry will also start watching that file for changes. In addition, in-memory changes to the config (for example, from a vtgate or vttablet's debugenv) will be persisted back to disk, with writes occuring no more frequently than the --config-persistence-min-interval flag.

A cancel function is returned to stop the re-persistence background thread, if one was started.

func NotifyConfigReload

func NotifyConfigReload(ch chan<- struct{})

NotifyConfigReload adds a subscription that the dynamic registry will attempt to notify on config changes. The notification fires after the updated config has been loaded from disk into the live config.

Analogous to signal.Notify, notifications are sent non-blocking, so users should account for this when writing code to consume from the channel.

This function must be called prior to LoadConfig; it will panic if called after the dynamic registry has started watching the loaded config.

func RegisterFlags

func RegisterFlags(fs *pflag.FlagSet)

RegisterFlags installs the flags that control viper config-loading behavior. It is exported to be called by servenv before parsing flags for all binaries.

It cannot be registered here via servenv.OnParse since this causes an import cycle.

Types

type ConfigFileNotFoundHandling

type ConfigFileNotFoundHandling int

ConfigFileNotFoundHandling is an enum to control how LoadConfig treats errors of type viper.ConfigFileNotFoundError when loading a config.

const (
	// IgnoreConfigFileNotFound causes LoadConfig to completely ignore a
	// ConfigFileNotFoundError (i.e. not even logging it).
	IgnoreConfigFileNotFound ConfigFileNotFoundHandling = iota
	// WarnOnConfigFileNotFound causes LoadConfig to log a warning with details
	// about the failed config load, but otherwise proceeds with the given
	// process, which will get config values entirely from defaults,
	// envirnoment variables, and flags.
	WarnOnConfigFileNotFound
	// ErrorOnConfigFileNotFound causes LoadConfig to return the
	// ConfigFileNotFoundError after logging an error.
	ErrorOnConfigFileNotFound
	// ExitOnConfigFileNotFound causes LoadConfig to log.Fatal on a
	// ConfigFileNotFoundError.
	ExitOnConfigFileNotFound
)

func (*ConfigFileNotFoundHandling) Set

func (*ConfigFileNotFoundHandling) String

func (h *ConfigFileNotFoundHandling) String() string

func (*ConfigFileNotFoundHandling) Type

type Options

type Options[T any] struct {
	// Aliases, if set, configures the Value to be accessible via additional
	// keys.
	//
	// This is useful for deprecating old names gracefully while maintaining
	// backwards-compatibility.
	Aliases []string
	// FlagName, if set, allows a value to be configured to also check the
	// named flag for its final config value. If depending on a flag, BindFlags
	// must be called on the Value returned from Configure. In most cases,
	// modules will do this in the same OnParse hook that defines their flags.
	//
	// Note that if the set FlagName does not match the Value's key, Configure
	// will automatically register an alias to allow both names to be used as
	// the key, which is necessary for the flag value to be discoverable by
	// viper for the Value's actual key.
	FlagName string
	// EnvVars, if set, configures the Value to also check the given environment
	// variables for its final config value.
	//
	// Note that unlike keys and aliases, environment variable names are
	// case-sensitive.
	EnvVars []string
	// Default is the default value that will be set for the key. If not
	// explicitly set during a call to Configure, the default value will be the
	// zero value for the type T. This means if T is a pointer type, the default
	// will be nil, not the zeroed out struct.
	Default T

	// Dynamic, if set, configures a value to be backed by the dynamic registry.
	// If a config file is used (via LoadConfig), that file will be watched for
	// changes, and dynamic Values will reflect changes via their Get() methods
	// (whereas static values will only ever return the value loaded initially).
	Dynamic bool

	// GetFunc is the function used to get this value out of a viper.
	//
	// If omitted, GetFuncForType will attempt to provide a useful default for
	// the given type T. For primitive types, this should be sufficient. For
	// more fine-grained control over value retrieval and unmarshalling, callers
	// should provide their own function.
	//
	// See GetFuncForType for further details.
	GetFunc func(v *viper.Viper) func(key string) T
}

Options represents the various options used to control how Values are configured by viperutil.

type Value

type Value[T any] interface {
	value.Registerable

	// Get returns the current value. For static implementations, this will
	// never change after the initial config load. For dynamic implementations,
	// this may change throughout the lifetime of the vitess process.
	Get() T
	// Set sets the underlying value. For both static and dynamic
	// implementations, this is reflected in subsequent calls to Get.
	//
	// If a config file was loaded, changes to dynamic values will be persisted
	// back to the config file in the background, governed by the behavior of
	// the --config-persistence-min-interval flag.
	Set(v T)
	// Default returns the default value configured for this Value. For both
	// static and dynamic implementations, it should never change.
	Default() T
}

Value represents the public API to access viper-backed config values.

N.B. the embedded value.Registerable interface is necessary only for BindFlags and other mechanisms of binding Values to the internal registries to work. Users of Value objects should only need to call Get(), Set(v T), and Default().

func Configure

func Configure[T any](key string, opts Options[T]) (v Value[T])

Configure configures a viper-backed value associated with the given key to either the static or dynamic internal registries, returning the resulting Value. This value is partially ready for use (it will be able to get values from environment variables and defaults), but file-based configs will not available until servenv calls LoadConfig, and flag-based configs will not be available until a combination of BindFlags and pflag.Parse have been called, usually by servenv.

Exact behavior of how the key is bound to the registries depend on the Options provided,

Directories

Path Synopsis
internal
log
Package log provides dual-use logging between vitess's vt/log package and viper's jww log.
Package log provides dual-use logging between vitess's vt/log package and viper's jww log.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL