cliutil

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2021 License: MIT Imports: 17 Imported by: 5

README

cliutil

Build Status Go Reference Go Report Card

Helper functions that simplify writing CLI tools in Golang using the Cobra and Viper libraries.

Installation

With a correctly configured Go toolchain:

go get github.com/cpliakas/cliutil

Next, include cliutil in your application:

import "github.com/cpliakas/cliutil"

Usage

Flagger

Convenience functions that make it easier to add options to commands when using Cobra and Viper.


var myCfg *viper.Viper

func init() {

	// Assumes rootCmd and myCmd are defined. We are adding flags to myCmd.
	// See https://github.com/spf13/cobra#create-additional-commands
	rootCmd.AddCommand(myCmd)
    
	// Configure the AutomaticEnv capability to read configuration from
	// environment variables prefixed with "MYAPP_".
	// See https://github.com/spf13/viper#working-with-environment-variables
	myCfg = cliutil.InitConfig("MYAPP")

	// Add flags to myCmd. Use the myCfg.Get* methods to get the options passed
	// via command line. See https://github.com/spf13/viper for usage docs.
	flags := cliutil.NewFlagger(myCmd, myCfg)
	flags.String("log-level", "l", "info", "the minimum log level")
	flags.Int("max-num", "n", 100, "the maximum number of something")
}

Or ...


var myCfg *viper.Viper

func init() {
	var flags *cliutil.Flagger
	myCfg, flagger = cliutil.AddCommand(rootCmd, myCmd, "MYAPP")

	flags.String("log-level", "l", "info", "the minimum log level")
	flags.Int("max-num", "n", 100, "the maximum number of something")
}

Option Struct Tags

Set and get options via the cliutil struct tag, as shown with the PrintInput struct below:

package cmd

import (
	"fmt"

	"github.com/cpliakas/cliutil"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

type PrintInput struct {
	Text string `cliutil:"option=text short=t default='default value' usage='text printed to stdout'"`
}

var printCfg *viper.Viper

var printCmd = &cobra.Command{
	Use:   "print",
	Short: "Print text to STDOUT",
	Run: func(cmd *cobra.Command, args []string) {
		input := &PrintInput{}
		cliutil.GetOptions(input, printCfg)
		fmt.Println(input.Text)
	},
}

func init() {
	var flags *cliutil.Flagger
	printCfg, flags = cliutil.AddCommand(rootCmd, printCmd, "MYAPP")
	flags.SetOptions(&PrintInput{})
}

Assuming rootCmd exists and defines the myapp command:

$> ./myapp print --text hello
hello
Key/Value Parser

Parses strings like key1=value1 key2="some other value" into a map[string]string.


func parseValues() {
	s := `key1=value1 key2="some other value"`
	m := cliutil.ParseKeyValue(s)
	fmt.Println(m["key1"])  // prints "value1"
	fmt.Println(m["key2"])  // prints "some other value"
}

Event Listener

Listens for shutdown events, useful for long-running processes.

func main() {

	// Start the event listener. A message is sent to the shutdown channel when
	// a SIGINT or SIGTERM signal is received.
	listener := cliutil.NewEventListener().Run()

	// Do something long-running in a goroutine.
	go doStuff()

	// Wait for the shutdown signal.
	listener.Wait()
	log.Println("shutdown signal received, exiting")
}

func doStuff() {
	// do stuff here
}
Leveled Logger with Context

A simple, leveled logger with log tags derived from context. The defaults are inspired by the best practices suggested by Splunk.

func main() {
	ctx, logger, _ := cliutil.NewLoggerWithContext(context.Background(), cliutil.LogDebug)
	logger.Debug(ctx, "transaction id created")
	// 2020/04/29 14:24:50.516125 DEBUG message="transaction id created" transid=bqkoscmg10l5tdt068i0

	err := doStuff()
	logger.FatalIfError(ctx, "error doing stuff", err)
	// no-op, will only log the message if err != nil.

	ctx = cliutil.ContextWithLogTag(ctx, "stuff", "done doing it")
	logger.Notice(ctx, "shutdown")
	// 2020/04/29 14:24:50.516140 NOTICE message="shutdown" transid=bqkoscmg10l5tdt068i0 stuff="done doing it"
}

func doStuff() error {

	// do stuff here, returns any errors

	return nil
}

Documentation

Index

Constants

View Source
const (
	LogNone   = "none"
	LogFatal  = "fatal"
	LogError  = "error"
	LogNotice = "notice"
	LogInfo   = "info"
	LogDebug  = "debug"
)

Log* constants represent the log levels as strings for configuration.

View Source
const (
	LogLevelNone = iota
	LogLevelFatal
	LogLevelError
	LogLevelNotice
	LogLevelInfo
	LogLevelDebug
)

LogLevel* represents log levels as integers for comparrison.

View Source
const (
	CtxLogTags ctxKey = iota
)

Ctx* constants contain the keys for contexts with values.

View Source
const LogTagTransactionID = "transid"

LogTagTransactionID is the log tag that contains the transaction ID.

View Source
const TagName = "cliutil"

TagName is the name of the tag.

Variables

This section is empty.

Functions

func ContextWithLogTag

func ContextWithLogTag(ctx context.Context, key string, val interface{}) context.Context

ContextWithLogTag returns a new context with log tags appended.

func DefaultMessageWriter

func DefaultMessageWriter(ctx context.Context, logger *log.Logger, level string, message string, err error)

DefaultMessageWriter formats log messages according to Splunk's best practices. It is the default MessageWriter.

See https://dev.splunk.com/enterprise/docs/developapps/addsupport/logging/loggingbestpractices/

func FormatJSON

func FormatJSON(v interface{}) (string, error)

FormatJSON returns pretty-printed JSON as a string.

func FormatJSONWithFilter

func FormatJSONWithFilter(v interface{}, filter string) (out string, err error)

FormatJSONWithFilter applies a JMESPath filter and returns pretty-printed JSON as a string and panics on any marshal errors.

func GetOptions

func GetOptions(v interface{}, cfg *viper.Viper) (err error)

GetOptions gets values from cfg and sets them in item.

func HandleError

func HandleError(cmd *cobra.Command, err error, prefixes ...string)

HandleError either performs a no-op if err is nil or writes the error plus command usage to os.Stderr and exits with a non-zero status otherwise.

func HasSpace

func HasSpace(s string) bool

HasSpace returns true if s has a space.

func InitConfig

func InitConfig(envPrefix string) (c *viper.Viper)

InitConfig returns a *viper.Viper with an environment variable prefix set so that options can be passed from environment variables.

func IsLetters

func IsLetters(s string) bool

IsLetters returns true if s only contains letters.

func IsNumber

func IsNumber(s string) bool

IsNumber returns true if s only contains numbers.

func LogLevel

func LogLevel(level string) (id int)

LogLevel returns the log level's integer representation.

func LogLevelValid

func LogLevelValid(level string) (ok bool)

LogLevelValid return true if the log level is valid.

func ParseKeyValue

func ParseKeyValue(s string) map[string]string

ParseKeyValue parses key value pairs. See https://stackoverflow.com/a/44282136

func PrintJSON

func PrintJSON(v interface{}) (err error)

PrintJSON writes pretty-printed JSON to STDOUT.

func PrintJSONWithFilter

func PrintJSONWithFilter(v interface{}, filter string) error

PrintJSONWithFilter applies a JMESPath filter and writes pretty-printed JSON to STDOUT.

func SetBoolValue

func SetBoolValue(cfg *viper.Viper, name string, b *bool)

SetBoolValue sets s if the name flag is passed.

func SetFloat64Value

func SetFloat64Value(cfg *viper.Viper, name string, f *float64)

SetFloat64Value sets f if the name flag is passed.

func SetIntValue

func SetIntValue(cfg *viper.Viper, name string, i *int)

SetIntValue sets s if the name flag is passed.

func SetStringValue

func SetStringValue(cfg *viper.Viper, name string, s *string)

SetStringValue sets s if the name flag is passed.

func Use

func Use(command string, args ...string) (use string)

Use formats a value for cobra.Command.Use.

func WriteError

func WriteError(w io.Writer, err error, prefixes ...string)

WriteError formats and writes an error message to io.Writer w. All prefixes are prepended to the error message and separated by a colon plus space (: ). Two new line characters are printed after the error message, as it is assumed that command usage follows the error message.

Types

type EventListener

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

EventListener listens for SIGINT and SIGTERM signals and notifies the shutdown channel if it detects that either was sent.

func NewEventListener

func NewEventListener() *EventListener

NewEventListener returns an EventListener with the channels initialized.

func (*EventListener) Run

func (e *EventListener) Run() *EventListener

Run runs the event listener in a goroutine and sends e message to EventListener.shutdown if a SIGINT or SIGTERM signal is detected.

func (*EventListener) StopSignal

func (e *EventListener) StopSignal()

StopSignal stops relaying incoming signals to EventListener.signal.

func (*EventListener) Wait

func (e *EventListener) Wait()

Wait waits for EventListener.shutdown to receive a message.

type Flagger

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

Flagger is a utility that streamlines adding flags to commands.

func AddCommand

func AddCommand(parentCmd, cmd *cobra.Command, envPrefix string) (*viper.Viper, *Flagger)

AddCommand adds a comand to it's parent, initializes the configuration, and returns a flagger to easily add options.

func NewFlagger

func NewFlagger(cmd *cobra.Command, cfg *viper.Viper) *Flagger

NewFlagger returns a new Flagger with the *cobra.Command and *viper.Viper set as properties.

func (*Flagger) Bool

func (f *Flagger) Bool(name, shorthand string, value bool, usage string)

Bool adds a local flag that accepts a boolean.

func (*Flagger) Float64

func (f *Flagger) Float64(name, shorthand string, value float64, usage string)

Float64 adds a local flag that accepts a 64-bit float.

func (*Flagger) Int

func (f *Flagger) Int(name, shorthand string, value int, usage string)

Int adds a local flag that accepts an integer.

func (*Flagger) PersistentBool

func (f *Flagger) PersistentBool(name, shorthand string, value bool, usage string)

PersistentBool adds a persistent flag that accepts a boolean.

func (*Flagger) PersistentFloat64

func (f *Flagger) PersistentFloat64(name, shorthand string, value float64, usage string)

PersistentFloat64 adds a persistent flag that accepts a 64-bit float.

func (*Flagger) PersistentInt

func (f *Flagger) PersistentInt(name, shorthand string, value int, usage string)

PersistentInt adds a persistent flag that accepts an integer.

func (*Flagger) PersistentString

func (f *Flagger) PersistentString(name, shorthand, value, usage string)

PersistentString adds a persistent flag that accepts an string.

func (*Flagger) SetOptions

func (f *Flagger) SetOptions(v interface{}) error

SetOptions sets flags based on the cliutil tag.

func (*Flagger) String

func (f *Flagger) String(name, shorthand, value, usage string)

String adds a local flag that accepts an string.

type LeveledLogger

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

LeveledLogger is a simple leveled logger that writes logs to STDOUT.

func NewLogger

func NewLogger(level string) *LeveledLogger

NewLogger returns a LeveledLogger that writes logs to either os.Stdout or ioutil.Discard depending on the passed minimum log level.

func NewLoggerWithContext

func NewLoggerWithContext(ctx context.Context, level string) (context.Context, *LeveledLogger, xid.ID)

NewLoggerWithContext returns a leveled logger with a context that is initialized with a unique transaction ID.

func (LeveledLogger) Debug

func (l LeveledLogger) Debug(ctx context.Context, message string)

Debug writes a debug level log.

func (LeveledLogger) Error

func (l LeveledLogger) Error(ctx context.Context, message string, err error)

Error writes an error level log.

func (LeveledLogger) ErrorIfError

func (l LeveledLogger) ErrorIfError(ctx context.Context, message string, err error)

ErrorIfError writes an error level log if err is not nil.

func (LeveledLogger) Fatal

func (l LeveledLogger) Fatal(ctx context.Context, message string, err error)

Fatal writes an fatal level log and exits with a non-zero exit code.

func (LeveledLogger) FatalIfError

func (l LeveledLogger) FatalIfError(ctx context.Context, message string, err error)

FatalIfError writes a fatal level log and exits with a non-zero exit code if err != nil. This function is a no-op if err == nil.

func (LeveledLogger) Info

func (l LeveledLogger) Info(ctx context.Context, message string)

Info writes an info level log.

func (LeveledLogger) Notice

func (l LeveledLogger) Notice(ctx context.Context, message string)

Notice writes an notice level log.

func (*LeveledLogger) SetFlags

func (l *LeveledLogger) SetFlags(flag int)

SetFlags sets the output flags for all loggers.

func (*LeveledLogger) SetLevel

func (l *LeveledLogger) SetLevel(level string)

SetLevel sets the minimum log level. The log level defaults to "info" if the passed log level is not valid.

func (*LeveledLogger) SetMessageWriter

func (l *LeveledLogger) SetMessageWriter(fn MessageWriter)

SetMessageWriter sets the MessageWriter for all loggers.

func (*LeveledLogger) SetOutput

func (l *LeveledLogger) SetOutput(w io.Writer)

SetOutput sets the output for all loggers.

func (*LeveledLogger) SetPrefix

func (l *LeveledLogger) SetPrefix(prefix string)

SetPrefix sets the prefix for all loggers.

type MessageWriter

type MessageWriter func(ctx context.Context, logger *log.Logger, level string, message string, err error)

MessageWriter defines a function the writes the log messages.

Jump to

Keyboard shortcuts

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