proc

package
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2022 License: Unlicense Imports: 20 Imported by: 0

README

proc

This is a unified library for process control and logging.

Originally this was 4 separate libraries, and the tangle of overlap between them became a source of bugs.

What is provided in here is a reliable way to start new processes and stop them, and pipe their log entries out to the controlling TTY, and receive and correctly process signals from outside a process most specifically for interrupt, in a fully uniform manner, that can be plugged into any application and make it usable as a worker for another application.

In future this library will add integrated Windows server process control interfacing, as part of the reason for the mess was precisely handling the differences between unix process signals and the windows process control libraries, which are less advanced.

Documentation

Index

Constants

View Source
const (
	Off   = "off"
	Fatal = "fatal"
	Error = "error"
	Warn  = "warn"
	Info  = "info"
	Check = "check"
	Debug = "debug"
	Trace = "trace"
)

Variables

View Source
var (
	App          = "   pod"
	AppColorizer = color.White.Sprint
	CurrentLevel = uberatomic.NewInt32(logLevels.Info)

	// LevelSpecs specifies the id, string name and color-printing function
	LevelSpecs = []LevelSpec{
		{logLevels.Off, "off  ", color.Bit24(0, 0, 0, false).Sprintf},
		{logLevels.Fatal, "fatal", color.Bit24(128, 0, 0, false).Sprintf},
		{logLevels.Error, "error", color.Bit24(255, 0, 0, false).Sprintf},
		{logLevels.Check, "check", color.Bit24(255, 255, 0, false).Sprintf},
		{logLevels.Warn, "warn ", color.Bit24(0, 255, 0, false).Sprintf},
		{logLevels.Info, "info ", color.Bit24(255, 255, 0, false).Sprintf},
		{logLevels.Debug, "debug", color.Bit24(0, 128, 255, false).Sprintf},
		{logLevels.Trace, "trace", color.Bit24(128, 0, 255, false).Sprintf},
	}
	Levels = []string{
		Off,
		Fatal,
		Error,
		Check,
		Warn,
		Info,
		Debug,
		Trace,
	}
	LogChanDisabled = uberatomic.NewBool(true)
	LogChan         chan Entry
)
View Source
var (
	Restart bool // = true

	// ShutdownRequestChan is a channel that can receive shutdown requests
	ShutdownRequestChan = qu.T()

	// HandlersDone is closed after all interrupt handlers run the first time
	// an interrupt is signaled.
	HandlersDone = make(qu.C)
)

Functions

func AddFilteredSubsystem

func AddFilteredSubsystem(hl string) struct{}

AddFilteredSubsystem adds a new subsystem Name to the highlighted list

func AddHandler

func AddHandler(handler func())

AddHandler adds a handler to call when a SIGINT (Ctrl+C) is received.

func AddHighlightedSubsystem

func AddHighlightedSubsystem(hl string) struct{}

AddHighlightedSubsystem adds a new subsystem Name to the highlighted list

func AddLogChan

func AddLogChan() (ch chan Entry)

AddLogChan adds a channel that log entries are sent to

func AddLoggerSubsystem

func AddLoggerSubsystem(pathBase string) (subsystem string)

AddLoggerSubsystem adds a subsystem to the list of known subsystems and returns the string so it is nice and neat in the package logg.go file

func Caller

func Caller(comment string, skip int) string

func DirectionString

func DirectionString(inbound bool) string

DirectionString is a helper function that returns a string that represents the direction of a connection (inbound or outbound).

func FileExists

func FileExists(filePath string) bool

func FilterNone

func FilterNone(string) bool

FilterNone is a filter that doesn't

func GetChk

func GetChk(level int32, subsystem string) func(e error) bool

func GetLoc

func GetLoc(skip int, level int32, subsystem string) (output string)

GetLoc calls runtime.Caller and formats as expected by source code editors for terminal hyperlinks

Regular expressions and the substitution texts to make these clickable in Tilix and other RE hyperlink configurable terminal emulators:

This matches the shortened paths generated in this command and printed at the very beginning of the line as this logger prints:

^((([\/a-zA-Z@0-9-_.]+/)+([a-zA-Z@0-9-_.]+)):([0-9]+))

goland --line $5 $GOPATH/src/github.com/p9c/matrjoska/$2

I have used a shell variable there but tilix doesn't expand them, so put your GOPATH in manually, and obviously change the repo subpath.

Change the path to use with another repository's logging output ( someone with more time on their hands could probably come up with something, but frankly the custom links feature of Tilix has the absolute worst UX I have encountered since the 90s... Maybe in the future this library will be expanded with a tool that more intelligently sets the path, ie from CWD or other cleverness.

This matches full paths anywhere on the commandline delimited by spaces:

