forked from mirrors/statsd_exporter
Log error and exit instead of panicking
Following the lead of prometheus/prometheus, we prefer to log-and-exit instead of an unstructured panic. cf. https://github.com/prometheus/prometheus/pull/3061/files#diff-4a3ccbb3ebdcd530af96f0105fe833c2R182 Signed-off-by: Matthias Rampke <mr@soundcloud.com>
This commit is contained in:
parent
0d72309324
commit
53f732d480
2 changed files with 55 additions and 27 deletions
|
@ -234,7 +234,8 @@ func (b *Exporter) handleEvent(event Event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unknown timer type '%s'", t))
|
level.Error(b.logger).Log("msg", "unknown timer type", "type", t)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -531,7 +532,8 @@ func (l *StatsDTCPListener) Listen() {
|
||||||
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("AcceptTCP failed: %s", err))
|
level.Error(l.logger).Log("msg", "AcceptTCP failed", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
go l.handleConn(c)
|
go l.handleConn(c)
|
||||||
}
|
}
|
||||||
|
|
76
main.go
76
main.go
|
@ -40,7 +40,7 @@ func init() {
|
||||||
prometheus.MustRegister(version.NewCollector("statsd_exporter"))
|
prometheus.MustRegister(version.NewCollector("statsd_exporter"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveHTTP(listenAddress, metricsEndpoint string) {
|
func serveHTTP(listenAddress, metricsEndpoint string, logger log.Logger) {
|
||||||
http.Handle(metricsEndpoint, promhttp.Handler())
|
http.Handle(metricsEndpoint, promhttp.Handler())
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte(`<html>
|
w.Write([]byte(`<html>
|
||||||
|
@ -51,13 +51,14 @@ func serveHTTP(listenAddress, metricsEndpoint string) {
|
||||||
</body>
|
</body>
|
||||||
</html>`))
|
</html>`))
|
||||||
})
|
})
|
||||||
panic(http.ListenAndServe(listenAddress, nil))
|
level.Error(logger).Log("msg", http.ListenAndServe(listenAddress, nil))
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipPortFromString(addr string) (*net.IPAddr, int) {
|
func ipPortFromString(addr string) (*net.IPAddr, int, error) {
|
||||||
host, portStr, err := net.SplitHostPort(addr)
|
host, portStr, err := net.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Bad StatsD listening address: %s", addr))
|
return nil, 0, fmt.Errorf("bad StatsD listening address: %s", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if host == "" {
|
if host == "" {
|
||||||
|
@ -65,33 +66,39 @@ func ipPortFromString(addr string) (*net.IPAddr, int) {
|
||||||
}
|
}
|
||||||
ip, err := net.ResolveIPAddr("ip", host)
|
ip, err := net.ResolveIPAddr("ip", host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Unable to resolve %s: %s", host, err))
|
return nil, 0, fmt.Errorf("Unable to resolve %s: %s", host, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
port, err := strconv.Atoi(portStr)
|
port, err := strconv.Atoi(portStr)
|
||||||
if err != nil || port < 0 || port > 65535 {
|
if err != nil || port < 0 || port > 65535 {
|
||||||
panic(fmt.Sprintf("Bad port %s: %s", portStr, err))
|
return nil, 0, fmt.Errorf("Bad port %s: %s", portStr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ip, port
|
return ip, port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func udpAddrFromString(addr string) *net.UDPAddr {
|
func udpAddrFromString(addr string) (*net.UDPAddr, error) {
|
||||||
ip, port := ipPortFromString(addr)
|
ip, port, err := ipPortFromString(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &net.UDPAddr{
|
return &net.UDPAddr{
|
||||||
IP: ip.IP,
|
IP: ip.IP,
|
||||||
Port: port,
|
Port: port,
|
||||||
Zone: ip.Zone,
|
Zone: ip.Zone,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tcpAddrFromString(addr string) *net.TCPAddr {
|
func tcpAddrFromString(addr string) (*net.TCPAddr, error) {
|
||||||
ip, port := ipPortFromString(addr)
|
ip, port, err := ipPortFromString(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &net.TCPAddr{
|
return &net.TCPAddr{
|
||||||
IP: ip.IP,
|
IP: ip.IP,
|
||||||
Port: port,
|
Port: port,
|
||||||
Zone: ip.Zone,
|
Zone: ip.Zone,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configReloader(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger) {
|
func configReloader(fileName string, mapper *mapper.MetricMapper, cacheSize int, logger log.Logger) {
|
||||||
|
@ -156,7 +163,8 @@ func main() {
|
||||||
logger := promlog.New(promlogConfig)
|
logger := promlog.New(promlogConfig)
|
||||||
|
|
||||||
if *statsdListenUDP == "" && *statsdListenTCP == "" && *statsdListenUnixgram == "" {
|
if *statsdListenUDP == "" && *statsdListenTCP == "" && *statsdListenUnixgram == "" {
|
||||||
panic("At least one of UDP/TCP/Unixgram listeners must be specified.")
|
level.Error(logger).Log("At least one of UDP/TCP/Unixgram listeners must be specified.")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
level.Info(logger).Log("msg", "Starting StatsD -> Prometheus Exporter", "version", version.Info())
|
level.Info(logger).Log("msg", "Starting StatsD -> Prometheus Exporter", "version", version.Info())
|
||||||
|
@ -164,23 +172,29 @@ func main() {
|
||||||
level.Info(logger).Log("msg", "Accepting StatsD Traffic", "udp", *statsdListenUDP, "tcp", *statsdListenTCP, "unixgram", *statsdListenUnixgram)
|
level.Info(logger).Log("msg", "Accepting StatsD Traffic", "udp", *statsdListenUDP, "tcp", *statsdListenTCP, "unixgram", *statsdListenUnixgram)
|
||||||
level.Info(logger).Log("msg", "Accepting Prometheus Requests", "addr", *listenAddress)
|
level.Info(logger).Log("msg", "Accepting Prometheus Requests", "addr", *listenAddress)
|
||||||
|
|
||||||
go serveHTTP(*listenAddress, *metricsEndpoint)
|
go serveHTTP(*listenAddress, *metricsEndpoint, logger)
|
||||||
|
|
||||||
events := make(chan Events, *eventQueueSize)
|
events := make(chan Events, *eventQueueSize)
|
||||||
defer close(events)
|
defer close(events)
|
||||||
eventQueue := newEventQueue(events, *eventFlushThreshold, *eventFlushInterval)
|
eventQueue := newEventQueue(events, *eventFlushThreshold, *eventFlushInterval)
|
||||||
|
|
||||||
if *statsdListenUDP != "" {
|
if *statsdListenUDP != "" {
|
||||||
udpListenAddr := udpAddrFromString(*statsdListenUDP)
|
udpListenAddr, err := udpAddrFromString(*statsdListenUDP)
|
||||||
|
if err != nil {
|
||||||
|
level.Error(logger).Log("msg", "invalid UDP listen address", "address", *statsdListenUDP, "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
uconn, err := net.ListenUDP("udp", udpListenAddr)
|
uconn, err := net.ListenUDP("udp", udpListenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
level.Error(logger).Log("msg", "failed to start UDP listener", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *readBuffer != 0 {
|
if *readBuffer != 0 {
|
||||||
err = uconn.SetReadBuffer(*readBuffer)
|
err = uconn.SetReadBuffer(*readBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Error setting UDP read buffer: %s", err))
|
level.Error(logger).Log("msg", "error setting UDP read buffer", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,10 +203,15 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *statsdListenTCP != "" {
|
if *statsdListenTCP != "" {
|
||||||
tcpListenAddr := tcpAddrFromString(*statsdListenTCP)
|
tcpListenAddr, err := tcpAddrFromString(*statsdListenTCP)
|
||||||
|
if err != nil {
|
||||||
|
level.Error(logger).Log("msg", "invalid TCP listen address", "address", *statsdListenUDP, "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
tconn, err := net.ListenTCP("tcp", tcpListenAddr)
|
tconn, err := net.ListenTCP("tcp", tcpListenAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
level.Error(logger).Log("msg", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer tconn.Close()
|
defer tconn.Close()
|
||||||
|
|
||||||
|
@ -203,14 +222,16 @@ func main() {
|
||||||
if *statsdListenUnixgram != "" {
|
if *statsdListenUnixgram != "" {
|
||||||
var err error
|
var err error
|
||||||
if _, err = os.Stat(*statsdListenUnixgram); !os.IsNotExist(err) {
|
if _, err = os.Stat(*statsdListenUnixgram); !os.IsNotExist(err) {
|
||||||
panic(fmt.Sprintf("Unixgram socket \"%s\" already exists", *statsdListenUnixgram))
|
level.Error(logger).Log("msg", "Unixgram socket already exists", "socket_name", *statsdListenUnixgram)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
uxgconn, err := net.ListenUnixgram("unixgram", &net.UnixAddr{
|
uxgconn, err := net.ListenUnixgram("unixgram", &net.UnixAddr{
|
||||||
Net: "unixgram",
|
Net: "unixgram",
|
||||||
Name: *statsdListenUnixgram,
|
Name: *statsdListenUnixgram,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
level.Error(logger).Log("msg", "failed to listen on Unixgram socket", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer uxgconn.Close()
|
defer uxgconn.Close()
|
||||||
|
@ -218,7 +239,8 @@ func main() {
|
||||||
if *readBuffer != 0 {
|
if *readBuffer != 0 {
|
||||||
err = uxgconn.SetReadBuffer(*readBuffer)
|
err = uxgconn.SetReadBuffer(*readBuffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Error setting Unixgram read buffer: %s", err))
|
level.Error(logger).Log("msg", "error setting Unixgram read buffer", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,12 +270,16 @@ func main() {
|
||||||
if *mappingConfig != "" {
|
if *mappingConfig != "" {
|
||||||
err := mapper.InitFromFile(*mappingConfig, *cacheSize)
|
err := mapper.InitFromFile(*mappingConfig, *cacheSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Error loading config: %s", err))
|
level.Error(logger).Log("msg", "error loading config", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if *dumpFSMPath != "" {
|
if *dumpFSMPath != "" {
|
||||||
err := dumpFSM(mapper, *dumpFSMPath, logger)
|
err := dumpFSM(mapper, *dumpFSMPath, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Error dumping FSM: %s", err))
|
level.Error(logger).Log("msg", "error dumping FSM", "error", err)
|
||||||
|
// Failure to dump the FSM is an error (the user asked for it and it
|
||||||
|
// didn't happen) but not fatal (the exporter is fully functional
|
||||||
|
// afterwards).
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue