2015-06-30 12:29:30 +00:00
// Copyright 2015 Prometheus Team
// 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.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
2015-07-01 11:17:08 +00:00
import (
2015-11-11 15:50:54 +00:00
"bytes"
2015-10-06 19:10:24 +00:00
"database/sql"
2015-07-01 15:56:53 +00:00
"flag"
2015-11-11 15:50:54 +00:00
"fmt"
2015-11-26 17:19:46 +00:00
"net"
2015-07-01 11:17:08 +00:00
"net/http"
2015-11-26 17:19:46 +00:00
"net/url"
2015-09-29 09:42:29 +00:00
"os"
"os/signal"
2015-10-06 10:36:33 +00:00
"path/filepath"
2015-11-11 15:50:54 +00:00
"strings"
2015-09-29 09:42:29 +00:00
"syscall"
2015-11-20 14:10:38 +00:00
tmpltext "text/template"
2015-11-27 14:41:22 +00:00
"time"
2015-07-01 11:17:08 +00:00
2015-09-28 10:12:27 +00:00
"github.com/prometheus/common/log"
2015-07-01 11:17:08 +00:00
"github.com/prometheus/common/route"
2015-07-01 15:56:53 +00:00
2015-09-25 16:14:46 +00:00
"github.com/prometheus/alertmanager/config"
2015-09-29 13:02:15 +00:00
"github.com/prometheus/alertmanager/notify"
2015-09-25 12:38:57 +00:00
"github.com/prometheus/alertmanager/provider"
2015-10-11 11:32:24 +00:00
"github.com/prometheus/alertmanager/template"
2015-11-09 13:34:57 +00:00
"github.com/prometheus/alertmanager/types"
2015-11-11 15:50:54 +00:00
"github.com/prometheus/alertmanager/version"
2015-07-01 15:56:53 +00:00
)
var (
2015-11-11 16:05:22 +00:00
showVersion = flag . Bool ( "version" , false , "Print version information." )
2015-11-20 14:10:38 +00:00
configFile = flag . String ( "config.file" , "alertmanager.yml" , "Alertmanager configuration file name." )
dataDir = flag . String ( "storage.path" , "data/" , "Base path for data storage." )
2015-11-11 16:05:22 +00:00
2015-11-20 14:10:38 +00:00
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." )
2015-09-30 15:24:06 +00:00
listenAddress = flag . String ( "web.listen-address" , ":9093" , "Address to listen on for the web interface and API." )
2015-07-01 11:17:08 +00:00
)
2015-06-30 12:29:30 +00:00
func main ( ) {
2015-09-29 09:50:59 +00:00
flag . Parse ( )
2015-11-11 15:50:54 +00:00
printVersion ( )
if * showVersion {
os . Exit ( 0 )
}
2015-10-29 13:30:58 +00:00
err := os . MkdirAll ( * dataDir , 0777 )
if err != nil {
log . Fatal ( err )
}
2015-10-06 19:10:24 +00:00
db , err := sql . Open ( "ql" , filepath . Join ( * dataDir , "am.db" ) )
if err != nil {
log . Fatal ( err )
}
defer db . Close ( )
2015-10-06 10:36:33 +00:00
2015-11-09 13:34:57 +00:00
marker := types . NewMarker ( )
2015-10-06 19:10:24 +00:00
alerts , err := provider . NewSQLAlerts ( db )
if err != nil {
log . Fatal ( err )
}
2015-11-20 14:10:38 +00:00
notifies , err := provider . NewSQLNotifies ( db )
2015-10-06 19:10:24 +00:00
if err != nil {
log . Fatal ( err )
}
2015-11-09 13:34:57 +00:00
silences , err := provider . NewSQLSilences ( db , marker )
2015-10-06 10:23:48 +00:00
if err != nil {
log . Fatal ( err )
}
2015-09-27 17:50:41 +00:00
2015-10-11 14:54:39 +00:00
var (
inhibitor * Inhibitor
tmpl * template . Template
disp * Dispatcher
)
defer disp . Stop ( )
2015-10-08 09:02:49 +00:00
2015-11-10 13:52:04 +00:00
api := NewAPI ( alerts , silences , func ( ) AlertOverview {
2015-11-07 13:30:21 +00:00
return disp . Groups ( )
2015-11-02 18:41:23 +00:00
} )
2015-11-10 13:08:20 +00:00
build := func ( rcvs [ ] * config . Receiver ) notify . Notifier {
2015-10-11 14:54:39 +00:00
var (
router = notify . Router { }
2015-11-10 13:08:20 +00:00
fanouts = notify . Build ( rcvs , tmpl )
2015-10-11 14:54:39 +00:00
)
for name , fo := range fanouts {
for i , n := range fo {
n = notify . Retry ( n )
n = notify . Log ( n , log . With ( "step" , "retry" ) )
n = notify . Dedup ( notifies , n )
n = notify . Log ( n , log . With ( "step" , "dedup" ) )
fo [ i ] = n
}
router [ name ] = fo
}
2015-11-20 14:10:38 +00:00
n := notify . Notifier ( router )
2015-10-08 09:02:49 +00:00
2015-10-11 14:54:39 +00:00
n = notify . Log ( n , log . With ( "step" , "route" ) )
n = notify . Mute ( silences , n )
n = notify . Log ( n , log . With ( "step" , "silence" ) )
n = notify . Mute ( inhibitor , n )
n = notify . Log ( n , log . With ( "step" , "inhibit" ) )
2015-10-08 09:02:49 +00:00
2015-10-11 14:54:39 +00:00
return n
2015-09-27 11:18:13 +00:00
}
2015-10-10 13:11:37 +00:00
2015-10-11 14:54:39 +00:00
reload := func ( ) ( err error ) {
log . With ( "file" , * configFile ) . Infof ( "Loading configuration file" )
defer func ( ) {
if err != nil {
2015-10-17 08:02:52 +00:00
log . With ( "file" , * configFile ) . Errorf ( "Loading configuration file failed: %s" , err )
2015-10-10 13:11:37 +00:00
}
2015-10-11 14:54:39 +00:00
} ( )
2015-10-10 13:11:37 +00:00
2015-10-11 14:54:39 +00:00
conf , err := config . LoadFile ( * configFile )
if err != nil {
return err
}
2015-10-10 13:11:37 +00:00
2015-11-27 14:41:22 +00:00
api . Update ( conf . String ( ) , time . Duration ( conf . Global . ResolveTimeout ) )
2015-11-02 18:41:23 +00:00
2015-10-11 14:54:39 +00:00
tmpl , err = template . FromGlobs ( conf . Templates ... )
if err != nil {
return err
}
2015-11-26 17:19:46 +00:00
if tmpl . ExternalURL , err = extURL ( * externalURL ) ; err != nil {
return err
}
2015-10-10 13:11:37 +00:00
2015-10-11 14:54:39 +00:00
disp . Stop ( )
2015-10-10 13:11:37 +00:00
2015-11-09 13:34:57 +00:00
inhibitor = NewInhibitor ( alerts , conf . InhibitRules , marker )
2015-11-10 13:08:20 +00:00
disp = NewDispatcher ( alerts , NewRoute ( conf . Route , nil ) , build ( conf . Receivers ) , marker )
2015-10-10 13:11:37 +00:00
2015-10-11 14:54:39 +00:00
go disp . Run ( )
2015-10-10 13:11:37 +00:00
2015-10-11 14:54:39 +00:00
return nil
2015-10-10 13:11:37 +00:00
}
2015-10-11 14:54:39 +00:00
if err := reload ( ) ; err != nil {
os . Exit ( 1 )
2015-09-29 10:22:13 +00:00
}
2015-07-01 11:17:08 +00:00
router := route . New ( )
2015-10-12 05:10:25 +00:00
RegisterWeb ( router )
2015-11-02 18:41:23 +00:00
api . Register ( router . WithPrefix ( "/api" ) )
2015-06-30 12:29:30 +00:00
2015-09-30 15:24:06 +00:00
go http . ListenAndServe ( * listenAddress , router )
2015-09-29 09:42:29 +00:00
2015-09-29 10:22:13 +00:00
var (
hup = make ( chan os . Signal )
term = make ( chan os . Signal )
)
signal . Notify ( hup , syscall . SIGHUP )
2015-09-29 09:42:29 +00:00
signal . Notify ( term , os . Interrupt , syscall . SIGTERM )
2015-09-29 10:22:13 +00:00
go func ( ) {
for range hup {
2015-10-11 14:54:39 +00:00
reload ( )
2015-09-29 10:22:13 +00:00
}
} ( )
2015-09-29 09:42:29 +00:00
<- term
2015-09-29 09:58:30 +00:00
log . Infoln ( "Received SIGTERM, exiting gracefully..." )
2015-09-29 10:22:13 +00:00
}
2015-11-11 15:50:54 +00:00
var versionInfoTmpl = `
alertmanager , version { { . version } } ( branch : { { . branch } } , revision : { { . revision } } )
build user : { { . buildUser } }
build date : { { . buildDate } }
go version : { { . goVersion } }
`
func printVersion ( ) {
2015-11-20 14:10:38 +00:00
t := tmpltext . Must ( tmpltext . New ( "version" ) . Parse ( versionInfoTmpl ) )
2015-11-11 15:50:54 +00:00
var buf bytes . Buffer
if err := t . ExecuteTemplate ( & buf , "version" , version . Map ) ; err != nil {
panic ( err )
}
fmt . Fprintln ( os . Stdout , strings . TrimSpace ( buf . String ( ) ) )
}
2015-11-26 17:19:46 +00:00
func extURL ( s string ) ( * url . URL , error ) {
if s == "" {
hostname , err := os . Hostname ( )
if err != nil {
return nil , err
}
_ , port , err := net . SplitHostPort ( * listenAddress )
if err != nil {
return nil , err
}
s = fmt . Sprintf ( "http://%s:%s/" , hostname , port )
}
u , err := url . Parse ( s )
if err != nil {
return nil , err
}
ppref := strings . TrimRight ( u . Path , "/" )
if ppref != "" && ! strings . HasPrefix ( ppref , "/" ) {
ppref = "/" + ppref
}
u . Path = ppref
return u , nil
}