apfel

package
v0.10.4 Latest Latest
Warning

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

Go to latest
Published: Nov 14, 2021 License: GPL-3.0 Imports: 22 Imported by: 4

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

Constants

This section is empty.

Variables

View Source
var ConfigCodec = flu.YAML

ConfigCodec is used for binary configuration representation.

View Source
var DefaultMetricsConfigurer = MetricsConfigurers{
	PrometheusConfigurer{},
	DummyMetricsConfigurer{Log: true},
}

DefaultMetricsConfigurer is used in Core.GetMetricsRegistry.

View Source
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.

View Source
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 GetCodec

func GetCodec(extension string) flu.Codec

GetCodec resolves the flu.Codec using the provided extension.

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.

func (Config) As

func (cfg Config) As(value interface{}) error

As reads the configuration as provided value.

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

type ConfigurerFunc func() (Map, error)

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 New

func New(version string, clock flu.Clock) *Core

New collects the configuration from Configurer and creates a new *Core instance.

func (*Core) Aux

func (app *Core) Aux() (bool, error)

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) Close

func (app *Core) Close() error

Close closes the context and shuts down the application.

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) GetConfig

func (app *Core) GetConfig() Config

GetConfig returns the configuration.

func (*Core) GetDatabase

func (app *Core) GetDatabase(driver, conn string) (*gorm.DB, error)

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

func (app *Core) GetGormConfig() *gorm.Config

GetGormConfig returns the *gorm.Config used to create *gorm.DB instances via GetDatabase().

func (*Core) GetMetricsRegistry

func (app *Core) GetMetricsRegistry(ctx context.Context) (me3x.Registry, error)

GetMetricsRegistry returns the me3x.Registry configured with the DefaultMetricsConfigurer.

func (*Core) GetVersion

func (app *Core) GetVersion() string

GetVersion returns the "version" parameter from New().

func (*Core) Manage

func (app *Core) Manage(service interface{})

Manage adds the service to lifecycle management.

func (*Core) Now

func (app *Core) Now() time.Time

Now returns the current time using the "clock" parameter from New().

func (*Core) SetConfig

func (app *Core) SetConfig(values Map) error

SetConfig sets the configuration values.

type DummyMetricsConfigurer

type DummyMetricsConfigurer struct {
	Log bool
}

func (DummyMetricsConfigurer) Configure

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

type GormDialect func(conn string) gorm.Dialector

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

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 LogFile

type LogFile *os.File

LogFile is a convenience type to distinguish log files from ordinary ones.

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) AsConfig

func (m Map) AsConfig() (Config, error)

AsConfig creates a Config from this Map.

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) Merge

func (m Map) Merge(other Map)

Merge merges the other Map into this one, overriding values if necessary.

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

func (m *Map) UnmarshalJSON(data []byte) error

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

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

Jump to

Keyboard shortcuts

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