app

package
v0.0.0-...-a32d5fc Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2017 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package app provides the application service model and platform for building message driven concurrent and distributed services.

Design Principles

  1. High performance. Prove it through benchmarking.

  2. Concurrency safe. Always design the service to be safely used by concurrent goroutines. - Prefer immutability - Prefer channels - use locks as a last resort

  3. Services define their dependencies as functions.

  4. One service per package, i.e., the package is the service. Public functions exposed by the package are the service interface.

  5. Each service package will initialize itself automatically, i.e., via package init() functions. Each service package will register itself with the app.Application service.

  6. Graceful application shutdown : when the application is killed, all registered services will be killed. The application will wait until all services are dead before exiting. - The following OS signals will trigger graceful application shutdown : SIGINT, SIGTERM, SIGQUIT

  7. All key components will be assigned a unique numeric id (uint64) for tracking and traceability purposes. - DomainID - AppID - ReleaseID - app release id - ServiceID - ErrorID - LogEventID

    Most systems prefer instead to define a symbolic global namespace , but this would have some important disadvantages:

  8. Programmers often feel the need to change symbolic names and organization in order to make their code cleaner, but the renamed code should still work with existing encoded data.

  9. It’s easy for symbolic names to collide, and these collisions could be hard to detect in a large distributed system with many different binaries.

  10. Fully-qualified type names may be large and waste space when transmitted on the wire.

  11. Config is typesafe and secure. - Each service will define its config via capnp. The config will be self contained. - Configurations will be encrypted. - Docker secrets (https://docs.docker.com/engine/swarm/secrets/) will be supported

  12. RPC network communication will be secured via mutual TLS - capnp RPC will be supported

Index

Constants

View Source
const (
	// for errors that have not been anticipated or not yet customized to your system
	ErrorType_BUG = ErrorType(iota)
	// e.g. broken network connections, IO errors, service not available, etc
	ErrorType_KNOWN_EDGE_CASE
	// misconfiguration or missing configuration
	ErrorType_Config
)

ErrorType enum values

View Source
const (
	ErrorSeverity_LOW = ErrorSeverity(iota)
	ErrorSeverity_MEDIUM
	ErrorSeverity_HIGH
	// should cause the app to terminate, i.e. trigger a panic
	ErrorSeverity_FATAL
)

ErrorSeverity enum values

View Source
const (
	HEALTHCHECK_SERVICE_ID = ServiceID(0xe105d0909fcc5ec5)

	HEALTHCHECK_METRIC_LABEL           = "healthcheck" // the label value will be the HealthCheckID in hex format
	HEALTHCHECK_METRIC_ID              = MetricID(0x844d7830332bffd3)
	HEALTHCHECK_RUN_DURATION_METRIC_ID = MetricID(0xcd4260d6e89ad9c6)

	DEFAULT_HEALTHCHECK_RUN_INTERVAL = 5 * time.Minute
	DEFAULT_HEALTHCHECK_RUN_TIMEOUT  = 5 * time.Second

	HEALTHCHECK_ID_LOG_FIELD = "healthcheck"
)

healthcheck constants

View Source
const (
	APP_STARTED          = LogEventID(0xa482715a50d67a5f)
	APP_STOPPING         = LogEventID(0xbcdae48c0cb8936e)
	APP_STOPPING_TIMEOUT = LogEventID(0xaa7744d8a20d857a)
	APP_STOPPED          = LogEventID(0xdd0c7775e42d7841)
	APP_RESET            = LogEventID(0xee317bbb0fe0fafe)

	// it is the service's responsibility to log the following Service lifecycle events
	SERVICE_STARTING = LogEventID(0xa3c3eb887d09f9aa)
	SERVICE_STARTED  = LogEventID(0xc27a49a4e5a2a502)

	// the below events are logged by the app using the service logger
	SERVICE_KILLED           = LogEventID(0x85adf7d70dcef626)
	SERVICE_STOPPING         = LogEventID(0x85adbb661141efce)
	SERVICE_STOPPING_TIMEOUT = LogEventID(0x8ed2e400ce585f16)
	SERVICE_STOPPED          = LogEventID(0xfd843c25ce81f841)
	SERVICE_REGISTERED       = LogEventID(0xd8f25797ffa58858)
	SERVICE_UNREGISTERED     = LogEventID(0xa611d10b1dfc880d)

	METRICS_SERVICE_CONFIG_ERROR = LogEventID(0x83ad8592584d0930)

	METRICS_HTTP_REPORTER_SHUTDOWN_ERROR                 = LogEventID(0xab355f6933e9b3fe)
	METRICS_HTTP_REPORTER_START_ERROR                    = LogEventID(0xa1e82667eef867ff)
	METRICS_HTTP_REPORTER_SHUTDOWN_WHILE_SERVICE_RUNNING = LogEventID(0xf8c787086a35cd78)

	METRICS_HTTP_SERVER_STARTING = LogEventID(0xbec4ba15afa97c2b)
	METRICS_HTTP_SERVER_STARTED  = LogEventID(0x8fab3d9ef5011368)
	METRICS_HTTP_SERVER_STOPPED  = LogEventID(0xefd0f72bffc636f6)

	CONFIG_LOADING_ERR = LogEventID(0x83e927cb25aaa032)

	CAPNP_ERR = LogEventID(0x823407a4ed427f33)

	ZERO_HEALTHCHECKS      = LogEventID(0x8c805853a70ec666)
	HEALTHCHECK_REGISTERED = LogEventID(0xb5f3142d410a2375)
	HEALTHCHECK_PAUSED     = LogEventID(0xc7a3b54188e75210)
	HEALTHCHECK_RESUMED    = LogEventID(0xc4dc7b2938caf3a9)
	HEALTHCHECK_RESULT     = LogEventID(0xa68e0475cc1839be)
)

log events

View Source
const (
	METRICS_SERVICE_ID               = ServiceID(0xe3054017c1b1d214)
	DEFAULT_METRICS_HTTP_PORT uint16 = 4444
)
View Source
const (
	APP_SERVICE = ServiceID(0)
)
View Source
const (
	CONFIG_SERVICE_ID = ServiceID(0x86813dd78fd207f5)
)
View Source
const (
	// BUG is for "unknown" errors, i.e., for errors that we did not anticipate
	ErrorID_BUG = ErrorID(0)
)

Variables

View Source
var (
	INFRASTRUCTURE_SERVICE_IDS = []ServiceID{
		CONFIG_SERVICE_ID,
		METRICS_SERVICE_ID,
		HEALTHCHECK_SERVICE_ID,
	}

	PID      = os.Getpid()
	HOSTNAME = func() string {
		name, err := os.Hostname()
		if err != nil {
			log.Panic().Err(err).Msg("os.Hostname() failed")
		}
		return name
	}()
)
View Source
var (
	Services       AppServices
	Configs        AppConfig
	MetricRegistry AppMetricRegistry
	HealthChecks   AppHealthChecks
)

app framework

View Source
var (
	ErrSpec_AppNotAlive   = ErrSpec{ErrorID: ErrorID(0xdf76e1927f240401), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_FATAL}
	ErrSpec_ConfigFailure = ErrSpec{ErrorID: ErrorID(0xe75f1a73534f382d), ErrorType: ErrorType_Config, ErrorSeverity: ErrorSeverity_FATAL}

	ErrSpec_ServiceInitFailed        = ErrSpec{ErrorID: ErrorID(0xec1bf26105c1a895), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_FATAL}
	ErrSpec_ServiceShutdownFailed    = ErrSpec{ErrorID: ErrorID(0xc24ac892db47da9f), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_MEDIUM}
	ErrSpec_ServiceNotAlive          = ErrSpec{ErrorID: ErrorID(0x9cb3a496d32894d2), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
	ErrSpec_ServiceNotRegistered     = ErrSpec{ErrorID: ErrorID(0xf34b64bac786f536), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
	ErrSpec_ServiceNotAvailable      = ErrSpec{ErrorID: ErrorID(0x8aae12f3016b7f50), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
	ErrSpec_ServiceAlreadyRegistered = ErrSpec{ErrorID: ErrorID(0xcfd879a478f9c733), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
	ErrSpec_IllegalArgument          = ErrSpec{ErrorID: ErrorID(0x9d95c5fac078b82c), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}

	ErrSpec_InvalidLogLevel = ErrSpec{ErrorID: ErrorID(0x814a17666a94fe39), ErrorType: ErrorType_Config, ErrorSeverity: ErrorSeverity_HIGH}

	ErrSpec_HealthCheckAlreadyRegistered = ErrSpec{ErrorID: ErrorID(0xdbfd6d9ab0049876), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_MEDIUM}
	ErrSpec_HealthCheckNotRegistered     = ErrSpec{ErrorID: ErrorID(0xefb3ffddac690f37), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_LOW}
	ErrSpec_HealthCheckNotAlive          = ErrSpec{ErrorID: ErrorID(0xe1972916f1c18dae), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
	ErrSpec_HealthCheckKillTimeout       = ErrSpec{ErrorID: ErrorID(0xf4ad6052397f6858), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
	ErrSpec_HealthCheckTimeout           = ErrSpec{ErrorID: ErrorID(0x8257a572526e13f4), ErrorType: ErrorType_KNOWN_EDGE_CASE, ErrorSeverity: ErrorSeverity_HIGH}
)

Functions

func Alive

func Alive() bool

Alive returns true if the app is still alive

func Dead

func Dead() <-chan struct{}

Dead returns a channel that signals the app has been shutdown

func DumpAllStacks

func DumpAllStacks(out io.Writer)

DumpAllStacks dumps all goroutine stacks to the specified writer. Used for troubleshooting purposes.

func Dying

func Dying() <-chan struct{}

Dying returns a channel that is used to signal that the app has been killed and shutting down

func IsError

func IsError(err error, errorID ErrorID) bool

IsError returns true if the error type is *Error and the ErrorID matches. Returns false if error is nil.

func Kill

func Kill()

Kill triggers app shutdown

func LogLevel

func LogLevel() zerolog.Level

LogLevel returns the application log level. If the command line is parsed, then the -loglevel flag will be inspected. Valid values for -loglevel are : [DEBUG,INFO,WARN,ERROR] If not specified on the command line, then the defauly value is INFO. The log level is used to configure the log level for loggers returned via NewTypeLogger() and NewPackageLogger(). It is also used to initialize zerolog's global logger level.

func Logger

func Logger() zerolog.Logger

Logger returns the app logger

func MarshalCapnpMessage

func MarshalCapnpMessage(msg *capnp.Message, out io.Writer) error

MarshalCapnpMessage marshals the capnp message to the writer. The message will be compressed using zlib.

func MetricSpecLabels

func MetricSpecLabels(serviceID ServiceID) prometheus.Labels

MetricSpecLabels returns the following labels:

  • domain : DomainID.Hex()
  • app : AppID.Hex
  • svc : ServiceID.Hex()
  • release : Release().Hex()
  • instance : Instance().Hex()

func MetricsServiceSpec

func MetricsServiceSpec() config.MetricsServiceSpec

func PrometheusName

func PrometheusName(metricSpec *MetricSpec) string

PrometheusName naming convention : op_{ServiceID.Hex()}_{MetricID.Hex()} e.g., op_e49214fa20b35ba8_db722ec1bb1b5766

func Reset

func Reset()

Reset is exposed only for testing purposes. Reset will :

  1. kill the app and then resurrect it with a new Tomb
  2. start the app server.
  3. start the app RPC server
  4. reset metrics
  5. start the metrics HTTP reporter
  6. reset healthchecks

func ResetWithConfigDir

func ResetWithConfigDir(configDir string)

func StartedOn

func StartedOn() time.Time

func UnmarshalCapnpMessage

func UnmarshalCapnpMessage(in io.Reader) (*capnp.Message, error)

UnmarshalCapnpMessage unmarshals the capnp message using the specified reader. The message should have have marshalled via MarshalCapnpMessage(), i.e., it must be zlib compressed.

Types

type AppConfig

type AppConfig struct{}

AppConfig is used to group together config related functions

func (AppConfig) Config

func (a AppConfig) Config(id ServiceID) (*capnp.Message, error)

Config returns the config message for the specified ServiceID. The config is expected to exist at {configDir}/{ServiceID}, where the ServiceID is specified in HEX format, e.g.,

/run/secrets/0xe49214fa20b35ba8

If no config exists for the specified service, then nil is returned.

errors:

  • ConfigError

func (AppConfig) ConfigDir

func (a AppConfig) ConfigDir() string

ConfigDir returns the config dir path

func (AppConfig) ConfigDirExists

func (a AppConfig) ConfigDirExists() bool

ConfigDirExists returns true if the config dir exists

func (AppConfig) ConfigServiceIDs

func (a AppConfig) ConfigServiceIDs() ([]ServiceID, error)

ConfigServiceIDs returns the list of ServiceID(s) for which configs exist The ServiceID is used as the config id.

func (AppConfig) ServiceConfigExists

func (a AppConfig) ServiceConfigExists(id ServiceID) bool

ServiceConfigExists returns true if a config exists for the specified ServiceID

func (AppConfig) ServiceConfigID

func (a AppConfig) ServiceConfigID(id ServiceID) string

ServiceConfigID is used to convert the ServiceID into the config id. The config id will be the ServiceID in HEX format.

func (AppConfig) ServiceConfigPath

func (a AppConfig) ServiceConfigPath(id ServiceID) string

ServiceConfigPath returns the service config file path

func (AppConfig) SetConfigDir

func (a AppConfig) SetConfigDir(dir string)

SetConfigDir is only exposed for testing purposes. This enables tests to setup test configurations

type AppHealthChecks

type AppHealthChecks struct{}

func (AppHealthChecks) HealthCheckIDs

func (a AppHealthChecks) HealthCheckIDs() []HealthCheckID

HealthCheckIDs returns the HealthCheckID(s) for the healthchecks that are currently registered. nil is returned if there are no healthchecks currently registered.

errors

  • ErrServiceNotAlive

func (AppHealthChecks) HealthCheckResult

func (a AppHealthChecks) HealthCheckResult(id HealthCheckID) (HealthCheckResult, error)

LastResult returns the latest HealthCheckResult from the last time the HealthCheck was run.

errors

  • ErrHealthCheckNotRegistered

func (AppHealthChecks) HealthCheckResults

func (a AppHealthChecks) HealthCheckResults() map[HealthCheckID]HealthCheckResult

HealthCheckResults returns a snapshot of all current HealthCheckResult(s)

func (AppHealthChecks) HealthCheckSpec

func (a AppHealthChecks) HealthCheckSpec(id HealthCheckID) *HealthCheckSpec

HealthCheckSpec returns the HealthCheckSpec for the specified HealthCheckID

errors:

  • ErrHealthCheckNotRegistered
  • ErrServiceNotAlive

func (AppHealthChecks) PauseHealthCheck

func (a AppHealthChecks) PauseHealthCheck(id HealthCheckID) bool

PauseHealthCheck will kill the healthcheck goroutine. false is returned if no HealthCheck is registered for the specified HealthCheckID

func (AppHealthChecks) PausedHealthChecks

func (a AppHealthChecks) PausedHealthChecks() []HealthCheckID

PausedHealthChecks returns HealthCheckID(s) for registered healthchecks that are not currently scheduled to run, i.e., not alive.

func (AppHealthChecks) Register

func (a AppHealthChecks) Register(id HealthCheckID, healthCheckFunc HealthCheck) error

Registers the HealthCheck for the specified HealthCheckID. If a HealthCheck is already registered for the specified HealthCheckID, then it will be replaced. The bool result indicates if there was a pre-existing healthcheck that was replaced. If true is returned, then it indicates that a healthcheck was replaced, i.e., there was a pre-existing healthcheck registered.

Design notes:

  • each healthcheck is scheduled to run on its own scheduled based on its HealthCheckSpec.RunInterval. The scheduling is performed by a scheduling goroutine.
  • the healthcheck is run within the command server goroutine, which owns the healtchecks, i.e., the command server goroutine ensures that healthchecks are run serially and in a concurrency safe manner.

errors

  • ErrHealthCheckNil
  • ErrServiceNotAlive

func (AppHealthChecks) Registered

func (a AppHealthChecks) Registered(id HealthCheckID) bool

Registered returns true if a HealthCheck is registered for the specified HealthCheckID

errors:

  • ErrServiceNotAlive

func (AppHealthChecks) ResumeHealthCheck

func (a AppHealthChecks) ResumeHealthCheck(id HealthCheckID) error

ResumeHealthCheck will schedule the healthcheck to run, if it is currently pause.

errors

  • ErrHealthCheckNotRegistered
  • ErrServiceNotAlive
  • ErrAppNotAlive
  • HealthCheckKillTimeoutError

func (AppHealthChecks) Run

Run triggers the healthcheck to run on demand.

errors

  • ErrServiceNotAlive
  • ErrHealthCheckNotRegistered

type AppID

type AppID uint64

AppID unique application ID

func ID

func ID() AppID

ID returns the AppID which is specified via a command line argument

func (AppID) Hex

func (a AppID) Hex() string

func (AppID) UInt64

func (a AppID) UInt64() uint64

type AppMetricRegistry

type AppMetricRegistry struct{}

func (AppMetricRegistry) Counter

func (a AppMetricRegistry) Counter(serviceId ServiceID, metricID MetricID) *CounterMetric

Counter looks up the registered metric.

func (AppMetricRegistry) CounterMetricIds

func (a AppMetricRegistry) CounterMetricIds(serviceId ServiceID) []MetricID

CounterMetricIds returns the registered metric ids for the specified service id

func (AppMetricRegistry) CounterMetricsIdsPerService

func (a AppMetricRegistry) CounterMetricsIdsPerService() map[ServiceID][]MetricID

CounterMetricsIdsPerService returns all counter metric ids grouped by service

func (AppMetricRegistry) CounterVector

func (a AppMetricRegistry) CounterVector(serviceId ServiceID, metricID MetricID) *CounterVectorMetric

CounterVec looks up the registered metric.

func (AppMetricRegistry) CounterVectorMetricIds

func (a AppMetricRegistry) CounterVectorMetricIds(serviceId ServiceID) []MetricID

CounterVectorMetricIds returns the registered metric ids for the specified service id

func (AppMetricRegistry) CounterVectorMetricsIdsPerService

func (a AppMetricRegistry) CounterVectorMetricsIdsPerService() map[ServiceID][]MetricID

CounterMetricsIdsPerService returns all counter metric ids grouped by service

func (AppMetricRegistry) Gauge

func (a AppMetricRegistry) Gauge(serviceId ServiceID, metricID MetricID) *GaugeMetric

Gauge looks up the registered metric.

func (AppMetricRegistry) GaugeMetricIds

func (a AppMetricRegistry) GaugeMetricIds(serviceId ServiceID) []MetricID

GaugeMetricIds returns all gauge metric ids registered for the service

func (AppMetricRegistry) GaugeMetricsByService

func (a AppMetricRegistry) GaugeMetricsByService() map[ServiceID][]MetricID

GaugeMetricsByService returns all gauge metric ids grouped by service

func (AppMetricRegistry) GaugeVector

func (a AppMetricRegistry) GaugeVector(serviceId ServiceID, metricID MetricID) *GaugeVectorMetric

GaugeVector looks up the registered metric.

func (AppMetricRegistry) GaugeVectorMetricIds

func (a AppMetricRegistry) GaugeVectorMetricIds(serviceId ServiceID) []MetricID

GaugeVectorMetricIds returns all gauge vector metric ids registered for the service

func (AppMetricRegistry) GaugeVectorMetricsByService

func (a AppMetricRegistry) GaugeVectorMetricsByService() map[ServiceID][]MetricID

GaugeVectorMetricsByService returns all gauge vector metric ids grouped by service

func (AppMetricRegistry) Histogram

func (a AppMetricRegistry) Histogram(serviceId ServiceID, metricID MetricID) *HistogramMetric

Histogram looks up a registered HistogramMetric

func (AppMetricRegistry) HistogramMetricIds

func (a AppMetricRegistry) HistogramMetricIds(serviceId ServiceID) []MetricID

HistogramMetricIds returns all histogram metric ids for the specified service

func (AppMetricRegistry) HistogramMetricsByService

func (a AppMetricRegistry) HistogramMetricsByService() map[ServiceID][]MetricID

HistogramMetricsByService returns all gauge metric ids grouped by service

func (AppMetricRegistry) HistogramVector

func (a AppMetricRegistry) HistogramVector(serviceId ServiceID, metricID MetricID) *HistogramVectorMetric

HistogramVector looks up a registered HistogramVectorMetric

func (AppMetricRegistry) HistogramVectorMetricIds

func (a AppMetricRegistry) HistogramVectorMetricIds(serviceId ServiceID) []MetricID

HistogramVectorMetricIds returns all histogram vector metric ids for the specified service

func (AppMetricRegistry) HistogramVectorMetricsByService

func (a AppMetricRegistry) HistogramVectorMetricsByService() map[ServiceID][]MetricID

HistogramVectorMetricsByService returns all gauge vector metric ids grouped by service

type AppServices

type AppServices struct{}

func (AppServices) LogLevel

func (a AppServices) LogLevel(id ServiceID) zerolog.Level

LogLevel returns the service log level. The service log level will use the application log level unless it is overridden via the -service-log-level command line flag

func (AppServices) Register

func (a AppServices) Register(s *Service)

Register will register the service with the app.

errors:

  • ErrAppNotAlive
  • ErrServiceAlreadyRegistered

func (AppServices) Service

func (a AppServices) Service(id ServiceID) *Service

Service will lookup the service for the specified ServiceID

func (AppServices) ServiceIDs

func (a AppServices) ServiceIDs() []ServiceID

ServiceIDs returns the ServiceID(s) for the currently registered services

errors:

  • ErrAppNotAlive

func (AppServices) Services

func (a AppServices) Services() []*Service

Services returns all currently registered services

func (AppServices) Unregister

func (a AppServices) Unregister(id ServiceID)

Unregister will unregister the service for the specified ServiceID

errors:

  • ErrAppNotAlive
  • ErrServiceNotRegistered

type CommandServer

type CommandServer struct {
	*ServiceCommandChannel

	// OPTIONAL - used for logging purposes
	Name string

	// OPTIONAL - invoked before any commands are run
	Init func() error
	// OPTIONAL - invoked when the service has been killed
	Destroy func()
}

CommandServer will execute commands in a background goroutine serially. Think of the command server as a command event loop. The CommandServer can be supplied with optional Init and Destroy funcs.

func NewCommandServer

func NewCommandServer(service *Service, chanSize uint16, name string, init func() error, destroy func()) (*CommandServer, error)

NewCommandServer creates a new CommandServer and returns it

type CounterMetric

type CounterMetric struct {
	*CounterMetricSpec
	prometheus.Counter
}

CounterMetric associates Counter with its spec. This is cached after the metric is registered.

type CounterMetricSpec

type CounterMetricSpec MetricSpec

CounterMetricSpec type alias for a Counter MetricSpec

func NewCounterMetricSpec

func NewCounterMetricSpec(spec config.CounterMetricSpec) (CounterMetricSpec, error)

NewCounterMetricSpec is a CounterMetricSpec factory method

errors - ConfigError

func (*CounterMetricSpec) CounterOpts

func (a *CounterMetricSpec) CounterOpts() prometheus.CounterOpts

CounterOpts maps the spec to a prometheus CounterOpts

type CounterVectorMetric

type CounterVectorMetric struct {
	*CounterVectorMetricSpec
	*prometheus.CounterVec
}

CounterVectorMetric associates the CounterVec with its spec. This is cached after the metric is registered.

type CounterVectorMetricSpec

type CounterVectorMetricSpec MetricVectorSpec

CounterVectorMetricSpec is a type alias for a Counter MetricVectorSpec

func NewCounterVectorMetricSpec

func NewCounterVectorMetricSpec(spec config.CounterVectorMetricSpec) (*CounterVectorMetricSpec, error)

NewCounterVectorMetricSpec is the CounterVectorMetricSpec factory method

func (*CounterVectorMetricSpec) CounterOpts

type DomainID

type DomainID uint64

DomainID is unique ID assigned to a domain

func Domain

func Domain() DomainID

func (DomainID) Hex

func (a DomainID) Hex() string

func (DomainID) UInt64

func (a DomainID) UInt64() uint64

type ErrSpec

type ErrSpec struct {
	ErrorID
	ErrorType
	ErrorSeverity
}

type Error

type Error struct {
	Cause error
	// user friendly message
	Message string
	// Used to identify the exact error type
	ErrorID
	ErrorType
	ErrorSeverity
	Stack string
	// tags can be used to categorize errors, e.g., UI, DB, ES, SECURITY
	Tags []string
	// should support JSON marshalling - it will be stored as a JSON clob
	Context interface{}

	// used for error tracking, i.e., used to lookup this specific error
	uid.UIDHash
	time.Time
	DomainID
	AppID
	InstanceID
	ReleaseID
	// PID and Hostname are part of the error because errors need to be centrally reported
	PID      int
	Hostname string

	ServiceID
}

Error is used to model all application errors purposely.

Many developers make the mistake of error propagation as secondary to the flow of their system. Careful consideration is given to how data flows through the system, but errors are something that are tolerated and ferried up the stack without much thought, and ultimately dumped in front of the user. With just a little forethought, and minimal overhead, you can make your error handling an asset to your system.

Errors indicate that your system has entered a state in which it cannot fulfill an operation that a user explicitly or implicitly requested. because of this, it needs to relay a few pieces of critical information:

  • What happened
  • When and where it happened

Even though the Error fields are directly exposed, Error should be treated as immutable - i.e., once created it should not be changed.

TODO: create capnp message

func AppNotAliveError

func AppNotAliveError() *Error

func ConfigError

func ConfigError(serviceID ServiceID, err error, message string) *Error

func HealthCheckAlreadyRegisteredError

func HealthCheckAlreadyRegisteredError(healthCheckID HealthCheckID) *Error

func HealthCheckKillTimeoutError

func HealthCheckKillTimeoutError(healthCheckID HealthCheckID) *Error

func HealthCheckNotAliveError

func HealthCheckNotAliveError(healthCheckID HealthCheckID) *Error

func HealthCheckNotRegisteredError

func HealthCheckNotRegisteredError(healthCheckID HealthCheckID) *Error

func HealthCheckTimeoutError

func HealthCheckTimeoutError(healthCheckID HealthCheckID) *Error

func IllegalArgumentError

func IllegalArgumentError(message string) *Error

func InvalidLogLevelError

func InvalidLogLevelError(message string) *Error

func NewBug

func NewBug(cause error, message string, serviceID ServiceID, ctx interface{}, tags ...string) *Error

func NewError

func NewError(cause error, message string, errSpec ErrSpec, serviceID ServiceID, ctx interface{}, tags ...string) *Error

func ServiceAlreadyRegisteredError

func ServiceAlreadyRegisteredError(serviceID ServiceID) *Error

func ServiceInitError

func ServiceInitError(serviceID ServiceID, err error) *Error

func ServiceNotAliveError

func ServiceNotAliveError(serviceID ServiceID) *Error

func ServiceNotAvailableError

func ServiceNotAvailableError(serviceID ServiceID) *Error

func ServiceNotRegisteredError

func ServiceNotRegisteredError(serviceID ServiceID) *Error

func ServiceShutdownError

func ServiceShutdownError(serviceID ServiceID, err error) *Error

func (*Error) ErrSpec

func (a *Error) ErrSpec() ErrSpec

func (*Error) Error

func (a *Error) Error() string

func (*Error) HasTag

func (a *Error) HasTag(tag string) bool

func (*Error) Log

func (a *Error) Log(logger zerolog.Logger)

func (*Error) WithTag

func (a *Error) WithTag(tag string) *Error

WithTag returns a new Error instance with the specified tag added. If this Error already has the tag, then the same Error is returned.

type ErrorID

type ErrorID uint64

ErrorID unique error id

func (ErrorID) Hex

func (a ErrorID) Hex() string

func (ErrorID) UInt64

func (a ErrorID) UInt64() uint64

type ErrorSeverity

type ErrorSeverity uint8

ErrorSeverity is used to classify error severity levels

func (ErrorSeverity) UInt8

func (a ErrorSeverity) UInt8() uint8

type ErrorType

type ErrorType uint8

ErrorType is used to classify error types

func (ErrorType) UInt8

func (a ErrorType) UInt8() uint8

type GaugeMetric

type GaugeMetric struct {
	*GaugeMetricSpec
	prometheus.Gauge
}

GaugeMetric associates the Gauge with its spec. It is cached after it is registered with prometheus.

type GaugeMetricSpec

type GaugeMetricSpec MetricSpec

GaugeMetricSpec is a type alias for a Gauge MetricSpec

func NewGaugeMetricSpec

func NewGaugeMetricSpec(spec config.GaugeMetricSpec) (GaugeMetricSpec, error)

func (*GaugeMetricSpec) GaugeOpts

func (a *GaugeMetricSpec) GaugeOpts() prometheus.GaugeOpts

GaugeOpts maps the spec to a prometheus GaugeOpts

type GaugeVectorMetric

type GaugeVectorMetric struct {
	*GaugeVectorMetricSpec
	*prometheus.GaugeVec
}

GaugeVectorMetric associates the Gauge with its spec. It is cached after it is registered with prometheus.

type GaugeVectorMetricSpec

type GaugeVectorMetricSpec MetricVectorSpec

GaugeVectorMetricSpec is a type alaias for the Gauge MetricVectorSpec

func NewGaugeVectorMetricSpec

func NewGaugeVectorMetricSpec(spec config.GaugeVectorMetricSpec) (*GaugeVectorMetricSpec, error)

NewGaugeVectorMetricSpec is the GaugeVectorMetricSpec factory method

errors: - ConfigError

func (*GaugeVectorMetricSpec) GaugeOpts

GaugeOpts maps the spec to a prometheus GaugeOpts

type HealthCheck

type HealthCheck func(result chan<- error, cancel <-chan struct{})

HealthCheck is used to run the health check. params:

  • result : the healthcheck will close the channel to signal success. If the healthcheck fails, then an error is sent on the channel.
  • cancel : when the cancel channel is closed, then it signals to the healthcheck that it has timed out.

type HealthCheckID

type HealthCheckID uint64

HealthCheckID unique healthcheck id

func (HealthCheckID) Hex

func (a HealthCheckID) Hex() string

type HealthCheckResult

type HealthCheckResult struct {
	// why the health check failed
	Err error

	// when the health check started running
	time.Time

	// how long it took to run the health check
	time.Duration

	// how many times the health check has failed consecutively
	ErrCount uint
}

HealthCheckResult is the result of running the health check

type HealthCheckSpec

type HealthCheckSpec struct {
	HealthCheckID
	RunInterval time.Duration
	Timeout     time.Duration
}

HealthCheckSpec is used to configure the healthchecks. Configuration that is loaded will override any runtime configuration. Consider runtime settings specified in the code as the default settings.

All healthchecks are recorded under a GaugeVector (HEALTHCHECK_METRIC_ID). The healthcheck id is used as the healthcheck label value.

The health gauge value indicates the number of consecutive failures. Thus, a gauge value of zero means the last time the health check ran, it succeeded. A gauge value of 3 means the healthcheck has failed the last 3 times it ran. A gauge value of -1 means the healthcheck has not yet been run.

The health check is run via the specified interval and the latest health check result is kept. When metrics are collected, the latest health result will be used to report the metric. It is the application's responsibility to register HealthCheck functions.

The health check run duration is also recorded as a gauge metric (HEALTHCHECK_RUN_DURATION_METRIC_ID). This can help identify health checks that are taking too long to execute. The run duration may also be used to configure alerts. For example, health checks that are passing but taking longer to run may be an early warning sign.

type HistogramMetric

type HistogramMetric struct {
	*HistogramMetricSpec
	prometheus.Histogram
}

HistogramMetric associates a Histogram with its spetric spec

type HistogramMetricSpec

type HistogramMetricSpec struct {
	MetricSpec
	Buckets []float64 // required
}

HistogramMetricSpec is a MetricSpec for a Histogram.

func NewHistogramMetricSpec

func NewHistogramMetricSpec(spec config.HistogramMetricSpec) (HistogramMetricSpec, error)

NewHistogramMetricSpec is the HistogramMetricSpec factory method

func (*HistogramMetricSpec) HistogramOpts

func (a *HistogramMetricSpec) HistogramOpts() prometheus.HistogramOpts

HistogramOpts maps the spec to a prometheus HistogramOpts

type HistogramVectorMetric

type HistogramVectorMetric struct {
	*HistogramVectorMetricSpec
	*prometheus.HistogramVec
}

HistogramVectorMetric associates a HistogramVec with its spetric spec

type HistogramVectorMetricSpec

type HistogramVectorMetricSpec struct {
	*MetricVectorSpec
	Buckets []float64
}

HistogramVectorMetricSpec is a MetricVectorSpec for a histogram vector

func NewHistogramVectorMetricSpec

func NewHistogramVectorMetricSpec(spec config.HistogramVectorMetricSpec) (*HistogramVectorMetricSpec, error)

NewHistogramVectorMetricSpec is the HistogramVectorMetricSpec factory method

func (*HistogramVectorMetricSpec) HistogramOpts

HistogramOpts maps the spec to a prometheus HistogramOpts

type InstanceID

type InstanceID uint64

InstanceID is the unique id for an app instance. There may be multiple instances, i.e., processes, of an app running. The instance id is used to differentiate the different app instances. For examples, logs and metrics will contain the instance id.

func Instance

func Instance() InstanceID

InstanceID returns a new unique instance id each time the app is started, i.e., when the process is started. The instance id remains for the lifetime of the process

func (InstanceID) Hex

func (a InstanceID) Hex() string

func (InstanceID) UInt64

func (a InstanceID) UInt64() uint64

type LogEventID

type LogEventID uint64

LogEventID

func (LogEventID) Hex

func (a LogEventID) Hex() string

func (LogEventID) Log

func (a LogEventID) Log(event *zerolog.Event) *zerolog.Event

Log sets the log event id for a new log event

type MetricID

type MetricID uint64

MetricID unique error id

func (MetricID) Hex

func (a MetricID) Hex() string

func (MetricID) PrometheusName

func (a MetricID) PrometheusName(serviceId ServiceID) string

Name returns the metric formatted name for Prometheus. The name must match the regex : [a-zA-Z_:][a-zA-Z0-9_:]*

func (MetricID) UInt64

func (a MetricID) UInt64() uint64

type MetricSpec

type MetricSpec struct {
	ServiceID
	MetricID
	Help string
}

MetricSpec specifies a service metric. Metrics are scoped to services.

Metric naming convention : op_{ServiceID.Hex()}_{MetricID.Hex()}

op_e49214fa20b35ba8_db722ec1bb1b5766

where op stands for OysterPack

Think of ServiceID and MetricID together as the unique key for a Service metric.

Each metric will have the following constant labels

  • domain : DomainID.Hex()
  • app : AppID.Hex
  • svc : ServiceID.Hex()

type MetricVectorSpec

type MetricVectorSpec struct {
	MetricSpec
	DynamicLabels []string
}

MetricVectorSpec specifies a service metric vector. The difference between a simple metric and a metric vector is that a metric vector can have dimensions, which are defined by dynamic labels. The labels are called dynamic because the the label value is not constant.

When a metric is recorded for a metric vector, all label values must be specified.

type ReleaseID

type ReleaseID uint64

ReleaseID is a unique ID assigned to an application release

func Release

func Release() ReleaseID

Release returns the application ReleaseID

func (ReleaseID) Hex

func (a ReleaseID) Hex() string

func (ReleaseID) UInt64

func (a ReleaseID) UInt64() uint64

type Service

type Service struct {
	tomb.Tomb
	// contains filtered or unexported fields
}

Service represents an application service. The service lifecycle is controlled by its Tomb.

func NewService

func NewService(id ServiceID) *Service

NewService is the service factory method. ServiceID must not be zero, i.e., a zero ServiceID will trigger a panic.

func (*Service) ID

func (a *Service) ID() ServiceID

ServiceID is the unique service id

func (*Service) LogLevel

func (a *Service) LogLevel() zerolog.Level

LogLevel is the service log level

func (*Service) Logger

func (a *Service) Logger() zerolog.Logger

Logger is the service logger

type ServiceCommandChannel

type ServiceCommandChannel struct {
	*Service
	// contains filtered or unexported fields
}

ServiceCommandChannel pairs a command channel to a service. It is the embedding service's responsibility to subscribe to service command channel and execute the command functions.

Service Channel Server Design Pattern

  • The server's main goroutine will listen on the command channel, and when a command function is received it will execute the function.

  • The service state is accessed within the service's main goroutine, i.e., the code executed by the command can assume that it will be run in a threadsafe manner.

  • Data is passed into the service via the function closure.

  • Data is passed out over channels that are enclosed by the closure function.

  • The service's main goroutine acts like an event loop which executes code that is received on the service commmand channel

  • NOTE: the service may embed more than 1 service command channel.

  • example service main goroutine :

    a.Go(func() error { for { // command event loop select { case <- a.Dying(): // listen for kill signal a.stop() // stop the service gracefully return nil // server exit case f := <- a.CommandChan(): // listen for commands f() // execute the command } } }

CommandServer is reference implementation and is designed to be embedded into services.

func NewServiceCommandChannel

func NewServiceCommandChannel(service *Service, chanSize uint16) (*ServiceCommandChannel, error)

NewServiceCommandChannel creates a new ServiceCommandChannel with the specified channel buffer size.

func (*ServiceCommandChannel) CommandChan

func (a *ServiceCommandChannel) CommandChan() <-chan func()

CommandChan returns the chan to used to receive commands to execute.

func (*ServiceCommandChannel) Submit

func (a *ServiceCommandChannel) Submit(f func()) error

Submit will put the command function on the service channel. Submit will block until the command function can be put on the channel.

errors:

  • ErrServiceNotAlive

type ServiceErrSpec

type ServiceErrSpec struct {
	ServiceID
	ErrSpec
}

type ServiceID

type ServiceID uint64

ServiceID unique service ID

func (ServiceID) Hex

func (a ServiceID) Hex() string

func (ServiceID) UInt64

func (a ServiceID) UInt64() uint64

Directories

Path Synopsis
net

Jump to

Keyboard shortcuts

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