-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Metricbeat: Add munin module #6517
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//// | ||
This file is generated! See scripts/docs_collector.py | ||
//// | ||
|
||
[[metricbeat-module-munin]] | ||
== Munin module | ||
|
||
experimental[] | ||
|
||
== munin module | ||
|
||
This is the munin module. | ||
|
||
|
||
|
||
[float] | ||
=== Example configuration | ||
|
||
The Munin module supports the standard configuration options that are described | ||
in <<configuration-metricbeat>>. Here is an example configuration: | ||
|
||
[source,yaml] | ||
---- | ||
metricbeat.modules: | ||
- module: munin | ||
metricsets: ["node"] | ||
enabled: false | ||
period: 10s | ||
hosts: ["localhost:4949"] | ||
node.namespace: node | ||
---- | ||
|
||
[float] | ||
=== Metricsets | ||
|
||
The following metricsets are available: | ||
|
||
* <<metricbeat-metricset-munin-node,node>> | ||
|
||
include::munin/node.asciidoc[] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
//// | ||
This file is generated! See scripts/docs_collector.py | ||
//// | ||
|
||
[[metricbeat-metricset-munin-node]] | ||
=== Munin node metricset | ||
|
||
experimental[] | ||
|
||
include::../../../module/munin/node/_meta/docs.asciidoc[] | ||
|
||
|
||
==== Fields | ||
|
||
For a description of each field in the metricset, see the | ||
<<exported-fields-munin,exported fields>> section. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
FROM ubuntu:16.04 | ||
|
||
RUN apt-get update && \ | ||
apt-get install -y munin-node netcat && \ | ||
apt-get clean && rm rm -rf /var/lib/apt/lists/* | ||
|
||
EXPOSE 4949 | ||
|
||
COPY munin-node.conf /etc/munin/munin-node.conf | ||
|
||
HEALTHCHECK --interval=1s --retries=90 CMD nc -z 127.0.0.1 4949 | ||
|
||
CMD munin-node |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
- module: munin | ||
metricsets: ["node"] | ||
enabled: false | ||
period: 10s | ||
hosts: ["localhost:4949"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add namespace config. |
||
node.namespace: node |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
== munin module | ||
|
||
This is the munin module. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
MUNIN_HOST=munin | ||
MUNIN_PORT=4949 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
- key: munin | ||
title: "Munin" | ||
description: > | ||
experimental[] | ||
|
||
Munin node metrics exporter | ||
release: experimental | ||
fields: | ||
- name: munin | ||
type: group | ||
description: > | ||
munin contains metrics exposed by a munin node agent | ||
fields: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
setsid 0 | ||
|
||
ignore_file [\#~]$ | ||
ignore_file DEADJOE$ | ||
ignore_file \.bak$ | ||
ignore_file %$ | ||
ignore_file \.dpkg-(tmp|new|old|dist)$ | ||
ignore_file \.rpm(save|new)$ | ||
ignore_file \.pod$ | ||
|
||
allow .* | ||
|
||
host 0.0.0.0 | ||
|
||
port 4949 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package munin is a Metricbeat module that contains MetricSets. | ||
package munin |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package munin | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"net" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/joeshaw/multierror" | ||
"github.com/pkg/errors" | ||
|
||
"github.com/elastic/beats/libbeat/common" | ||
) | ||
|
||
const ( | ||
unknownValue = "U" | ||
) | ||
|
||
// Node connection | ||
type Node struct { | ||
conn net.Conn | ||
|
||
writer io.Writer | ||
reader *bufio.Reader | ||
} | ||
|
||
// Connect with a munin node | ||
func Connect(address string, timeout time.Duration) (*Node, error) { | ||
conn, err := net.DialTimeout("tcp", address, timeout) | ||
if err != nil { | ||
return nil, err | ||
} | ||
n := &Node{conn: conn, | ||
writer: conn, | ||
reader: bufio.NewReader(conn), | ||
} | ||
// Cosume and ignore first line returned by munin, it is a comment | ||
// about the node | ||
scanner := bufio.NewScanner(n.reader) | ||
scanner.Scan() | ||
return n, scanner.Err() | ||
} | ||
|
||
// Close node connection relasing its resources | ||
func (n *Node) Close() error { | ||
return n.conn.Close() | ||
} | ||
|
||
// List of items exposed by the node | ||
func (n *Node) List() ([]string, error) { | ||
_, err := io.WriteString(n.writer, "list\n") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
scanner := bufio.NewScanner(n.reader) | ||
scanner.Scan() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we also check here the return value? |
||
return strings.Fields(scanner.Text()), scanner.Err() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see you run here |
||
} | ||
|
||
// Fetch metrics from munin node | ||
func (n *Node) Fetch(items ...string) (common.MapStr, error) { | ||
var errs multierror.Errors | ||
event := common.MapStr{} | ||
|
||
for _, item := range items { | ||
_, err := io.WriteString(n.writer, "fetch "+item+"\n") | ||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
scanner := bufio.NewScanner(n.reader) | ||
scanner.Split(bufio.ScanWords) | ||
for scanner.Scan() { | ||
name := strings.TrimSpace(scanner.Text()) | ||
|
||
// Munin delimites metrics with a dot | ||
if name == "." { | ||
break | ||
} | ||
|
||
name = strings.TrimSuffix(name, ".value") | ||
|
||
if !scanner.Scan() { | ||
if scanner.Err() == nil { | ||
errs = append(errs, errors.New("unexpected EOF when expecting value")) | ||
} | ||
break | ||
} | ||
value := scanner.Text() | ||
|
||
key := fmt.Sprintf("%s.%s", item, name) | ||
|
||
if value == unknownValue { | ||
errs = append(errs, errors.Errorf("unknown value for %s", key)) | ||
continue | ||
} | ||
if f, err := strconv.ParseFloat(value, 64); err == nil { | ||
event.Put(key, f) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for the record, this is a candidate for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, the PR went in already, so you can update these :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, but I think dots are not allowed in munin metric names. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if the float parsing will make a difference in ES. If we have a value 3 and we parse it it will still put 3 into the event and on the ES side it will assume it's an integer so conflicts will happen afterwards. Sounds like a good use case for the local fields definitions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Umm, so what do you recommend to do here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've checked metrics format, sounds like we don't need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what I'm getting at we could even skip this code part here and it would make no difference? If someone wants to make sure the mapping is correct he has to use #6024 Please double check the above statement as I don't know much about the munin output. |
||
continue | ||
} | ||
event.Put(key, value) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
if scanner.Err() != nil { | ||
errs = append(errs, scanner.Err()) | ||
} | ||
} | ||
|
||
return event, errs.Err() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add namespace config