forked from linkedin/Burrow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
115 lines (99 loc) · 4.23 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
// Copyright 2017 LinkedIn Corp. Licensed under the Apache License, Version
// 2.0 (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// Burrow provides advanced Kafka Consumer Lag Checking.
// It is a monitoring companion for Apache Kafka that provides consumer lag checking as a service without the need for
// specifying thresholds. It monitors committed offsets for all consumers and calculates the status of those consumers
// on demand. An HTTP endpoint is provided to request status on demand, as well as provide other Kafka cluster
// information. There are also configurable notifiers that can send status out via email or HTTP calls to another
// service.
//
// # CLI or Library
//
// Burrow is designed to be run as a standalone application (CLI), and this is what the main package provides. In some
// situations it may be better for you to wrap Burrow with another application - for example, in environments where you
// have your own application structure to provide configuration and logging. To this end, Burrow can also be used as a
// library within another app.
//
// When embedding Burrow, please refer to https://github.com/linkedin/Burrow/blob/master/main.go for details on what
// preparation should happen before starting it. This is the wrapper that provides the CLI interface. The main logic
// for Burrow is in the core package, while the protocol package provides some of the common interfaces that are used.
//
// # Additional Documentation
//
// More documentation on Burrow, including configuration and HTTP requests, can be found at
// https://github.com/linkedin/Burrow/wiki
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"runtime"
"strings"
"syscall"
"time"
"github.com/spf13/viper"
"github.com/linkedin/Burrow/core"
)
// exitCode wraps a return value for the application
type exitCode struct{ Code int }
func handleExit() {
if e := recover(); e != nil {
if exit, ok := e.(exitCode); ok {
if exit.Code != 0 {
fmt.Fprintln(os.Stderr, "Burrow failed at", time.Now().Format("January 2, 2006 at 3:04pm (MST)"))
} else {
fmt.Fprintln(os.Stderr, "Stopped Burrow at", time.Now().Format("January 2, 2006 at 3:04pm (MST)"))
}
os.Exit(exit.Code)
}
panic(e) // not an exitCode, bubble up
}
}
func main() {
// This makes sure that we panic and run defers correctly
defer handleExit()
runtime.GOMAXPROCS(runtime.NumCPU())
// The only command line arg is the config file
configPath := flag.String("config-dir", ".", "Directory that contains the configuration file")
flag.Parse()
// Load the configuration from the file
viper.SetConfigName("burrow")
viper.AddConfigPath(*configPath)
fmt.Fprintln(os.Stderr, "Reading configuration from", *configPath)
err := viper.ReadInConfig()
if err != nil {
fmt.Fprintln(os.Stderr, "Failed reading configuration:", err.Error())
panic(exitCode{1})
}
// setup viper to be able to read env variables with a configured prefix
viper.SetDefault("general.env-var-prefix", "burrow")
envPrefix := viper.GetString("general.env-var-prefix")
viper.SetEnvPrefix(envPrefix)
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
viper.AutomaticEnv()
// Create the PID file to lock out other processes
viper.SetDefault("general.pidfile", "burrow.pid")
pidFile := viper.GetString("general.pidfile")
if !core.CheckAndCreatePidFile(pidFile) {
// Any error on checking or creating the PID file causes an immediate exit
panic(exitCode{1})
}
defer core.RemovePidFile(pidFile)
// Set up stderr/stdout to go to a separate log file, if enabled
stdoutLogfile := viper.GetString("general.stdout-logfile")
if stdoutLogfile != "" {
core.OpenOutLog(stdoutLogfile)
}
// Register signal handlers for exiting
exitChannel := make(chan os.Signal, 1)
signal.Notify(exitChannel, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
// This triggers handleExit (after other defers), which will then call os.Exit properly
panic(exitCode{core.Start(nil, exitChannel)})
}