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

Docker health metricset cleanup #3463

Merged
merged 1 commit into from
Jan 25, 2017
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ https://github.com/elastic/beats/compare/v5.1.1...master[Check the HEAD diff]
- Add system socket module that reports all TCP sockets. {pull}3246[3246]
- Kafka consumer groups metricset. {pull}3240[3240]
- Add dynamic configuration reloading for modules. {pull}3281[3281]
- Add docker health metricset {pull}3357[3357]

*Packetbeat*

Expand Down
3 changes: 3 additions & 0 deletions metricbeat/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ ENV METRICBEAT_PATH /go/src/github.com/elastic/beats/metricbeat

RUN mkdir -p $METRICBEAT_PATH/build/coverage
WORKDIR $METRICBEAT_PATH

# Add healthcheck for docker/healthcheck metricset to check during testing
HEALTHCHECK CMD exit 0
22 changes: 13 additions & 9 deletions metricbeat/module/docker/healthcheck/_meta/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,26 @@
"name": "host.example.com"
},
"docker": {
"container": {
"id": "6d01caff41f2f9118c0ced423579d70b6161eec614270e3cbf1b72e2bb40f84e",
"name": "gifted_hugle"
},
"healthcheck": {
"failingstreak": 0,
"status": "healthy",
"event": {
"end_date": "2017-01-09T20:38:13.080472813+01:00",
"exit_code": 0,
"output": "this is an event output",
"start_date": "2017-01-09T20:38:12.999970865+01:00",
}
"end_date": "2017-01-25T10:58:51.171Z",
"exit_code": 0,
"output": "",
"start_date": "2017-01-25T10:58:51.114Z"
},
"failingstreak": 0,
"status": "healthy"
}
},
"metricset": {
"host": "/var/run/docker.sock",
"module": "docker",
"name": "container",
"name": "healthcheck",
"rtt": 115
},
"type": "metricsets"
}
}
86 changes: 49 additions & 37 deletions metricbeat/module/docker/healthcheck/data.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,64 @@
package healthcheck

import (
"strings"

dc "github.com/fsouza/go-dockerclient"

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

dc "github.com/fsouza/go-dockerclient"
"strings"
)

func eventsMapping(containersList []dc.APIContainers, m *MetricSet) []common.MapStr {
myEvents := []common.MapStr{}
for _, container := range containersList {
returnevent := eventMapping(&container, m)
// Compare event to empty event
if returnevent != nil {
myEvents = append(myEvents, returnevent)
func eventsMapping(containers []dc.APIContainers, m *MetricSet) []common.MapStr {
var events []common.MapStr
for _, container := range containers {
event := eventMapping(&container, m)
if event != nil {
events = append(events, event)
}
}
return myEvents
return events
}

func eventMapping(cont *dc.APIContainers, m *MetricSet) common.MapStr {
event := common.MapStr{}
// Detect if healthcheck is available for container
if strings.Contains(cont.Status, "(") && strings.Contains(cont.Status, ")") {
container, _ := m.dockerClient.InspectContainer(cont.ID)
last_event := len(container.State.Health.Log) - 1
// Detect if an healthcheck already occured
if last_event >= 0 {
event = common.MapStr{
mb.ModuleData: common.MapStr{
"container": common.MapStr{
"name": docker.ExtractContainerName(cont.Names),
"id": cont.ID,
},
},
"status": container.State.Health.Status,
"failingstreak": container.State.Health.FailingStreak,
"event": common.MapStr{
"start_date": common.Time(container.State.Health.Log[last_event].Start),
"end_date": common.Time(container.State.Health.Log[last_event].End),
"exit_code": container.State.Health.Log[last_event].ExitCode,
"output": container.State.Health.Log[last_event].Output,
},
}
return event
}
if !hasHealthCheck(cont.Status) {
return nil
}
return nil

container, err := m.dockerClient.InspectContainer(cont.ID)
if err != nil {
logp.Err("Error inpsecting container %v: %v", cont.ID, err)
return nil
}
lastEvent := len(container.State.Health.Log) - 1

// Checks if a healthcheck already happened
if lastEvent < 0 {
return nil
}

return common.MapStr{
mb.ModuleData: common.MapStr{
"container": common.MapStr{
"name": docker.ExtractContainerName(cont.Names),
"id": cont.ID,
},
},
"status": container.State.Health.Status,
"failingstreak": container.State.Health.FailingStreak,
"event": common.MapStr{
"start_date": common.Time(container.State.Health.Log[lastEvent].Start),
"end_date": common.Time(container.State.Health.Log[lastEvent].End),
"exit_code": container.State.Health.Log[lastEvent].ExitCode,
"output": container.State.Health.Log[lastEvent].Output,
},
}

}

// hasHealthCheck detects if healthcheck is available for container
func hasHealthCheck(status string) bool {
return strings.Contains(status, "(") && strings.Contains(status, ")")
}
26 changes: 26 additions & 0 deletions metricbeat/tests/system/test_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,32 @@ def test_network_fields(self):
evt = self.remove_labels(evt)
self.assert_fields_are_documented(evt)

@unittest.skipUnless(metricbeat.INTEGRATION_TESTS, "integration test")
def test_health_fields(self):
"""
test health fields
"""
self.render_config_template(modules=[{
"name": "docker",
"metricsets": ["healthcheck"],
"hosts": ["unix:///var/run/docker.sock"],
"period": "1s",
}])

proc = self.start_beat()
self.wait_until(lambda: self.output_lines() > 0, max_timeout=20)
proc.check_kill_and_wait()

# Ensure no errors or warnings exist in the log.
log = self.get_log()
self.assertNotRegexpMatches(log.replace("WARN EXPERIMENTAL", ""), "ERR|WARN")

output = self.read_output_json()
evt = output[0]

evt = self.remove_labels(evt)
self.assert_fields_are_documented(evt)

def remove_labels(self, evt):

if 'labels' in evt["docker"]["container"]:
Expand Down