Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Nginx Plus status #2329

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions metricbeat/include/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import (
_ "github.com/elastic/beats/metricbeat/module/mysql"
_ "github.com/elastic/beats/metricbeat/module/mysql/status"
_ "github.com/elastic/beats/metricbeat/module/nginx"
_ "github.com/elastic/beats/metricbeat/module/nginx/pluscache"
_ "github.com/elastic/beats/metricbeat/module/nginx/plustcpupstream"
_ "github.com/elastic/beats/metricbeat/module/nginx/plustcpzone"
_ "github.com/elastic/beats/metricbeat/module/nginx/plusupstream"
_ "github.com/elastic/beats/metricbeat/module/nginx/pluszone"
_ "github.com/elastic/beats/metricbeat/module/nginx/stubstatus"
_ "github.com/elastic/beats/metricbeat/module/postgresql"
_ "github.com/elastic/beats/metricbeat/module/postgresql/activity"
Expand Down
Empty file.
1 change: 1 addition & 0 deletions metricbeat/module/nginx/pluscache/_beat/docs.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
=== Nginx PlusCache MetricSet
9 changes: 9 additions & 0 deletions metricbeat/module/nginx/pluscache/_beat/fields.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- name: pluscache
type: group
description: >
`pluscache` reads server cache status from Nginx ngx_http_status_module.
fields:
- name: hostname
type: keyword
description: >
Nginx hostname
42 changes: 42 additions & 0 deletions metricbeat/module/nginx/pluscache/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package pluscache

import (
"encoding/json"
"io"
"io/ioutil"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/metricbeat/module/nginx"
)

// Map body to []MapStr
func eventMapping(m *MetricSet, body io.ReadCloser, hostname string, metricset string) ([]common.MapStr, error) {
// Nginx plus server caches:
b, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}

var caches map[string]interface{}
if err := json.Unmarshal([]byte(b), &caches); err != nil {
return nil, err
}
caches = nginx.Ftoi(caches)

events := []common.MapStr{}

for name, cache := range caches {
event := common.MapStr{
"hostname": hostname,
"name": name,
}

for k, v := range cache.(map[string]interface{}) {
event[k] = v
}

events = append(events, event)
}

return events, nil
}
84 changes: 84 additions & 0 deletions metricbeat/module/nginx/pluscache/pluscache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Package pluscache reads server cache status from Nginx, ngx_http_status_module is required.
package pluscache

import (
"fmt"
"net/http"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/logp"
"github.com/elastic/beats/metricbeat/mb"
"github.com/elastic/beats/metricbeat/module/nginx"
)

const (
// defaultScheme is the default scheme to use when it is not specified in
// the host config.
defaultScheme = "http"

// defaultPath is the default path to the ngx_http_status_module server cache endpoint on Nginx.
defaultPath = "/status/caches"
)

var (
debugf = logp.MakeDebug("nginx-status")
)

func init() {
if err := mb.Registry.AddMetricSet("nginx", "pluscache", New); err != nil {
panic(err)
}
}

// MetricSet for fetching Nginx plus status.
type MetricSet struct {
mb.BaseMetricSet

client *http.Client // HTTP client that is reused across requests.
url string // Nginx pluscache endpoint URL.

requests int
}

// New creates new instance of MetricSet
func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// Additional configuration options
config := struct {
ServerStatusPath string `config:"server_status_path"`
}{
ServerStatusPath: defaultPath,
}

if err := base.Module().UnpackConfig(&config); err != nil {
return nil, err
}

u, err := nginx.GetURL(config.ServerStatusPath, base.Host())
if err != nil {
return nil, err
}

debugf("nginx-pluscache URL=%s", u)
return &MetricSet{
BaseMetricSet: base,
url: u.String(),
client: &http.Client{Timeout: base.Module().Config().Timeout},
requests: 0,
}, nil
}

