init

package
v0.0.0-...-1edb6db Latest Latest
Warning

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

Go to latest
Published: Mar 26, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Package init provides service initialization and close functions. These functions represent a set of standards around services.

When building a project using the genproject binary, an "init" package will be setup that refers to this one.

The Service() function does things like setup logging, tracing, audit logging and signal handling. It also sets the GOMAXPROCS based on the real CPUs available and will set the GOMEMLIMIT based on the container memory limit if running in a Linux container and will honor a pre-set GOMEMLIMIT if set. Defaults for other packages in the base/ packages are set like the default worker pool and background tasks.

It determines what should and shouldn't run based on the environment the service is running in. Users can register their own initialization functions to run at the end of the Service() function to centralize service initialization.

The Close() function does things like close various clients that were setup, flush logs and handle panics so that we ensure they are written to the log before existing (it does not stop a panic).

Serivce() and Close() should always be called in the main function of the service if using directly (if using the one generated by genproject, this is slightly different).

Example of a basic service setup:

package main

import (
	"github.com/gostdlib/base/init"
)

var serviceMeta = init.Meta{
	Service: "[your service name]",
	Build:   "[your image tag]",
}

var initArgs = InitArgs{Meta: serviceMeta}

func main() {
	init.Service(initArgs)
	defer init.Close(initArgs)

	// Insert the rest of your code
}

Sometimes you want other registrations to be done, but you want them to be done after other init() functions and after things like logging and tracing are setup. This is where the InitFunc type comes in. You can register an init to happen after stadard init.Service() functions are called.

This is normally done in a package init(), but if you need to control exact ordering you can do it in main() before init.Service() is called.

Example RegisterInit:

package expvar

import (
	"net/http"
	"expvar"

	"github.com/gostdlib/base/init"
)

func init() {
	init.RegisterInit(Init)
}

// Init is the function that will be called after init.Service() has done all its setups.
func Init(i init.InitArgs) error {
	var mux *http.ServeMux

	// Extract a mux from the InitArgs. If not provided, return an error.
	v := i.Value("httpMuxer")
	if v == nil {
		return fmt.Errorf("httpMuxer key not found in InitArgs")
	}
	mux.Handle("/debug/vars", expvar.Handler())
}

In some cases, you may want to close resources that were opened in the Service() function. This is where RegisterClose() can be used. Below is an example, though I probably wouldn't use this for this purpose, however it shows a case where you might want to close something.

Example RegisterClose:

	package storage

	import (
		...
		"github.com/gostdlib/base/init"
		...
	)

	var db *sql.DB

	// We use init here to register our Init() function that will happen after microsoft.Init() has
	// done all its setups.
	func init() {
		init.RegisterInit(Init)
		init.RegisterClose(Close)
	}

	// Init is the function that will be called after init.Service() has done all its setups.
	func Init(init.InitArgs) error {
		// Extract a mux from the InitArgs. If not provided, return an error.
		v := i.Value("storageDB")
		if v == nil {
			return fmt.Errorf("storageDB key not found in InitArgs")
		}
		ptr := v.(*sql.DB)

		var err error
		db, err = sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/jazzrecords")
		if err != nil {
  			return err
		}
		ptr = *db

		return nil
	}

	func Close(i IntArgs) {
		v := i.Value("storageDB").(*sql.DB)
		if err := db.Close; err != nil {
			log.Default().Error(fmt.Sprintf("could not close db: %v", err))
		}
	}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Called

func Called() bool

Called returns true if Service() has been called.

func Close

func Close(args InitArgs)

Close is used as a defer function in the main function of a service after Init. This will recover from a panics in order to log it via the base/log.Default() logger to avoid any panics from escaping logs. However, it will still exit after logging the error. This also closes the audit client in audit.Default(). All other closers that are registered via RegisterClose() will be called in parallel. This will return in 30 seconds no matter if all closers are done or not.

func RegisterClose

func RegisterClose(f CloseFunc)

RegisterClose registers a function to be called during Close(). They are called in parallel. All closers must be completed within 30 seconds. This is usually called along with RegisterInit() within a package init() function and side effect imported.

func RegisterInit

func RegisterInit(f InitFunc)

Register registers a function to be called during Service(). These functions are called in the order they are registered. If one fails, then Service() will panic. These functions are called after all other setup has been done by Service(). Normal use is within a package init() function. Often side effect imported.

func Service

func Service(args InitArgs, options ...Option)

Service is the service initialization function for initing services. This will set the logger with the service name and build tag if provided.

