-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
169 lines (144 loc) · 4.3 KB
/
main.go
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package main
import (
"fmt"
"net/http"
"os"
"path"
"path/filepath"
"reporter/internal"
_ "testing"
"time"
log "github.com/sirupsen/logrus"
"github.com/akamensky/argparse"
"gopkg.in/natefinch/lumberjack.v2"
)
func init() {
// Print Maxon Reporter text header.
internal.PrintHeader()
}
// Separate from init() as we don't want this code (i.e. parsing CLI arguments)
// to be executed when initializing testing/benchmarks and when this logic was
// placed inside Go's native init(), the benchmarks wouldn't run when executed
// via "go test --bench ." for some reason...
func initialize() {
// Define CLI arguments.
parser := argparse.NewParser("reporter", "Maxon Reporter")
configJsonPath := parser.String(
"c", "config",
&argparse.Options{Required: false, Help: "Path to config.json"},
)
verboseMode := parser.Flag(
"v", "verbose",
&argparse.Options{Required: false, Help: "Enable verbose mode", Default: false},
)
justTry := parser.Flag(
"t", "try",
&argparse.Options{Required: false, Help: "Do a single run and exit", Default: false},
)
foregroundMode := parser.Flag(
"f", "foreground",
&argparse.Options{Required: false, Help: "Run in foreground without daemonization", Default: false},
)
logLevels := []string{"info", "debug", "warning", "error"}
logLevel := parser.Selector(
"l", "log-level", logLevels,
&argparse.Options{Required: false, Help: "Set log level", Default: "warning"},
)
// Parse the arguments.
err := parser.Parse(os.Args)
if err != nil {
log.Fatal(parser.Usage(err))
}
settings := &internal.Settings
// Determine absolute path to directory of the binary.
selfPath, err := os.Executable()
internal.FatalExitOnError(err)
selfDir, err := filepath.Abs(path.Dir(selfPath))
internal.FatalExitOnError(err)
settings.SelfDir = selfDir
settings.DaemonMode = true
settings.VerboseMode = *verboseMode
settings.ForegroundMode = *foregroundMode
settings.ConfigJsonPath = *configJsonPath
settings.JustTry = *justTry
settings.LogLevel = *logLevel
// Set log level.
switch settings.LogLevel {
case "info":
log.SetLevel(log.InfoLevel)
case "debug":
log.SetLevel(log.DebugLevel)
case "warning":
log.SetLevel(log.WarnLevel)
case "error":
log.SetLevel(log.ErrorLevel)
default:
log.SetLevel(log.WarnLevel)
}
// Set up log rotation
log.SetOutput(&lumberjack.Logger{
Filename: filepath.Join(settings.SelfDir, "reporter.log"),
MaxSize: 20, // MB
MaxBackups: 1,
MaxAge: 30, // days
Compress: false,
})
log.Info("Log rotation enabled.")
// Force some settings when In "just try" mode.
if settings.JustTry {
settings.DaemonMode = false
settings.VerboseMode = true
}
// Force some settings when In "just try" mode.
if settings.ForegroundMode {
settings.DaemonMode = false
}
// Force some of the settings for dev builds.
if internal.ReporterDevFlag == "1" {
// Because the built dev binary is in different directory than
// example config, we'll force the example config to be used (unless
// overridden with CLI argument). This makes manual testing during
// development easier.
settings.ConfigJsonPath = filepath.Join(selfDir, "../example/config.json")
}
}
func main() {
initialize()
settings := &internal.Settings
// If the config JSON file path was not specified via CLI argument, we'll
// try to find the config file ourselves.
if settings.ConfigJsonPath == "" {
settings.ConfigJsonPath = internal.FindConfig()
}
// Do this before daemonization, so that errors in config are visible soon.
loadedConfig := internal.LoadConfig(settings.ConfigJsonPath)
reporter := internal.Reporter{
ConfigJson: loadedConfig,
HttpClient: &http.Client{
Timeout: 1 * time.Minute, // Payload requests will timeout after this.
},
}
reporter.Single()
if settings.JustTry {
return
}
if settings.DaemonMode {
weAreTheDaemon, ctx := internal.Daemonize()
if weAreTheDaemon {
// Do our best to remove the PID file when terminating the child
// process.
defer func() {
if err := ctx.Release(); err != nil {
log.Errorf("Unable to release PID file: %s", err.Error())
}
}()
} else {
// We're the parent process - we'll tell the client the reporter
// is being daemonized and then exit.
fmt.Println("Daemonizing...")
os.Exit(0)
}
log.Warning("Running in daemon mode. PID:", os.Getpid())
}
reporter.Run()
}