From 3f69495497c2587cb3dd53707ab21073df262d10 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Sun, 28 Apr 2019 17:42:43 +0000 Subject: [PATCH 1/2] =?UTF-8?q?atexit:=20=E6=B7=BB=E5=8A=A0=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E8=AE=B0=E5=BD=95=E5=9C=A8=E8=BF=9B=E7=A8=8B=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=97=B6=E6=89=A7=E8=A1=8C=E7=9A=84=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/atexit/atexit.go | 96 ++++++++++++++++++++++++++++++++++ pkg/util/atexit/atexit_test.go | 56 ++++++++++++++++++++ pkg/util/atexit/const.go | 5 ++ 3 files changed, 157 insertions(+) create mode 100644 pkg/util/atexit/atexit.go create mode 100644 pkg/util/atexit/atexit_test.go create mode 100644 pkg/util/atexit/const.go diff --git a/pkg/util/atexit/atexit.go b/pkg/util/atexit/atexit.go new file mode 100644 index 0000000000..38efa8c65d --- /dev/null +++ b/pkg/util/atexit/atexit.go @@ -0,0 +1,96 @@ +package atexit + +import ( + "os" + "runtime/debug" + "sort" + "sync" +) + +// ExitHandlerFunc is the type of handler func +type ExitHandlerFunc func(ExitHandler) + +// ExitHandler defines the spec of handler +// +// Reason and Func are mandatory and must not be empty or nil +// +// Handlers with smaller Prio will be executed earlier than those with bigger +// Prio at exit time. Handler func will receive a copy of the ExitHandler +// struct previously registered +type ExitHandler struct { + Prio int + Reason string + Func ExitHandlerFunc + Value interface{} +} + +var ( + handlers = map[int][]ExitHandler{} + handlersLock = &sync.Mutex{} + once = &sync.Once{} +) + +// Register registers ExitHandler +// +// Smaller prio number mean higher priority and exit handlers with higher +// priority will be executed first. For handlers with equal priorities, those +// registered first will be executed earlier at exit time +func Register(eh ExitHandler) { + if eh.Reason == "" { + panic("handler reason must not be empty") + } + if eh.Func == nil { + panic("handler func must not be nil") + } + + handlersLock.Lock() + defer handlersLock.Unlock() + + ehs, ok := handlers[eh.Prio] + if ok { + ehs = append(ehs, eh) + } else { + ehs = []ExitHandler{eh} + } + handlers[eh.Prio] = ehs +} + +// Handle calls registered handlers sequentially according to priority and +// registration order +// +// Panics caused by handler func will be caught, recorded, then next func will +// be run +func Handle() { + once.Do(func() { + handlersLock.Lock() + defer handlersLock.Unlock() + + prios := make([]int, 0, len(handlers)) + for prio := range handlers { + prios = append(prios, prio) + } + sort.Ints(prios) + for _, prio := range prios { + ehs := handlers[prio] + for _, eh := range ehs { + print("atexit: prio=", prio, ", reason=", eh.Reason, "\n") + func() { + defer func() { + val := recover() + if val != nil { + print("panic ", val, "\n") + debug.PrintStack() + } + }() + eh.Func(eh) + }() + } + } + }) +} + +// Exit calls handlers then does os.Exit(code) +func Exit(code int) { + defer os.Exit(code) + Handle() +} diff --git a/pkg/util/atexit/atexit_test.go b/pkg/util/atexit/atexit_test.go new file mode 100644 index 0000000000..b2a69c8948 --- /dev/null +++ b/pkg/util/atexit/atexit_test.go @@ -0,0 +1,56 @@ +package atexit + +import ( + "testing" +) + +func TestAtExit(t *testing.T) { + t.Run("empty reason", func(t *testing.T) { + func() { + defer func() { + val := recover() + if val == nil { + t.Errorf("should panic") + } + }() + Register(ExitHandler{}) + }() + }) + t.Run("empty func", func(t *testing.T) { + func() { + defer func() { + val := recover() + if val == nil { + t.Errorf("should panic") + } + }() + Register(ExitHandler{ + Reason: "have reason", + }) + }() + }) + t.Run("order & prio", func(t *testing.T) { + verdict := "" + handler := func(eh ExitHandler) { verdict += eh.Reason } + Register(ExitHandler{ + Prio: 2, + Reason: "2", + Func: handler, + }) + Register(ExitHandler{ + Prio: 0, + Reason: "0", + Func: handler, + }) + Register(ExitHandler{ + Prio: 0, + Reason: "1", + Func: handler, + }) + Handle() + Handle() + if verdict != "012" { + t.Errorf("expecting %q, got %q", "012", verdict) + } + }) +} diff --git a/pkg/util/atexit/const.go b/pkg/util/atexit/const.go new file mode 100644 index 0000000000..8bed426fc3 --- /dev/null +++ b/pkg/util/atexit/const.go @@ -0,0 +1,5 @@ +package atexit + +const ( + PRIO_LOG_CLOSE = 40000 +) From fc73a8d8113f6233b9e0f1426ce6cfe2077b3848 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Sun, 28 Apr 2019 01:53:39 +0000 Subject: [PATCH 2/2] =?UTF-8?q?cloudcommon:=20=E6=B7=BB=E5=8A=A0--log-file?= =?UTF-8?q?-prefix=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 指定日志文件名,rotate 10,每个100MB --- Gopkg.lock | 5 +++-- cmd/baremetal-agent/main.go | 3 +++ cmd/cloudir/main.go | 7 ++++++- cmd/cloutpost/main.go | 7 ++++++- cmd/glance/main.go | 3 +++ cmd/host-image/main.go | 7 ++++++- cmd/host/main.go | 7 ++++++- cmd/lbagent/main.go | 3 +++ cmd/logger/main.go | 3 +++ cmd/region-dns/main.go | 3 +++ cmd/region/main.go | 3 +++ cmd/scheduler/main.go | 11 +++++++---- cmd/torrent/main.go | 3 +++ cmd/webconsole/main.go | 3 +++ cmd/yunionconf/main.go | 3 +++ pkg/cloudcommon/options/options.go | 27 +++++++++++++++++++++++++++ vendor/yunion.io/x/log/log.go | 7 +++++++ 17 files changed, 95 insertions(+), 10 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index aa7a8e0f40..8fb5c31e8e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1713,14 +1713,14 @@ [[projects]] branch = "master" - digest = "1:b098c5b757b7622dfeed71f9cdcf0621a42051b88967286b0e1bcfb8a910fc86" + digest = "1:20590bdd812710ad3257e92c23c7d19d9595a48ed69b200ac1d23ac76eee848e" name = "yunion.io/x/log" packages = [ ".", "hooks", ] pruneopts = "UT" - revision = "71a36f55dcfcfa2c8b2477c339e2c7ebd78c731d" + revision = "3c4f24289a1b2fd39b94a9ccbd40931b3a20aab7" [[projects]] branch = "master" @@ -1895,6 +1895,7 @@ "k8s.io/kubernetes/pkg/scheduler/api/v1", "yunion.io/x/jsonutils", "yunion.io/x/log", + "yunion.io/x/log/hooks", "yunion.io/x/pkg/gotypes", "yunion.io/x/pkg/prettytable", "yunion.io/x/pkg/trace", diff --git a/cmd/baremetal-agent/main.go b/cmd/baremetal-agent/main.go index 2b182e32de..46d9fa37e6 100644 --- a/cmd/baremetal-agent/main.go +++ b/cmd/baremetal-agent/main.go @@ -16,8 +16,11 @@ package main import ( "yunion.io/x/onecloud/pkg/baremetal/service" + "yunion.io/x/onecloud/pkg/util/atexit" ) func main() { + defer atexit.Handle() + service.New().StartService() } diff --git a/cmd/cloudir/main.go b/cmd/cloudir/main.go index 2f312e79d5..46a24f86de 100644 --- a/cmd/cloudir/main.go +++ b/cmd/cloudir/main.go @@ -14,8 +14,13 @@ package main -import "yunion.io/x/onecloud/pkg/cloudir/service" +import ( + "yunion.io/x/onecloud/pkg/cloudir/service" + "yunion.io/x/onecloud/pkg/util/atexit" +) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/cmd/cloutpost/main.go b/cmd/cloutpost/main.go index 08a6041c11..d92950e7cf 100644 --- a/cmd/cloutpost/main.go +++ b/cmd/cloutpost/main.go @@ -14,8 +14,13 @@ package main -import "yunion.io/x/onecloud/pkg/cloutpost/service" +import ( + "yunion.io/x/onecloud/pkg/cloutpost/service" + "yunion.io/x/onecloud/pkg/util/atexit" +) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/cmd/glance/main.go b/cmd/glance/main.go index 8f106eb0f4..f4026d2afb 100644 --- a/cmd/glance/main.go +++ b/cmd/glance/main.go @@ -16,8 +16,11 @@ package main import ( "yunion.io/x/onecloud/pkg/image/service" + "yunion.io/x/onecloud/pkg/util/atexit" ) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/cmd/host-image/main.go b/cmd/host-image/main.go index bf95d5405a..d5dd53f47e 100644 --- a/cmd/host-image/main.go +++ b/cmd/host-image/main.go @@ -14,8 +14,13 @@ package main -import "yunion.io/x/onecloud/pkg/hostimage" +import ( + "yunion.io/x/onecloud/pkg/hostimage" + "yunion.io/x/onecloud/pkg/util/atexit" +) func main() { + defer atexit.Handle() + hostimage.StartService() } diff --git a/cmd/host/main.go b/cmd/host/main.go index 4b2f491416..2387902257 100644 --- a/cmd/host/main.go +++ b/cmd/host/main.go @@ -14,9 +14,14 @@ package main -import "yunion.io/x/onecloud/pkg/hostman" +import ( + "yunion.io/x/onecloud/pkg/hostman" + "yunion.io/x/onecloud/pkg/util/atexit" +) func main() { + defer atexit.Handle() + var srv = hostman.SHostService{} srv.StartService() } diff --git a/cmd/lbagent/main.go b/cmd/lbagent/main.go index dc49da93fa..8d9b6f743b 100644 --- a/cmd/lbagent/main.go +++ b/cmd/lbagent/main.go @@ -26,9 +26,12 @@ import ( app_common "yunion.io/x/onecloud/pkg/cloudcommon/app" common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" "yunion.io/x/onecloud/pkg/lbagent" + "yunion.io/x/onecloud/pkg/util/atexit" ) func main() { + defer atexit.Handle() + opts := &lbagent.Options{} commonOpts := &opts.CommonOptions { diff --git a/cmd/logger/main.go b/cmd/logger/main.go index 4fcc6d85ad..05ed33b41b 100644 --- a/cmd/logger/main.go +++ b/cmd/logger/main.go @@ -16,8 +16,11 @@ package main import ( "yunion.io/x/onecloud/pkg/logger/service" + "yunion.io/x/onecloud/pkg/util/atexit" ) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/cmd/region-dns/main.go b/cmd/region-dns/main.go index f553cc81ae..b7b70e1ba5 100644 --- a/cmd/region-dns/main.go +++ b/cmd/region-dns/main.go @@ -34,6 +34,7 @@ import ( _ "github.com/mholt/caddy/startupshutdown" _ "yunion.io/x/onecloud/pkg/dns" + "yunion.io/x/onecloud/pkg/util/atexit" ) var directives = []string{ @@ -58,5 +59,7 @@ func init() { } func main() { + defer atexit.Handle() + coremain.Run() } diff --git a/cmd/region/main.go b/cmd/region/main.go index 2753fb99ac..e1dbbaf1fc 100644 --- a/cmd/region/main.go +++ b/cmd/region/main.go @@ -16,8 +16,11 @@ package main import ( "yunion.io/x/onecloud/pkg/compute/service" + "yunion.io/x/onecloud/pkg/util/atexit" ) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/cmd/scheduler/main.go b/cmd/scheduler/main.go index 9fe0001792..cb8b2d1e9d 100644 --- a/cmd/scheduler/main.go +++ b/cmd/scheduler/main.go @@ -15,17 +15,20 @@ package main import ( - "os" - "yunion.io/x/log" "yunion.io/x/onecloud/pkg/scheduler/service" + "yunion.io/x/onecloud/pkg/util/atexit" ) func main() { + exitCode := 0 + defer func() { + atexit.Exit(exitCode) + }() + if err := service.StartService(); err != nil { log.Errorln(err) - os.Exit(-1) + exitCode = -1 } - os.Exit(0) } diff --git a/cmd/torrent/main.go b/cmd/torrent/main.go index 9b9c7481db..2dd768ee67 100644 --- a/cmd/torrent/main.go +++ b/cmd/torrent/main.go @@ -33,6 +33,7 @@ import ( "yunion.io/x/pkg/util/version" "yunion.io/x/structarg" + "yunion.io/x/onecloud/pkg/util/atexit" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/nodeid" "yunion.io/x/onecloud/pkg/util/torrentutils" @@ -62,6 +63,8 @@ func exitSignalHandlers(client *torrent.Client) { } func main() { + defer atexit.Handle() + options := Options{} parser, err := structarg.NewArgumentParser(&options, "torrent-srv", "bit-torrent server", "2018") diff --git a/cmd/webconsole/main.go b/cmd/webconsole/main.go index d158a5343a..e6a9b5ac30 100644 --- a/cmd/webconsole/main.go +++ b/cmd/webconsole/main.go @@ -15,9 +15,12 @@ package main import ( + "yunion.io/x/onecloud/pkg/util/atexit" "yunion.io/x/onecloud/pkg/webconsole/service" ) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/cmd/yunionconf/main.go b/cmd/yunionconf/main.go index bb92a3a056..e85e94419e 100644 --- a/cmd/yunionconf/main.go +++ b/cmd/yunionconf/main.go @@ -20,9 +20,12 @@ Yunion Conf Service */ import ( + "yunion.io/x/onecloud/pkg/util/atexit" "yunion.io/x/onecloud/pkg/yunionconf/service" ) func main() { + defer atexit.Handle() + service.StartService() } diff --git a/pkg/cloudcommon/options/options.go b/pkg/cloudcommon/options/options.go index db9d275910..5bfa24e457 100644 --- a/pkg/cloudcommon/options/options.go +++ b/pkg/cloudcommon/options/options.go @@ -16,16 +16,20 @@ package options import ( "fmt" + "io/ioutil" "os" "path" + "path/filepath" "yunion.io/x/log" + "yunion.io/x/log/hooks" "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/pkg/util/version" "yunion.io/x/pkg/utils" "yunion.io/x/structarg" "yunion.io/x/onecloud/pkg/cloudcommon/consts" + "yunion.io/x/onecloud/pkg/util/atexit" ) type CommonOptions struct { @@ -34,6 +38,7 @@ type CommonOptions struct { LogLevel string `help:"log level" default:"info" choices:"debug|info|warn|error"` LogVerboseLevel int `help:"log verbosity level" default:"0"` + LogFilePrefix string `help:"prefix of log files"` Region string `help:"Region name or ID" alias:"auth-region"` AuthURL string `help:"Keystone auth URL" alias:"auth-uri"` @@ -148,6 +153,28 @@ func ParseOptions(optStruct interface{}, args []string, configFileName string, s if err != nil { log.Fatalf("Set log level %q: %v", optionsRef.LogLevel, err) } + if optionsRef.LogFilePrefix != "" { + dir, name := filepath.Split(optionsRef.LogFilePrefix) + h := &hooks.LogFileRotateHook{ + RotateNum: 10, + RotateSize: 100 * 1024 * 1024, + LogFileHook: hooks.LogFileHook{ + FileDir: dir, + FileName: name, + }, + } + h.Init() + log.DisableColors() + log.Logger().AddHook(h) + log.Logger().Out = ioutil.Discard + atexit.Register(atexit.ExitHandler{ + Prio: atexit.PRIO_LOG_CLOSE, + Reason: "deinit log rotate hook", + Func: func(atexit.ExitHandler) { + h.DeInit() + }, + }) + } log.V(10).Debugf("Parsed options: %#v", optStruct) diff --git a/vendor/yunion.io/x/log/log.go b/vendor/yunion.io/x/log/log.go index 53533ad367..bc1cb1afa6 100644 --- a/vendor/yunion.io/x/log/log.go +++ b/vendor/yunion.io/x/log/log.go @@ -127,6 +127,13 @@ func Fatalln(args ...interface{}) { logrus.Fatalln(args...) } +func DisableColors() { + formatter, ok := logger.Formatter.(*TextFormatter) + if ok { + formatter.DisableColors = true + } +} + func AddHookFormatter(logger *logrus.Logger) { logger.Hooks.Add(new(hooks.CallerHook))