Init CAN panic if something required for a production service or a bad option is provided. To panic in production, the cause of the panic (outside a bad option passed to Service() which always panics) should be an absolute no-go for the service to run, such as a critical service requirement.

This will do the following (not inclusive): - Set google/uuid to use a random pool - Setup the logger - Setup the audit client - Setup tracing - Integrates various clients and error packages with each other - Run user provided initializers

Types

type CloseFunc

type CloseFunc func(args InitArgs)

CloseFunc is a function that is called during Close() in order to close various clients or other resources that were setup during Service(). These happen in parallel.

type InitArgs

type InitArgs struct {
	// Meta provides metadata about the service that will be used for telemetry.
	Meta Meta

	// SignalHandlers provides handlers for signals that are caught by Service().
	// This can only be used to deal with syscall.SIGQUIT, syscall.SIGINT or syscall.SIGTERM.
	// Registering any other signals will cause a panic.
	// All of these will have Close() called after the signal handler is called.
	// Once handling is done, panic is called.
	SignalHandlers map[os.Signal]func()
	// contains filtered or unexported fields
}

InitArgs are the arguments that are passed to Service(). These are filtered down to customer initialization functions and closers. Custom initializers and closers should treat this as readonly.

func WithValue

func WithValue(i InitArgs, key, value any) InitArgs

WithValue adds an opaque key value pair to the InitArgs. This is used to pass values to custom initializers and closers. The key must be comparable or this panics. Returns a new InitArgs with the key value pair added. This works similar to context.WithValue(). You should use typed keys to avoid collisions.

func (InitArgs) Value

func (i InitArgs) Value(key any) any

Value returns the value for a key that was set with WithOpaque(). If the key is not found, then nil is returned. This is used to retrieve values for custom initializers and closers.

type InitFunc

type InitFunc func(args InitArgs) error

InitFunc is a function that is called during Service() in order to setup various needs for the service. These happen in the order they are registered, so if one has a dependency on another, you have to register them in the correct order. For those that do not have a dependency, these are usually done via a package init() function. If this function returns an error, then Service() will panic.

type Meta

type Meta struct {
	// Service is the name of the service. If provided, will be used in log output.
	Service string
	// Build is the build tag. Usually the image version or commit hash.
	// If provided, will be used in log output.
	Build string
}

Meta is metadata about the service.

type Option

type Option func(*initOpts) error

Option is an optional argument to Init.

func WithDisableTrace

func WithDisableTrace() Option

WithDisableTrace disables tracing for the service.

func WithExtraFields

func WithExtraFields(fieldPairs []any) Option

WithExtraFields sets extra fields to be added to the logger. These fields will always be logged with every log message. These are not logged in non-production environments.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the logger in the base/log package to use the provided logger. By default there is a JSON logger to stderr that records the source and uses an adjustable level from the base/telemetry/log package. If you require zap or zerolog, you can use the log/adapters package to convert them to the slog.Logger type. If you provide a logger that outside of those, you need to set your logger to use the LogLevel defined in the base/telemetry/log package.

func WithMeterProvider

func WithMeterProvider(m metric.MeterProvider) Option

WithMeterProvider sets the metric provider to use for the service. By default this will be created for you. You may use the ("go.opentelemetry.io/otel/metric/noop") noop.NewMeterProvider() to disable metrics.

func WithMetricsPort

func WithMetricsPort(p uint16) Option

WithMetricsPort sets the port to use for the metrics server. If not provided, then this defaults to port 2223.

func WithPool

func WithPool(p *worker.Pool, noDefault bool) Option

WithPool sets the worker pool to use for the service. If not provided, then this defaults to a worker.Pool with runtime.NumCPUs() workers (this number is based on the Uber gomaxprocs package). The pool grows and shrinks with use. See package worker documentation for more. If you provide a pool, this will set the default pool to this pool unless you set noDefault to true.

func WithTraceProvider

func WithTraceProvider(t *sdkTrace.TracerProvider) Option

WithTraceProvider sets the trace provider to use for the service. By default this will be created for you. If the environment variable "TracingEndpoint" is set, this will be used to send traces to the OTEL provider endpoint. Otherwise it uses the stdout exporter that is set to use stderr. You cannot use this and WithTraceSampleRate together or it will cause a panic.

func WithTraceSampleRate

func WithTraceSampleRate(r float64) Option

WithTraceSampleRate sets the sample rate for traces. This only applies if using the default trace provider when the environmental variable "TracingEndpoint" is set. If using WithTraceProvider, using this will cause a panic.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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