summaryrefslogtreecommitdiff
path: root/main.go
blob: e54d32099ab8f67fe1ea6dcc92bbb4ce2254e6b6 (plain)
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
package main

import (
	"dtail/clients"
	"dtail/color"
	"dtail/config"
	"dtail/logger"
	"dtail/omode"
	"dtail/server"
	"dtail/version"
	"flag"
	"fmt"
	"net/http"
	_ "net/http"
	_ "net/http/pprof"
	"os"
	"os/user"
	"runtime"
	"sync"
	"time"
)

// The evil begins here.
func main() {
	var cfgFile, modeStr string
	var checkHealth bool
	var clientServerEnable bool
	var connectionsPerCPU int
	var debugEnable bool
	var discovery string
	var displayVersion bool
	var files string
	var grep, regex string
	var maxInitConnections int
	var noColor bool
	var pprofEnable bool
	var queryStr string
	var serversStr string
	var shutdownAfter int
	var silent bool
	var sshPort int
	var trustAllHosts bool
	var userName string

	user, err := user.Current()
	if err != nil {
		panic(err)
	}

	if user.Uid == "0" {
		panic("Not allowed to run as UID 0")
	}

	if user.Gid == "0" {
		panic("Not allowed to run as GID 0")
	}

	defaultMode := omode.Default()
	serverEnable := defaultMode == omode.Server
	clientEnable := !serverEnable

	// Based on the mode we have different default timeouts
	var pingTimeoutS int
	switch defaultMode {
	case omode.CatClient:
		fallthrough
	case omode.GrepClient:
		pingTimeoutS = 60
	case omode.MapClient:
		pingTimeoutS = 900
	default:
		pingTimeoutS = 5
	}

	flag.BoolVar(&checkHealth, "checkHealth", false, "Only check for server health")
	flag.BoolVar(&clientServerEnable, "clientServer", false, "Enable client and server (dev purposes)")
	flag.BoolVar(&debugEnable, "debug", false, "Activate debug messages")
	flag.BoolVar(&displayVersion, "version", false, "Display version")
	flag.BoolVar(&noColor, "noColor", false, "Disable ANSII terminal colors")
	flag.BoolVar(&pprofEnable, "pprofEnable", false, "Enable pprof server")
	flag.BoolVar(&serverEnable, "server", serverEnable, "Start as a DTail server")
	flag.BoolVar(&silent, "silent", false, "Reduce output")
	flag.BoolVar(&trustAllHosts, "trustAllHosts", false, "Auto trust all unknown host keys")
	flag.IntVar(&connectionsPerCPU, "cpc", 10, "How many connections established per CPU core concurrently")
	flag.IntVar(&maxInitConnections, "mic", 20, "Max cpc")
	flag.IntVar(&shutdownAfter, "shutdownAfter", 0, "Automatically shutdown after so many seconds")
	flag.IntVar(&sshPort, "port", 2222, "SSH server port")
	flag.IntVar(&pingTimeoutS, "pingTimeout", 10, "The server ping timeout (0 means disable pings)")
	flag.StringVar(&cfgFile, "cfg", "", "Config file path")
	flag.StringVar(&discovery, "discovery", "", "Server discovery method")
	flag.StringVar(&files, "files", "", "File(s) to read")
	flag.StringVar(&grep, "grep", "", "Regular expression (deprecated)")
	flag.StringVar(&modeStr, "mode", defaultMode.String(), "Operating mode (tail, grep, cat, map, server)")
	flag.StringVar(&queryStr, "query", "", "Map reduce query")
	flag.StringVar(&regex, "regex", "", "Regular expression")
	flag.StringVar(&serversStr, "servers", "", "Remote servers to connect")
	flag.StringVar(&userName, "user", user.Username, "Your system user name")

	mode := omode.New(modeStr)

	flag.Parse()

	config.Init(cfgFile)
	color.Init(!noColor)

	if displayVersion {
		fmt.Println(version.PaintedString())
		os.Exit(0)
	}

	// Figure out how many SSH sessions can be established concurrently.
	if connectionsPerCPU*runtime.NumCPU() < maxInitConnections {
		maxInitConnections = connectionsPerCPU * runtime.NumCPU()
	}

	// Figure out in which mode I am? Server or client or both (the latter for dev purposes)?
	if serverEnable {
		clientEnable = false
	}
	if clientServerEnable {
		clientEnable = true
		serverEnable = true
	}

	// If non-standard port specified, overwrite config
	if sshPort != 2222 {
		config.Common.SSHPort = sshPort
	}

	// Figure out the log level.
	var logMode logger.LogMode
	switch {
	case debugEnable:
		logMode = logger.DebugMode
	case checkHealth:
		logMode = logger.NothingMode
	case config.Common.TraceEnable:
		logMode = logger.TraceMode
	case config.Common.DebugEnable:
		logMode = logger.DebugMode
	case silent:
		logMode = logger.SilentMode
	default:
		logMode = logger.NormalMode
	}

	// Figure out the log strategy.
	var logStrategy logger.LogStrategy
	switch config.Common.LogStrategy {
	case "daily":
		logStrategy = logger.DailyStrategy
	case "stdout":
		fallthrough
	default:
		logStrategy = logger.StdoutStrategy
	}

	logger.Init(serverEnable, logMode, logStrategy)

	// Wait group for shutting down logger.
	var wg sync.WaitGroup
	if serverEnable {
		wg.Add(1)
	}
	if clientEnable {
		wg.Add(1)
	}

	logger.Debug("Common config", config.Common)
	logger.Debug("Client config", config.Client)
	logger.Debug("Server config", config.Server)

	if grep != "" {
		logger.Warn("Flag 'grep' is deprecated and may be removed in the future, please use 'regex' instead")
		if regex == "" {
			regex = grep
		}
	}

	if checkHealth {
		healthClient, _ := clients.NewHealthClient(omode.HealthClient)
		os.Exit(healthClient.Start(&wg))
	}

	if shutdownAfter > 0 {
		go func() {
			defer os.Exit(1)

			logger.Info("Enabling auto shutdown timer", shutdownAfter)
			time.Sleep(time.Duration(shutdownAfter) * time.Second)
			logger.Info("Auto shutdown timer reached, shutting down now")
		}()
	}

	if pprofEnable || config.Common.PProfEnable {
		bindAddr := fmt.Sprintf("%s:%d", config.Common.PProfBindAddress, config.Common.PProfPort)
		logger.Info("Starting PProf server", bindAddr)
		go http.ListenAndServe(bindAddr, nil)
	}

	if serverEnable {
		logger.Info("Launching server", mode, version.String())
		sshServer := server.New()
		go sshServer.Start(&wg)
	}

	if clientEnable {
		var client clients.Client
		var err error

		logger.Info("Launching client", mode, version.String())

		args := clients.Args{
			Mode:               mode,
			ServersStr:         serversStr,
			Discovery:          discovery,
			UserName:           userName,
			Files:              files,
			Regex:              regex,
			TrustAllHosts:      trustAllHosts,
			MaxInitConnections: maxInitConnections,
			PingTimeout:        pingTimeoutS,
		}

		switch mode {
		case omode.TailClient:
			switch queryStr {
			case "":
				client, err = clients.NewTailClient(args)
			default:
				client, err = clients.NewMaprClient(args, queryStr)
			}
		case omode.GrepClient:
			client, err = clients.NewGrepClient(args)
		case omode.CatClient:
			client, err = clients.NewCatClient(args)
		case omode.MapClient:
			client, err = clients.NewMaprClient(args, queryStr)
		}

		if err != nil {
			panic(err)
		}

		go client.Start(&wg)
	}

	wg.Wait()
	logger.Stop()
}