diff --git a/README.md b/README.md index c4af59aa..ee221773 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Example usage: * Create dashboards in Kibana with metrics collected by Icinga 2 * Monitor notifications sent by Icinga 2 -**StatusPoller:** The Icinga 2 API exports lots of information about the state +**Statuspoller:** The Icinga 2 API exports lots of information about the state of the Icinga daemon. These information can be polled periodically. Example usage: @@ -110,8 +110,12 @@ Example for the CheckResult type with the service matching the string pattern filter: 'match("mysql*", event.service)' ``` -### StatusPoller -StatusPoller is not implemented yet. +### Statuspoller +These settings are specific to the statuspoller mode. + +#### `interval` +Interval at which the status API is called. Set to `0` to disable polling. +Defaults to `60s` ## Run To run Icingabeat with debugging output enabled, run: diff --git a/_meta/beat.yml b/_meta/beat.yml index a5972a2d..1384b4dd 100644 --- a/_meta/beat.yml +++ b/_meta/beat.yml @@ -57,3 +57,7 @@ icingabeat: # # To disable filtering set an empty string or comment out the filter option filter: "" + + statuspoller: + # Interval at which the status API is called. Set to 0 to disable polling. + interval: 60s diff --git a/beater/icingabeat.go b/beater/icingabeat.go index 31b9082f..6c0e8607 100644 --- a/beater/icingabeat.go +++ b/beater/icingabeat.go @@ -34,16 +34,21 @@ func New(b *beat.Beat, cfg *common.Config) (beat.Beater, error) { // Run Icingabeat func (bt *Icingabeat) Run(b *beat.Beat) error { - var eventstream *Eventstream - logp.Info("icingabeat is running! Hit CTRL-C to stop it.") bt.client = b.Publisher.Connect() if len(bt.config.Eventstream.Types) > 0 { + var eventstream *Eventstream eventstream = NewEventstream(bt, bt.config) go eventstream.Run() } + if bt.config.Statuspoller.Interval > 0 { + var statuspoller *Statuspoller + statuspoller = NewStatuspoller(bt, bt.config) + go statuspoller.Run() + } + for { select { case <-bt.done: diff --git a/beater/statuspoller.go b/beater/statuspoller.go new file mode 100644 index 00000000..0580e990 --- /dev/null +++ b/beater/statuspoller.go @@ -0,0 +1,107 @@ +package beater + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/url" + "strconv" + "time" + + "github.com/icinga/icingabeat/config" + + "github.com/elastic/beats/libbeat/common" + "github.com/elastic/beats/libbeat/logp" +) + +// Statuspoller type +type Statuspoller struct { + icingabeat *Icingabeat + config config.Config + + done chan struct{} +} + +// NewStatuspoller ... +func NewStatuspoller(bt *Icingabeat, cfg config.Config) *Statuspoller { + statuspoller := &Statuspoller{ + icingabeat: bt, + done: make(chan struct{}), + config: cfg, + } + return statuspoller +} + +// Run evenstream receiver +func (sp *Statuspoller) Run() error { + host := sp.config.Host + ":" + strconv.Itoa(sp.config.Port) + var URL *url.URL + + URL, err := url.Parse("https://" + host) + if err != nil { + logp.Info("Invalid request URL") + } + + URL.Path += "/v1/status" + + for { + ticker := time.NewTicker(sp.config.Statuspoller.Interval) + response, responseErr := requestURL(sp.icingabeat, "GET", URL) + var event common.MapStr + + if responseErr == nil { + body, err := ioutil.ReadAll(response.Body) + if err != nil { + logp.Warn("Response body invalid: %v", err) + } + + if err := json.Unmarshal(body, &event); err != nil { + logp.Info("Unmarshal problem %v", err) + + if err == io.ErrUnexpectedEOF || err == io.EOF { + break + } + continue + } + + for _, result := range event { + switch statustype := result.(type) { + case []interface{}: + + for _, status := range statustype { + fmt.Println(status) + + statusevent := common.MapStr{ + "@timestamp": common.Time(time.Now()), + "type": "icingabeat.status", + } + + for key, value := range status.(map[string]interface{}) { + if key != "perfdata" { + statusevent.Put(key, value) + } + } + + sp.icingabeat.client.PublishEvent(statusevent) + logp.Info("Event sent") + } + } + } + } else { + logp.Info("Error connecting to API: %v", responseErr) + } + + select { + case <-sp.done: + return nil + case <-ticker.C: + } + } + return nil +} + +// Stop eventstream receiver +func (sp *Statuspoller) Stop() { + close(sp.done) +} diff --git a/config/config.go b/config/config.go index 4b4169ab..432bc7c0 100644 --- a/config/config.go +++ b/config/config.go @@ -7,13 +7,14 @@ import "time" // Config options type Config struct { - Host string `config:"host"` - Port int `config:"port"` - User string `config:"user"` - Password string `config:"password"` - RetryInterval time.Duration `config:"retry_interval"` - SkipSSLVerify bool `config:"skip_ssl_verify"` - Eventstream EventstreamConfig `config:"eventstream"` + Host string `config:"host"` + Port int `config:"port"` + User string `config:"user"` + Password string `config:"password"` + RetryInterval time.Duration `config:"retry_interval"` + SkipSSLVerify bool `config:"skip_ssl_verify"` + Eventstream EventstreamConfig `config:"eventstream"` + Statuspoller StatuspollerConfig `config:"statuspoller"` } // EventstreamConfig optoins @@ -22,6 +23,11 @@ type EventstreamConfig struct { Filter string `config:"filter"` } +// StatuspollerConfig options +type StatuspollerConfig struct { + Interval time.Duration `config:"interval"` +} + // DefaultConfig values var DefaultConfig = Config{ RetryInterval: 1 * time.Second, diff --git a/icingabeat.full.yml b/icingabeat.full.yml index 7e5110e8..b564ed87 100644 --- a/icingabeat.full.yml +++ b/icingabeat.full.yml @@ -58,6 +58,10 @@ icingabeat: # To disable filtering set an empty string or comment out the filter option filter: "" + statuspoller: + # Interval at which the status API is called. Set to 0 to disable polling. + interval: 60s + #================================ General ====================================== # The name of the shipper that publishes the network data. It can be used to group diff --git a/icingabeat.yml b/icingabeat.yml index bbb2f0ec..6e401c00 100644 --- a/icingabeat.yml +++ b/icingabeat.yml @@ -58,6 +58,10 @@ icingabeat: # To disable filtering set an empty string or comment out the filter option filter: "" + statuspoller: + # Interval at which the status API is called. Set to 0 to disable polling. + interval: 60s + #================================ General ===================================== # The name of the shipper that publishes the network data. It can be used to group