func main() { peers := &stringset{} var ( showVersion = flag.Bool("version", false, "Print version information.") configFile = flag.String("config.file", "alertmanager.yml", "Alertmanager configuration file name.") dataDir = flag.String("storage.path", "data/", "Base path for data storage.") retention = flag.Duration("data.retention", 5*24*time.Hour, "How long to keep data for.") externalURL = flag.String("web.external-url", "", "The URL under which Alertmanager is externally reachable (for example, if Alertmanager is served via a reverse proxy). Used for generating relative and absolute links back to Alertmanager itself. If the URL has a path portion, it will be used to prefix all HTTP endpoints served by Alertmanager. If omitted, relevant URL components will be derived automatically.") listenAddress = flag.String("web.listen-address", ":9093", "Address to listen on for the web interface and API.") meshListen = flag.String("mesh.listen-address", net.JoinHostPort("0.0.0.0", strconv.Itoa(mesh.Port)), "mesh listen address") hwaddr = flag.String("mesh.hardware-address", mustHardwareAddr(), "MAC address, i.e. mesh peer ID") nickname = flag.String("mesh.nickname", mustHostname(), "peer nickname") ) flag.Var(peers, "mesh.peer", "initial peers (may be repeated)") flag.Parse() if len(flag.Args()) > 0 { log.Fatalln("Received unexpected and unparsed arguments: ", strings.Join(flag.Args(), ", ")) } if *showVersion { fmt.Fprintln(os.Stdout, version.Print("alertmanager")) os.Exit(0) } log.Infoln("Starting alertmanager", version.Info()) log.Infoln("Build context", version.BuildContext()) err := os.MkdirAll(*dataDir, 0777) if err != nil { log.Fatal(err) } logger := log.NewLogger(os.Stderr) mrouter := initMesh(*meshListen, *hwaddr, *nickname) stopc := make(chan struct{}) var wg sync.WaitGroup wg.Add(1) notificationLog, err := nflog.New( nflog.WithMesh(func(g mesh.Gossiper) mesh.Gossip { return mrouter.NewGossip("nflog", g) }), nflog.WithRetention(*retention), nflog.WithSnapshot(filepath.Join(*dataDir, "nflog")), nflog.WithMaintenance(15*time.Minute, stopc, wg.Done), nflog.WithLogger(logger.With("component", "nflog")), ) if err != nil { log.Fatal(err) } marker := types.NewMarker() silences, err := silence.New(silence.Options{ SnapshotFile: filepath.Join(*dataDir, "silences"), Retention: *retention, Logger: logger.With("component", "silences"), Gossip: func(g mesh.Gossiper) mesh.Gossip { return mrouter.NewGossip("silences", g) }, }) if err != nil { log.Fatal(err) } // Start providers before router potentially sends updates. wg.Add(1) go func() { silences.Maintenance(15*time.Minute, filepath.Join(*dataDir, "silences"), stopc) wg.Done() }() mrouter.Start() defer func() { close(stopc) // Stop receiving updates from router before shutting down. mrouter.Stop() wg.Wait() }() mrouter.ConnectionMaker.InitiateConnections(peers.slice(), true) alerts, err := mem.NewAlerts(*dataDir) if err != nil { log.Fatal(err) } defer alerts.Close() var ( inhibitor *inhibit.Inhibitor tmpl *template.Template pipeline notify.Stage disp *dispatch.Dispatcher ) defer disp.Stop() apiv := api.New(alerts, silences, func() dispatch.AlertOverview { return disp.Groups() }) amURL, err := extURL(*listenAddress, *externalURL) if err != nil { log.Fatal(err) } waitFunc := meshWait(mrouter, 5*time.Second) timeoutFunc := func(d time.Duration) time.Duration { if d < notify.MinTimeout { d = notify.MinTimeout } return d + waitFunc() } reload := func() (err error) { log.With("file", *configFile).Infof("Loading configuration file") defer func() { if err != nil { log.With("file", *configFile).Errorf("Loading configuration file failed: %s", err) configSuccess.Set(0) } else { configSuccess.Set(1) configSuccessTime.Set(float64(time.Now().Unix())) } }() conf, err := config.LoadFile(*configFile) if err != nil { return err } apiv.Update(conf.String(), time.Duration(conf.Global.ResolveTimeout)) tmpl, err = template.FromGlobs(conf.Templates...) if err != nil { return err } tmpl.ExternalURL = amURL inhibitor.Stop() disp.Stop() inhibitor = inhibit.NewInhibitor(alerts, conf.InhibitRules, marker) pipeline = notify.BuildPipeline( conf.Receivers, tmpl, waitFunc, inhibitor, silences, notificationLog, marker, ) disp = dispatch.NewDispatcher(alerts, dispatch.NewRoute(conf.Route, nil), pipeline, marker, timeoutFunc) go disp.Run() go inhibitor.Run() return nil } if err := reload(); err != nil { os.Exit(1) } router := route.New() webReload := make(chan struct{}) ui.Register(router.WithPrefix(amURL.Path), webReload) apiv.Register(router.WithPrefix(path.Join(amURL.Path, "/api"))) log.Infoln("Listening on", *listenAddress) go listen(*listenAddress, router) var ( hup = make(chan os.Signal) hupReady = make(chan bool) term = make(chan os.Signal) ) signal.Notify(hup, syscall.SIGHUP) signal.Notify(term, os.Interrupt, syscall.SIGTERM) go func() { <-hupReady for { select { case <-hup: case <-webReload: } reload() } }() // Wait for reload or termination signals. close(hupReady) // Unblock SIGHUP handler. <-term log.Infoln("Received SIGTERM, exiting gracefully...") }
func main() { flag.Parse() http.Handle(*metricsPath, prometheus.Handler()) cfg, err := config.LoadFile(*configFile) if err != nil { log.Fatalln("Configuration file could not be read.", err) } c := newTailCollector(cfg) prometheus.MustRegister(c) // If args then start file/fifo collectors if len(flag.Args()) > 0 { for _, filename := range flag.Args() { go func(filename string) { var isPipe bool st, err := os.Stat(filename) if err == nil { if st.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { isPipe = true } } else { isPipe = false } t, err := tail.TailFile(filename, tail.Config{ Location: &tail.SeekInfo{0, os.SEEK_END}, ReOpen: true, Follow: isPipe, }) for line := range t.Lines { c.IngestLine(line.Text) } }(filename) } } // If collector address present, then start port collector. if *collectorAddress != "" { tcpSock, err := net.Listen("tcp", *collectorAddress) if err != nil { log.Fatalf("Error binding to TCP socket: %s", err) } go func() { for { conn, err := tcpSock.Accept() if err != nil { log.Errorf("Error accepting TCP connection: %s", err) continue } go func() { defer conn.Close() c.processReader(conn) }() } }() udpAddress, err := net.ResolveUDPAddr("udp", *collectorAddress) if err != nil { log.Fatalf("Error resolving UDP address: %s", err) } udpSock, err := net.ListenUDP("udp", udpAddress) if err != nil { log.Fatalf("Error listening to UDP address: %s", err) } go func() { defer udpSock.Close() for { buf := make([]byte, 65536) chars, srcAddress, err := udpSock.ReadFromUDP(buf) if err != nil { log.Errorf("Error reading UDP packet from %s: %s", srcAddress, err) continue } go c.processReader(bytes.NewReader(buf[0:chars])) } }() } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`<html> <head><title>Tail Exporter</title></head> <body> <h1>TCP/UDP Tail Exporter</h1> <p>Accepting raw lines over TCP and UDP on ` + *collectorAddress + `</p> <p>Watching files for lines:` + strings.Join(flag.Args(), ", ") + `</p> <p><a href="` + *metricsPath + `">Metrics</a></p> <h1>Config</h1> <pre>` + cfg.Original + `</pre> </body> </html>`)) }) log.Infof("Starting Server: %s", *listeningAddress) http.ListenAndServe(*listeningAddress, nil) }
func main() { rand.Seed(time.Now().Unix()) flag.Parse() // This is only used when we're running in -dev mode with bindata rootDir, _ = osext.ExecutableFolder() rootDir = path.Join(rootDir, "web") // Parse configuration cfg, err := config.LoadFromFile(*configFile) if err != nil { log.Fatalln("Error loading config", err) } // Templates amberTmpl, err := Asset("templates/index.amber") if err != nil { log.Fatalln("Could not load index template:", err) } tmpl := amber.MustCompile(string(amberTmpl), amber.Options{}) // Setup the web UI router := httprouter.New() router.Handler("GET", *metricsPath, prometheus.Handler()) // Prometheus // Static asset handling router.GET("/static/*filepath", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { reqpath := ps.ByName("filepath") realpath := path.Join("static", reqpath) b, err := Asset(realpath) if err != nil { log.Debugln("Could not find asset: ", err) return } else { w.Write(b) } }) var monitoredHosts []*pollers.Host router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { data := struct { Cfg *config.Config Hosts *[]*pollers.Host }{ Cfg: cfg, Hosts: &monitoredHosts, } err := tmpl.Execute(w, &data) if err != nil { log.Errorln("Error rendering template", err) } }) // Initialize the host pollers monitoredHosts = make([]*pollers.Host, len(cfg.Hosts)) // We don't allow duplicate hosts, but also don't want to panic just due // to a typo, so keep track and skip duplicates here. seenHosts := make(map[string]bool) realidx := 0 for _, hostCfg := range cfg.Hosts { log.Debugln("Setting up poller for: ", hostCfg.Hostname) if *skipPing { hostCfg.PingDisable = true } if _, ok := seenHosts[hostCfg.Hostname]; ok { log.Warnln("Discarding repeat configuration of same hostname", hostCfg.Hostname) continue } host := pollers.NewHost(hostCfg) monitoredHosts[realidx] = host prometheus.MustRegister(host) seenHosts[hostCfg.Hostname] = true realidx++ } // Trim monitoredHosts to the number we actually used monitoredHosts = monitoredHosts[0:realidx] // This is the dispatcher. It is responsible for invoking the doPoll method // of hosts. connectionLimiter := pollers.NewLimiter(*maxConnections) hostQueue := make(chan *pollers.Host) // Start the host dispatcher go func() { for host := range hostQueue { go host.Poll(connectionLimiter, hostQueue) } }() // Do the initial host dispatch go func() { for _, host := range monitoredHosts { log.Debugln("Starting polling for hosts") hostQueue <- host } }() var handler http.Handler // If basic auth is requested, enable it for the interface. if cfg.BasicAuthUsername != "" && cfg.BasicAuthPassword != "" { basicauth := httpauth.SimpleBasicAuth(cfg.BasicAuthUsername, cfg.BasicAuthPassword) handler = basicauth(router) } else { handler = router } // If TLS certificates are specificed, use TLS if cfg.TLSCertificatePath != "" && cfg.TLSKeyPath != "" { log.Infof("Listening on (TLS-enabled) %s", *listenAddress) err = http.ListenAndServeTLS(*listenAddress, cfg.TLSCertificatePath, cfg.TLSKeyPath, handler) } else { log.Infof("Listening on %s", *listenAddress) err = http.ListenAndServe(*listenAddress, handler) } if err != nil { log.Fatal(err) } }