1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
package main
import (
"context"
"flag"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/mimecast/dtail/internal/cli"
"github.com/mimecast/dtail/internal/config"
"github.com/mimecast/dtail/internal/io/dlog"
"github.com/mimecast/dtail/internal/server"
"github.com/mimecast/dtail/internal/source"
"github.com/mimecast/dtail/internal/user"
"github.com/mimecast/dtail/internal/version"
)
// The evil begins here.
func main() {
var args config.Args
var color bool
var displayVersion bool
var pprof string
var shutdownAfter int
user.NoRootCheck()
flag.BoolVar(&color, "color", false, "Enable ANSII terminal colors")
flag.BoolVar(&displayVersion, "version", false, "Display version")
flag.IntVar(&args.SSHPort, "port", config.DefaultSSHPort, "SSH server port")
flag.IntVar(&shutdownAfter, "shutdownAfter", 0, "Shutdown after so many seconds")
flag.StringVar(&args.ConfigFile, "cfg", "", "Config file path")
flag.StringVar(&args.LogDir, "logDir", "", "Log dir")
flag.StringVar(&args.LogLevel, "logLevel", config.DefaultLogLevel, "Log level")
flag.StringVar(&args.Logger, "logger", config.DefaultServerLogger, "Logger name")
flag.StringVar(&args.SSHBindAddress, "bindAddress", "", "The SSH bind address")
flag.StringVar(&pprof, "pprof", "", "Start PProf server this address")
flag.Parse()
args.NoColor = !color
config.Setup(source.Server, &args, flag.Args())
if displayVersion {
runtimeCfg := config.CurrentRuntime()
version.PrintAndExit(runtimeCfg.Client != nil && runtimeCfg.Client.TermColorsEnable)
}
version.Print(false)
// rootCtx is always cancelled on exit to ensure the internal goroutine
// spawned by context.WithCancel is released. When -shutdownAfter is set,
// ctx is replaced by a child WithTimeout context whose own cancel is also
// deferred, preventing the lostcancel leak flagged by go vet.
rootCtx, rootCancel := context.WithCancel(context.Background())
defer rootCancel()
ctx := rootCtx
cancel := context.CancelFunc(rootCancel)
if shutdownAfter > 0 {
// Override ctx with a timeout-bounded child; defer its cancel so the
// timeout goroutine is always cleaned up regardless of code path.
var timeoutCancel context.CancelFunc
ctx, timeoutCancel = context.WithTimeout(rootCtx, time.Duration(shutdownAfter)*time.Second)
defer timeoutCancel()
// Callers that invoke cancel() (e.g. the signal handler and post-serve
// cleanup) should trigger the timeout cancel so the server shuts down
// promptly even before the deadline fires.
cancel = timeoutCancel
}
sigCh := make(chan os.Signal, 10)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
go func() {
select {
case <-sigCh:
cancel()
case <-ctx.Done():
}
}()
var wg sync.WaitGroup
wg.Add(1)
dlog.Start(ctx, &wg, source.Server)
var pprofServer *cli.PProfServer
if pprof != "" {
// Enable mutex and block profiling so the /debug/pprof/mutex and
// /debug/pprof/block endpoints actually contain samples. These rates
// are gated on --pprof so they cost nothing when profiling is off.
cli.EnableProfilingRates()
// Assign to the outer pprofServer with '=' (declaring pprofErr
// separately) so it is NOT shadowed: the graceful Shutdown below relies
// on the outer var being non-nil to actually stop the pprof server.
var pprofErr error
pprofServer, pprofErr = cli.NewPProfServer(pprof)
if pprofErr != nil {
dlog.Client.Error("Unable to start PProf", pprofErr)
} else {
dlog.Client.Info("Starting PProf", pprofServer.Address())
pprofServer.Start(nil)
}
}
serv := server.New(config.CurrentRuntime())
status := serv.Start(ctx)
cancel()
if pprofServer != nil {
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
if err := pprofServer.Shutdown(shutdownCtx); err != nil {
dlog.Client.Error("Unable to stop PProf", err)
}
shutdownCancel()
}
wg.Wait()
os.Exit(status)
}
|