1
0
Fork 0
mirror of https://github.com/eosswedenorg/antelope-api-healthcheck synced 2026-06-17 04:50:02 +02:00
antelope-api-healthcheck/cmd/antelope-api-healtcheck/main.go

208 lines
4.8 KiB
Go

package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/eosswedenorg-go/pid"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/server"
"github.com/eosswedenorg/antelope-api-healthcheck/internal/utils"
log "github.com/inconshreveable/log15"
"github.com/pborman/getopt/v2"
)
// Command line flags
// ---------------------------------------------------------
var (
logFile string
pidFile string
)
// Global variables
// ---------------------------------------------------------
// Version string, should be updated by the go linker (by passing "-X main.VersionString=value" to the linker)
// see: https://pkg.go.dev/cmd/link
var VersionString string = "-"
// File descriptor to the current log file.
var logfd *os.File
var (
logfmt log.Format
logger log.Logger
// TCP Server
srv *server.Server
)
// argv_listen_addr
// Parse listen address from command line.
//
// ---------------------------------------------------------
func argv_listen_addr() string {
var addr string
argv := getopt.Args()
if len(argv) > 0 {
addr = argv[0]
} else {
addr = "127.0.0.1"
}
addr += ":"
if len(argv) > 1 {
addr += argv[1]
} else {
addr += "1337"
}
return addr
}
func setLogFile() {
// Open file
fd, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
logger.Error(err.Error())
}
// Try close if old descriptor is defined.
if logfd != nil {
if err = logfd.Close(); err != nil {
logger.Error(err.Error())
}
}
// Update variable and set log writer.
logfd = fd
logger.SetHandler(log.StreamHandler(logfd, logfmt))
}
// signalEventLoop()
// Initialize event channel for OS signals
// and runs an event loop.
//
// ---------------------------------------------------------
func signalEventLoop() {
// Setup a channel
sig_ch := make(chan os.Signal, 1)
// subscribe to SIGHUP signal.
signal.Notify(sig_ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
// Event loop
var run bool = true
for run {
// Block until we get a signal.
sig := <-sig_ch
l := logger.New("signal", sig)
switch sig {
case syscall.SIGINT, syscall.SIGTERM:
l.Info("Program was asked to terminate.")
run = false
// Tell the server to close.
err := srv.Close()
if err != nil {
l.Error("Failed to close server", "error", err)
}
// SIGHUP is sent when logfile is rotated.
case syscall.SIGHUP:
msg := "Logfile was rotated: "
if logfd != nil {
setLogFile()
msg += "Filedescriptor was updated"
} else {
msg += "No Filedescriptor to update (most likely uses standard out/err streams)"
}
l.Info(msg)
default:
l.Warn("Unknown signal")
}
}
}
// main
//
// ---------------------------------------------------------
func main() {
var version bool
var usage bool
var logFormatter *string
// Set default timeout to 2 sec
// as haproxy "inter" parameter to healthcheck is set to 2s per default.
req_timeout := time.Second * 2
logger = log.Root()
// Command line parsing
getopt.SetParameters("[ip] [port]")
getopt.FlagLong(&usage, "help", 'h', "Print this help text")
getopt.FlagLong(&version, "version", 'v', "Print version")
getopt.FlagLong(&logFile, "log", 'l', "Path to log file", "file")
getopt.FlagLong(&pidFile, "pid", 'p', "Path to pid file", "file")
getopt.FlagLong(&req_timeout, "timeout", 't', "Set the maximum time before a request times out, valid prefixes are 's','ms','us'", "duration")
logFormatter = getopt.EnumLong("log-format", 0, []string{"term", "logfmt", "json", "json-pretty"}, "", "Log format to use: term,logfmt,json,json-pretty")
getopt.Parse()
if usage {
getopt.Usage()
return
}
if version {
fmt.Printf("Version: %s\n", VersionString)
return
}
logfmt = utils.ParseLogFormatter(*logFormatter)
// Open logfile.
if len(logFile) > 0 {
setLogFile()
} else {
logger.SetHandler(log.StreamHandler(os.Stdout, logfmt))
}
logger.Info("Process is starting", "pid", pid.Get())
if len(pidFile) > 0 {
logger.Info("Writing pidfile", "file", pidFile)
err := pid.Save(pidFile)
if err != nil {
logger.Error("Failed to write pidfile", "msg", err)
}
}
if req_timeout.Seconds() < 2 {
// Dont alow anything below 2 seconds. that is abit aggressive.
logger.Warn("Request timeout is less than the minimum. Setting it to 2 seconds", "req_timeout", req_timeout)
req_timeout = time.Second * 2
} else if req_timeout.Minutes() > 1.0 {
// Anything more than 1 min is too long :)
logger.Warn("Request timeout is more than the maximum. Setting it to 1 minute", "req_timeout", req_timeout)
req_timeout = time.Minute
}
// Create server
srv = server.New(argv_listen_addr(), server.WithTick(time.Second*10), server.WithTimeout(req_timeout))
// Run signal event loop in its own goroutine
go signalEventLoop()
// Run server
if err := srv.Run(); err != nil {
logger.Error("Server error", "error", err)
os.Exit(1)
}
}