Skip to content

Instantly share code, notes, and snippets.

@dmotylev
Created April 1, 2019 13:57
Show Gist options
  • Save dmotylev/17ee9e9c8ba31c970b2a74c6efc7aca1 to your computer and use it in GitHub Desktop.
Save dmotylev/17ee9e9c8ba31c970b2a74c6efc7aca1 to your computer and use it in GitHub Desktop.
main.go template for cli tool or server
package main
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/alecthomas/kingpin.v2"
)
var Version = "unknown"
type Configuration struct {
logLevel string
}
func main() {
finalizers := new(Finalizers)
cfg, err := configure(os.Args)
FatalIfError(err, "configuration failed", finalizers)
log, err := newLogger(cfg.logLevel)
FatalIfError(err, "logger configuration failed", finalizers)
log.Info("starting", zap.String("app", os.Args[0]), zap.String("version", Version))
_, cancel := context.WithCancel(context.Background())
finalizers.Add(cancel)
WaitShutdownRequest(func(sig os.Signal) {
log.Info("initiate shutdown", zap.Stringer("signal", sig))
// cancel global context
cancel()
// stop all exposed services
// stop all the rest
finalizers.Execute()
})
log.Info("done")
}
func newLogger(level string) (*zap.Logger, error) {
cfg := zap.NewProductionEncoderConfig()
cfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
cfg.TimeKey = ""
enc := zapcore.NewConsoleEncoder(cfg)
syncer := zapcore.Lock(os.Stdout)
var priority zapcore.Level
if err := priority.Set(level); err != nil {
return nil, err
}
return zap.New(zapcore.NewCore(enc, syncer, priority)), nil
}
func configure(args []string) (Configuration, error) {
cfg := Configuration{}
app := kingpin.New(filepath.Base(args[0]), "IPForensics: Internet Protocols security toolkit")
app.Version(Version)
// application level parameters
app.Flag("log-priority", "Priority of logging").Short('l').
Envar("LOG_PRIORITY").Default("info").EnumVar(&cfg.logLevel, "debug", "info", "error")
kingpin.MustParse(app.Parse(args[1:]))
return cfg, nil
}
func WaitShutdownRequest(f func(os.Signal)) {
signals := make(chan os.Signal)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
f(<-signals)
}
type Finalizers []func()
func (c *Finalizers) Add(f func()) { *c = append(*c, f) }
func (c *Finalizers) Execute() {
for _, f := range *c {
f()
}
}
func FatalIfError(err error, lastWords string, finalizers *Finalizers) {
if err == nil {
return
}
finalizers.Execute()
fmt.Printf("FATAL %s: %s", lastWords, err)
os.Exit(1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment