Documentation ¶
Overview ¶
apfel contains utilities for generic application configuration and basic lifecycle management (setup/teardown). A common application would define its own Instance struct with embedded *apfel.Core and containing all the application-specific context while also providing initialization and execution methods. See example below.
package main import ( "context" "github.com/jfk9w-go/flu" "github.com/jfk9w-go/flu/apfel" "github.com/pkg/errors" "gorm.io/driver/postgres" "gorm.io/gorm" ) // Instance describes a dummy application type Instance struct { *apfel.Core dbconn string } // Create creates a new application instance. func Create(version string, clock flu.Clock, configurer apfel.Configurer) (apfel.Interface, error) { core, err := apfel.New(version, clock, configurer) if err != nil { return nil, errors.Wrap(err, "initialize") } // configure default logging via logrus if err := core.ConfigureLogging(); err != nil { return nil, errors.Wrap(err, "configure logging") } return &Instance{ Core: core, }, nil } // GetDefaultDatabase returns (creates if necessary) the connection for default application database. // It expectes a postgresql://... connection string (for PostgreSQL). // The method allows to get the database connection on demand when initializing other services. func (app *Instance) GetDefaultDatabase() (*gorm.DB, error) { if app.dbconn == "" { config := new(struct{ Database string }) if err := app.GetConfig().As(config); err != nil { return nil, errors.Wrap(err, "get db config") } app.dbconn = config.Database } return app.GetDatabase("postgres", app.dbconn) } // Run sets up the required services and runs the application. func (app *Instance) Run(ctx context.Context) error { return nil } // GitCommit contains the current commit SHA-1. // Compile the application with -ldflags "-X main.GitCommit=$(git rev-parse HEAD)" var GitCommit = "dev" // start with // go run main.go --database postgresql://username:password@host:port/db // or // TESTAPP_DATABASE=postgresql://username:password@host:port/db go run main.go // or even with // echo "database: postgresql://username:password@host:port/db" | go run main.go --config.stdin=yaml func main() { // provide GormDialect for postgres apfel.GormDialects["postgres"] = postgres.Open // this context will be cancelled when main() completes // and cancel all nested contexts which is used for lifecycle management ctx, cancel := context.WithCancel(context.Background()) defer cancel() // create and run the app instance configurer := apfel.DefaultConfigurer("testapp") app := Create(GitCommit, flu.DefaultClock) apfel.Run(ctx, app, configurer) // await for SIGKILL, SIGINT, etc. in case of starting the async application flu.AwaitSignal() }
Index ¶
- Variables
- func GetCodec(extension string) flu.Codec
- func Run(ctx context.Context, app Lifecycle, configurer Configurer)
- func SpecifyType(value string) interface{}
- type Config
- type Configurer
- type ConfigurerFunc
- type Configurers
- type Core
- func (app *Core) Aux() (bool, error)
- func (app *Core) Close() error
- func (app *Core) Configure(configurer Configurer) error
- func (app *Core) GetConfig() Config
- func (app *Core) GetDatabase(driver, conn string) (*gorm.DB, error)
- func (app *Core) GetGormConfig() *gorm.Config
- func (app *Core) GetMetricsRegistry(ctx context.Context) (me3x.Registry, error)
- func (app *Core) GetVersion() string
- func (app *Core) Manage(service interface{})
- func (app *Core) Now() time.Time
- func (app *Core) SetConfig(values Map) error
- type DummyMetricsConfigurer
- type FromInputConfigurer
- type FromKeyValueConfigurer
- type GormDialect
- type GraphiteConfigurer
- type Lifecycle
- type LogFile
- type LoggingApplication
- type LoggingConfigurer
- type Map
- type MeteredApplication
- type MetricsConfigurer
- type MetricsConfigurers
- type PrometheusConfigurer
Constants ¶
This section is empty.
Variables ¶
var ConfigCodec = flu.YAML
ConfigCodec is used for binary configuration representation.
var DefaultMetricsConfigurer = MetricsConfigurers{ PrometheusConfigurer{}, DummyMetricsConfigurer{Log: true}, }
DefaultMetricsConfigurer is used in Core.GetMetricsRegistry.
var ExtensionCodecs = map[string]flu.Codec{ "json": flu.JSON, "yaml": flu.YAML, "yml": flu.YAML, "xml": flu.XML, "gob": flu.Gob, }
ExtensionCodecs is an index of flu.Codecs by their common file extensions.
var GormDialects = make(map[string]GormDialect)
GormDialects is a map of supported GormDialects (indexed by driver names). It is empty by default. End applications are supposed to fill it with required dialects.
Functions ¶
func Run ¶
func Run(ctx context.Context, app Lifecycle, configurer Configurer)
Run executes the application using the default workflow (configure -> show -> run).
func SpecifyType ¶
func SpecifyType(value string) interface{}
SpecifyTypes tries to convert the string to most specific primitive type (int64, float64, or bool). If it fails, it returns the input value as is.
Types ¶
type Config ¶
type Config struct { // Map is a deserialized configuration. // Can be used to access parameters directly (beware of type specification). Map // Bytes is a binary configuration representation. flu.Bytes }
Config is a generic application configuration.
func Configure ¶
func Configure(configurer Configurer) (Config, error)
Configure produces a Config using the specified Configurer.
type Configurer ¶
type Configurer interface { // Configure yield a Map containing configuration options. Configure() (Map, error) }
Configurer reads the configuration values as Map.
func Arguments ¶
func Arguments(args []string, ignores ...string) Configurer
Arguments produces a Properties instance for parsing command-line arguments. Ignored configuration options may be specified with ignores vararg. For example, the following command-line arguments:
--appname=test-app --service.name=test-service --service.enabled=true OR --service.enabled --service.threshold=0.05 --service.instances=10 --service.true=enabled --service.10=instances
with Arguments(os.Args[1:]) call would yield the following configuration:
Map{ "appname": "test-app", "service": Map{ "name": "test-service", "enabled": bool(true), "threshold": float64(0.05), "instances": int64(10), bool(true): "enabled", int64(10): "instances", }, }
func DefaultConfigurer ¶
func DefaultConfigurer(appName string) Configurer
DefaultConfigurer provides the default Configurer suitable for most applications. It reads the configuration from following sources (overriding values in the same order):
1. Configuration files and stdin using the provided --config.file and --config.stdin CLI arguments (see FromInputConfigurer).
2. Environment variables prefixed with the provided application name in upper case with dashes replaced with underscores (see Environ).
3. Options provided as command-line arguments (see Arguments).
func Environ ¶
func Environ(environ []string, prefix string) Configurer
Environ produces a Properties instance for parsing configuration from environment variables with the specified prefix. Nested option keys are separated with underscore (_). Options with underscores in the name are not supported. For example, using the following environment variables:
TEST_APPNAME=test-app TEST_SERVICE_NAME=test-service TEST_SERVICE_ENABLED=true TEST_SERVICE_THRESHOLD=0.05 TEST_SERVICE_INSTANCES=10 TEST_SERVICE_TRUE=enabled TEST_SERVICE_10=instances
with Environ(os.Environ(), "TEST_") call would yield the following configuration:
Map{ "appname": "test-app", "service": Map{ "name": "test-service", "enabled": bool(true), "threshold": float64(0.05), "instances": int64(10), bool(true): "enabled", int64(10): "instances", }, }
type ConfigurerFunc ¶
ConfigurerFunc is an adapter for lambdas.
func (ConfigurerFunc) Configure ¶
func (f ConfigurerFunc) Configure() (Map, error)
type Configurers ¶
type Configurers []Configurer
Configurers is the umbrella Configurer for multiple Configurers. It merges the Map from each Configurer in the order of appearance into one global Map and returns it as the result. Failures are reported as warnings and do not interrupt execution.
func (Configurers) Configure ¶
func (cs Configurers) Configure() (Map, error)
func (Configurers) Labels ¶
func (cs Configurers) Labels() me3x.Labels
func (Configurers) String ¶
func (cs Configurers) String() string
type Core ¶
type Core struct {
// contains filtered or unexported fields
}
Core is an application core. It provides some common utilities for configuration and context setup (also shutdown).
func (*Core) Aux ¶
Aux prints the debug information if respective configuration options are provided. End application should call this method right after initialization and exit immediately if it returns "true". Supported options: show.config, show.version
func (*Core) Configure ¶
func (app *Core) Configure(configurer Configurer) error
Configure configures the application using the specified Configurer. It also configures logging with DefaultLoggingConfigurer.
func (*Core) GetDatabase ¶
GetDatabase returns the *gorm.DB instance (creating if necessary) for the provided driver and connection string. Driver should be registered via GormDialects.
func (*Core) GetGormConfig ¶
GetGormConfig returns the *gorm.Config used to create *gorm.DB instances via GetDatabase().
func (*Core) GetMetricsRegistry ¶
GetMetricsRegistry returns the me3x.Registry configured with the DefaultMetricsConfigurer.
func (*Core) GetVersion ¶
GetVersion returns the "version" parameter from New().
func (*Core) Manage ¶
func (app *Core) Manage(service interface{})
Manage adds the service to lifecycle management.
type DummyMetricsConfigurer ¶
type DummyMetricsConfigurer struct {
Log bool
}
func (DummyMetricsConfigurer) Configure ¶
func (c DummyMetricsConfigurer) Configure(ctx context.Context, app MeteredApplication) (me3x.Registry, error)
type FromInputConfigurer ¶
type FromInputConfigurer struct { // Args is a collection of command-line arguments (most commonly os.Args[1:]). Args []string // Stdin is the standard input (most commonly os.Stdin). Stdin flu.Input // FileOption is the option which will be used for supplying configuration file paths // (most commonly "config.file" for --config.file=config.yml style arguments). FileOption string // StdinOption is the option which will be used for supplying the stdin configuration codec // (most commonly "config.stdin" for --config.stdin=json style arguments). // If the stdin option is not specified in the argument list, the configurer will not read stdin. StdinOption string }
FromInputConfigurer reads configuration file paths as arguments from command line and parses the provided files. The codec is detected based on file extension (see supported extensions in ExtensionCodecs). The configurer also supports reading the configuration from stdin using the supplied codec. The configuration is merged from all sources, overriding options from respective sources in the order of appearance. This allows for building highly modular configurations with default values. An error (absent file, invalid format, etc.) causes a warning in logs, but does not interrupt execution.
func (*FromInputConfigurer) Configure ¶
func (c *FromInputConfigurer) Configure() (Map, error)
func (*FromInputConfigurer) Labels ¶
func (c *FromInputConfigurer) Labels() me3x.Labels
func (*FromInputConfigurer) String ¶
func (c *FromInputConfigurer) String() string
type FromKeyValueConfigurer ¶
type FromKeyValueConfigurer struct { // Prefix is an optional prefix for configuration options. // If set, only the options with this prefix are read, // and the prefix is stripped from option key. Prefix string // PathSeparator is used for separating nested configuration keys (for example, service.instance.name contains . as a separator). PathSeparator string // Separator is a key-value separator. Separator string // Lines is a collection of strings containing key-value pairs. Lines []string // Except is a collection of option regexes which should be ignored when reading configuration from Lines. Except flu.StringSet }
FromKeyValueConfigurer is used to read configuration as key-value pairs from a collection of string values. Nested option keys are joined using the PathSeparator. Type specification is performed on keys as well as values (and nested objects). Please note that this Configurer does not support options with array values. Having a nested and simple value for the same key (for example, APP_OPTIONS=a and APP_OPTIONS_DEBUG=true) will cause a warning and preference of the option with the longest path (converting into Map and overwriting all of its parents).
func (*FromKeyValueConfigurer) Configure ¶
func (c *FromKeyValueConfigurer) Configure() (Map, error)
func (*FromKeyValueConfigurer) Labels ¶
func (c *FromKeyValueConfigurer) Labels() me3x.Labels
func (*FromKeyValueConfigurer) String ¶
func (c *FromKeyValueConfigurer) String() string
type GormDialect ¶
GormDialect is a function providing gorm.Dialector for a connection string.
type GraphiteConfigurer ¶
type GraphiteConfigurer struct { // HistogramBucketFormat is a format string used for formatting histogram bucket values. HistogramBucketFormat string }
GraphiteConfigurer configures Graphite metrics reporter.
func (GraphiteConfigurer) Configure ¶
func (c GraphiteConfigurer) Configure(ctx context.Context, app MeteredApplication) (me3x.Registry, error)
type Lifecycle ¶
type Lifecycle interface { // Configure configures the application using the provided Configurer. Configure(Configurer) error // Aux is intended for immediate processing of various print // and debug commands like --show.version, --show.config, etc. // Returns false if no command was specified. Aux() (bool, error) // Run sets up internal services and runs the application (does actual work). Run(context.Context) error }
Lifecycle is an application interface intended primarily for Run pipeline.
type LoggingApplication ¶
type LoggingApplication interface { // GetConfig returns the application configuration. GetConfig() Config // GetGormConfig returns the *gorm.Config instance used for creating *gorm.DBs. GetGormConfig() *gorm.Config // Manage applies lifecycle management if possible. Manage(interface{}) }
LoggingApplication is an application interface for logging configurers.
type LoggingConfigurer ¶
type LoggingConfigurer interface {
Configure(LoggingApplication) error
}
LoggingConfigurer configures (or not) logging based on parsed configuration.
var DefaultLoggingConfigurer LoggingConfigurer = LogrusConfigurer
DefaultLoggingConfigurer is used in Core.Configure.
var LogrusConfigurer LoggingConfigurer = logrusConfigurer{}
LogrusConfigurer configures github.com/sirupsen/logrus package.
var NoOpLoggingConfigurer LoggingConfigurer = noOpLoggingConfigurer{}
NoOpLoggingConfigurer does nothing.
type Map ¶
type Map map[interface{}]interface{}
Map is a generic key-value container.
func (*Map) Get ¶
func (m *Map) Get(path ...interface{}) interface{}
Get obtains the value from Map. It panics if the value is nil (or not found).
func (Map) GetOptional ¶
func (m Map) GetOptional(path ...interface{}) interface{}
GetOptional gets the possibly nested value pointed by path from Map. May return nil.
func (Map) SpecifyTypes ¶
func (m Map) SpecifyTypes()
SpecifyTypes performs type specification on all keys and string values. It also converts map[string]interface{} values to Maps, and recursively calls SpecifyTypes on all Map values.
func (*Map) UnmarshalJSON ¶
type MeteredApplication ¶
type MeteredApplication interface { // GetConfig returns the application configuration. GetConfig() Config // Manage applies lifecycle management if possible. Manage(interface{}) }
MeteredApplication is an application interface for metrics configurers.
type MetricsConfigurer ¶
type MetricsConfigurer interface {
Configure(ctx context.Context, app MeteredApplication) (me3x.Registry, error)
}
MetricsConfigurer configures metrics reporting framework.
func AnyMetricsConfigurer ¶
func AnyMetricsConfigurer(dummyLog bool) MetricsConfigurer
AnyMetricsConfigurer returns a configurer with all supported frameworks.
type MetricsConfigurers ¶
type MetricsConfigurers []MetricsConfigurer
MetricsConfigurers is an umbrella configurer which tries all configurers in the slice until it succeeds.
func (MetricsConfigurers) Configure ¶
func (cs MetricsConfigurers) Configure(ctx context.Context, app MeteredApplication) (me3x.Registry, error)
type PrometheusConfigurer ¶
type PrometheusConfigurer struct { // Collectors will be used when creating metrics registry. // If nil, default ones will be applied. Collectors []prometheus.Collector }
PrometheusConfigurer configures Prometheus metrics registry.
func (PrometheusConfigurer) Configure ¶
func (c PrometheusConfigurer) Configure(ctx context.Context, app MeteredApplication) (me3x.Registry, error)