// Fetch makes an HTTP request to fetch status metrics from the pluscache endpoint.
func (m *MetricSet) Fetch() ([]common.MapStr, error) {
req, err := http.NewRequest("GET", m.url, nil)
resp, err := m.client.Do(req)
if err != nil {
return nil, fmt.Errorf("error making http request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, resp.Status)
}

return eventMapping(m, resp.Body, m.Host(), m.Name())
}
42 changes: 42 additions & 0 deletions metricbeat/module/nginx/pluscache/pluscache_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// +build integration

package pluscache

import (
"testing"

mbtest "github.com/elastic/beats/metricbeat/mb/testing"
"github.com/elastic/beats/metricbeat/module/nginx"

"github.com/stretchr/testify/assert"
)

func TestFetch(t *testing.T) {
f := mbtest.NewEventFetcher(t, getConfig())
event, err := f.Fetch()
if !assert.NoError(t, err) {
t.FailNow()
}

t.Logf("%s/%s event: %+v", f.Module().Name(), f.Name(), event)

// Check number of fields.
assert.Equal(t, 10, len(event))
}

func TestData(t *testing.T) {
f := mbtest.NewEventFetcher(t, getConfig())

err := mbtest.WriteEvent(f, t)
if err != nil {
t.Fatal("write", err)
}
}

func getConfig() map[string]interface{} {
return map[string]interface{}{
"module": "nginx",
"metricsets": []string{"pluscache"},
"hosts": []string{nginx.GetNginxEnvHost()},
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
=== Nginx PlusTCPUpstream MetricSet
9 changes: 9 additions & 0 deletions metricbeat/module/nginx/plustcpupstream/_beat/fields.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- name: plustcpupstream
type: group
description: >
`plustcpupstream` reads server tcpupstream status from Nginx ngx_http_status_module.
fields:
- name: hostname
type: keyword
description: >
Nginx hostname
42 changes: 42 additions & 0 deletions metricbeat/module/nginx/plustcpupstream/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package plustcpupstream

import (
"encoding/json"
"io"
"io/ioutil"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/metricbeat/module/nginx"
)

// Map body to []MapStr
func eventMapping(m *MetricSet, body io.ReadCloser, hostname string, metricset string) ([]common.MapStr, error) {
// Nginx plus server tcpupstreams:
b, err := ioutil.ReadAll(body)
if err != nil {
return nil, err
}

var tcpupstreams map[string]interface{}
if err := json.Unmarshal([]byte(b), &tcpupstreams); err != nil {
return nil, err
}
tcpupstreams = nginx.Ftoi(tcpupstreams)

events := []common.MapStr{}

for name, tcpupstream := range tcpupstreams {
event := common.MapStr{
"hostname": hostname,
"name": name,
}

for k, v := range tcpupstream.(map[string]interface{}) {
event[k] = v
}

events = append(events, event)
}

return events, nil
}
84 changes: 84 additions & 0 deletions metricbeat/module/nginx/plustcpupstream/plustcpupstream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Package plustcpupstream reads server tcpupstream status from Nginx, ngx_http_status_module is required.
package plustcpupstream

import (
"fmt"
"net/http"

"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/logp"
"github.com/elastic/beats/metricbeat/mb"
"github.com/elastic/beats/metricbeat/module/nginx"
)

const (
// defaultScheme is the default scheme to use when it is not specified in
// the host config.
defaultScheme = "http"

// defaultPath is the default path to the ngx_http_status_module server tcpupstream endpoint on Nginx.
defaultPath = "/status/tcpupstreams"
)

var (
debugf = logp.MakeDebug("nginx-status")
)

func init() {
if err := mb.Registry.AddMetricSet("nginx", "plustcpupstream", New); err != nil {
panic(err)
}
}

// MetricSet for fetching Nginx plus status.
type MetricSet struct {
mb.BaseMetricSet

client *http.Client // HTTP client that is reused across requests.
url string // Nginx plustcpupstream endpoint URL.

requests int
}

// New creates new instance of MetricSet
func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// Additional configuration options
config := struct {
ServerStatusPath string `config:"server_status_path"`
}{
ServerStatusPath: defaultPath,
}

if err := base.Module().UnpackConfig(&config); err != nil {
return nil, err
}

u, err := nginx.GetURL(config.ServerStatusPath, base.Host())
if err != nil {
return nil, err
}

debugf("nginx-plustcpupstream URL=%s", u)
return &MetricSet{
BaseMetricSet: base,
url: u.String(),
client: &http.Client{Timeout: base.Module().Config().Timeout},
requests: 0,
}, nil
}

// Fetch makes an HTTP request to fetch status metrics from the plustcpupstream endpoint.
func (m *MetricSet) Fetch() ([]common.MapStr, error) {
req, err := http.NewRequest("GET", m.url, nil)
resp, err := m.client.Do(req)
if err != nil {
return nil, fmt.Errorf("error making http request: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
return nil, fmt.Errorf("HTTP error %d: %s", resp.StatusCode, resp.Status)
}

return eventMapping(m, resp.Body, m.Host(), m.Name())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// +build integration

package plustcpupstream

import (
"testing"

mbtest "github.com/elastic/beats/metricbeat/mb/testing"
"github.com/elastic/beats/metricbeat/module/nginx"

"github.com/stretchr/testify/assert"
)

func TestFetch(t *testing.T) {
f := mbtest.NewEventFetcher(t, getConfig())
event, err := f.Fetch()
if !assert.NoError(t, err) {
t.FailNow()
}

t.Logf("%s/%s event: %+v", f.Module().Name(), f.Name(), event)

// Check number of fields.
assert.Equal(t, 10, len(event))
}

func TestData(t *testing.T) {
f := mbtest.NewEventFetcher(t, getConfig())

err := mbtest.WriteEvent(f, t)
if err != nil {
t.Fatal("write", err)
}
}

func getConfig() map[string]interface{} {
return map[string]interface{}{
"module": "nginx",
"metricsets": []string{"plustcpupstream"},
"hosts": []string{nginx.GetNginxEnvHost()},
}
}
Empty file.
1 change: 1 addition & 0 deletions metricbeat/module/nginx/plustcpzone/_beat/docs.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
=== Nginx PlusTCPZone MetricSet
9 changes: 9 additions & 0 deletions metricbeat/module/nginx/plustcpzone/_beat/fields.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- name: plustcpzone
type: group
description: >
`plustcpzone` reads server tcpzone status from Nginx ngx_http_status_module.
fields:
- name: hostname
type: keyword
description: >
Nginx hostname
Loading