([/](([\/a-zA-Z@0-9-_.]+/)+([a-zA-Z@0-9-_.]+)):([0-9]+))

goland --line $5 /$2

Adapt the invocation to open your preferred editor if it has the capability, the above is for Jetbrains Goland

func GetPrintc

func GetPrintc(level int32, subsystem string) func(closure func() string)

func GetPrintf

func GetPrintf(level int32, subsystem string) func(
	format string,
	a ...interface{},
)

func GetPrintln

func GetPrintln(level int32, subsystem string) func(a ...interface{})

func GetPrints

func GetPrints(level int32, subsystem string) func(a ...interface{})

func GoroutineDump

func GoroutineDump() string

GoroutineDump returns a string with the current goroutine dump in order to show what's going on in case of timeout.

func IsHighlighted

func IsHighlighted(subsystem string) (found bool)

IsHighlighted returns true if the subsystem is in the list to have attention getters added to them

func IsSubsystemFiltered

func IsSubsystemFiltered(subsystem string) (found bool)

IsSubsystemFiltered returns true if the subsystem should not pr logs

func JoinStrings

func JoinStrings(sep string, a ...interface{}) (o string)

JoinStrings constructs a string from an slice of interface same as Println but without the terminal newline

func Kill

func Kill(w *Worker)

Kill sends a kill signal via the pipe logger

func ListAllFilteredSubsystems

func ListAllFilteredSubsystems() (out []string)

func ListAllHighlightedSubsystems

func ListAllHighlightedSubsystems() (out []string)

func ListAllSubsystems

func ListAllSubsystems() []string

func Listener

func Listener()

Listener listens for interrupt signals, registers interrupt callbacks, and responds to custom shutdown signals as required

func LoadHighlightedSubsystems

func LoadHighlightedSubsystems() (o []string)

LoadHighlightedSubsystems returns a copy of the map of highlighted subsystems

func LoadSubsystemFilter

func LoadSubsystemFilter() (o []string)

LoadSubsystemFilter returns a copy of the map of filtered subsystems

func LogServe

func LogServe(quit qu.C, appName string)

LogServe starts up a handler to listen to logs from the child process worker

func PickNoun

func PickNoun(n int, singular, plural string) string

func Request

func Request()

Request programmatically requests a shutdown

func RequestRestart

func RequestRestart()

RequestRestart sets the reset flag and requests a restart

func Requested

func Requested() bool

Requested returns true if an interrupt has been requested

func SetLevel

func SetLevel(w *Worker, level string)

SetLevel sets the level of logging from the worker

func SetLogLevel

func SetLogLevel(l string)

SetLogLevel sets the log level via a string, which can be truncated down to one character, similar to nmcli's argument processor, as the first letter is unique. This could be used with a linter to make larger command sets.

func SetLogWriteToFile

func SetLogWriteToFile(path, appName string) (e error)

func SetLogWriter

func SetLogWriter(wr io.Writer)

SetLogWriter atomically changes the log io.Writer interface

func SimpleLog

func SimpleLog(name string) func(ent *Entry) (e error)

SimpleLog is a very simple log printer

func SortSubsystemsList

func SortSubsystemsList()

SortSubsystemsList sorts the list of subsystems, to keep the data read-only, call this function right at the top of the main, which runs after declarations and main/init. Really this is just here to alert the reader.

func Start

func Start(w *Worker)

func Stop

func Stop(w *Worker)

Stop running the worker

func StoreHighlightedSubsystems

func StoreHighlightedSubsystems(highlights []string) (found bool)

StoreHighlightedSubsystems sets the list of subsystems to highlight

func StoreSubsystemFilter

func StoreSubsystemFilter(filter []string)

StoreSubsystemFilter sets the list of subsystems to filter

Types

type Entry

type Entry struct {
	Time         time.Time
	Level        string
	Package      string
	CodeLocation string
	Text         string
}

Entry is a log entry to be printed as json to the log file

type HandlerWithSource

type HandlerWithSource struct {
	Source string
	Fn     func()
}

type LevelPrinter

type LevelPrinter struct {
	// Ln prints lists of interfaces with spaces in between
	Ln func(a ...interface{})
	// F prints like fmt.Println surrounded by log details
	F func(format string, a ...interface{})
	// S prints a spew.Sdump for an interface slice
	S func(a ...interface{})
	// C accepts a function so that the extra computation can be avoided if it is
	// not being viewed
	C func(closure func() string)
	// Chk is a shortcut for printing if there is an error, or returning true
	Chk func(e error) bool
}

LevelPrinter defines a set of terminal printing primitives that output with extra data, time, log logLevelList, and code location

func GetLogPrinterSet

func GetLogPrinterSet(subsystem string) (Fatal, Error, Warn, Info, Debug, Trace LevelPrinter)

GetLogPrinterSet returns a set of LevelPrinter with their subsystem preloaded

func GetOnePrinter

func GetOnePrinter(level int32, subsystem string) LevelPrinter

type LevelSpec

type LevelSpec struct {
	ID        int32
	Name      string
	Colorizer func(format string, a ...interface{}) string
}

type LogPrinters

type LogPrinters struct {
	F, E, W, I, D, T LevelPrinter
}

LogPrinters is a struct that bundles a set of log printers for a subsystem

func GetLogPrinters

func GetLogPrinters(subsystem string) (log LogPrinters)

GetLogPrinters returns a set of log printers wrapped in a struct

type RunUnit

type RunUnit struct {
	// contains filtered or unexported fields
}

RunUnit handles correctly starting and stopping child processes that have StdConn pipe logging enabled, allowing custom hooks to run on start and stop,

func NewUnit

func NewUnit(
	name string, run, stop func(), logger func(ent *Entry) (e error),
	pkgFilter func(pkg string) (out bool), quit qu.C, args ...string,
) (r *RunUnit)

NewUnit creates and starts a new rununit. run and stop functions are executed after starting and stopping. logger receives log entries and processes them (such as logging them).

func (*RunUnit) Running

func (r *RunUnit) Running() bool

Running returns whether the unit is running

func (*RunUnit) Shutdown

func (r *RunUnit) Shutdown()

Shutdown terminates the run unit

func (*RunUnit) ShuttingDown

func (r *RunUnit) ShuttingDown() bool

ShuttingDown returns true if the server is shuting down

func (*RunUnit) Start

func (r *RunUnit) Start()

Start signals the run unit to start

func (*RunUnit) Stop

func (r *RunUnit) Stop()

Stop signals the run unit to stop

type StdConn

type StdConn struct {
	io.ReadCloser
	io.WriteCloser
	Quit qu.C
}

func New

func New(in io.ReadCloser, out io.WriteCloser, quit qu.C) (s *StdConn)

func Serve

func Serve(quit qu.C, handler func([]byte) error) *StdConn

Serve runs a goroutine processing the FEC encoded packets, gathering them and decoding them to be delivered to a handler function

func (*StdConn) Close

func (s *StdConn) Close() (e error)

func (*StdConn) LocalAddr

func (s *StdConn) LocalAddr() (addr net.Addr)

func (*StdConn) Read

func (s *StdConn) Read(b []byte) (n int, e error)

func (*StdConn) RemoteAddr

func (s *StdConn) RemoteAddr() (addr net.Addr)

func (*StdConn) SetDeadline

func (s *StdConn) SetDeadline(t time.Time) (e error)

func (*StdConn) SetReadDeadline

func (s *StdConn) SetReadDeadline(t time.Time) (e error)

func (*StdConn) SetWriteDeadline

func (s *StdConn) SetWriteDeadline(t time.Time) (e error)

func (*StdConn) Write

func (s *StdConn) Write(b []byte) (n int, e error)

type Worker

type Worker struct {
	Cmd  *exec.Cmd
	Args []string
	// Stderr  io.WriteCloser
	// StdPipe io.ReadCloser
	StdConn *StdConn
}

func Consume

func Consume(
	quit qu.C,
	handler func([]byte) error,
	args ...string,
) *Worker

Consume listens for messages from a child process over a stdio pipe.

func LogConsume

func LogConsume(
	quit qu.C, handler func(ent *Entry) (e error),
	filter func(pkg string) (out bool), args ...string,
) *Worker

func Spawn

func Spawn(quit qu.C, args ...string) (w *Worker, e error)

Spawn starts up an arbitrary executable file with given arguments and attaches a connection to its stdin/stdout

func (*Worker) Continue

func (w *Worker) Continue() (e error)

Continue sends a signal to a worker process to resume work

func (*Worker) Interrupt

func (w *Worker) Interrupt() (e error)

Interrupt the child process. This invokes kill on windows because windows doesn't have an interrupt signal.

func (*Worker) Kill

func (w *Worker) Kill() (e error)

Kill forces the child process to shut down without cleanup

func (*Worker) Pause

func (w *Worker) Pause() (e error)

Pause sends a signal to the worker process to stop

func (*Worker) Stop

func (w *Worker) Stop() (e error)

Stop signals the worker to shut down cleanly.

Note that the worker must have handlers for os.Signal messages.

It is possible and neater to put a quit method in the IPC API and use the quit channel built into the StdConn

func (*Worker) Wait

func (w *Worker) Wait() (e error)

Wait for the process to finish running

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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