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

Metricbeat: Support multiple apache status page versions #6450

Merged
merged 1 commit into from
Mar 20, 2018
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 @@ -66,6 +66,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di
- Add filtering option by exact device names in system.diskio. `diskio.include_devices`. {pull}6085[6085]
- Fix dealing with new process status codes in Linux kernel 4.14+. {pull}6306[6306]
- Add config option for windows/perfmon metricset to ignore non existent counters. {pull}6432[6432]
- Support apache status pages for versions older than 2.4.16. {pull}6450[6450]

*Packetbeat*

Expand Down
5 changes: 5 additions & 0 deletions metricbeat/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ services:
apache:
build: ./module/apache/_meta

apache_2_4_12:
build:
context: ./module/apache/_meta
dockerfile: Dockerfile.2.4.12

ceph:
build: ./module/ceph/_meta

Expand Down
4 changes: 2 additions & 2 deletions metricbeat/docs/modules/apache.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ HTTPD] servers.
[float]
=== Compatibility

The Apache metricsets were tested with Apache 2.4.20 and are expected to work with all versions
>= 2.2.31 and >= 2.4.16.
The Apache metricsets were tested with Apache 2.4.12 and 2.4.20 and are expected to work with
all versions >= 2.2.31 and >= 2.4.16.


[float]
Expand Down
4 changes: 4 additions & 0 deletions metricbeat/module/apache/_meta/Dockerfile.2.4.12
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM httpd:2.4.12
RUN apt-get update && apt-get install -y curl
HEALTHCHECK --interval=1s --retries=90 CMD curl -f http://localhost
COPY ./httpd.conf /usr/local/apache2/conf/httpd.conf
4 changes: 2 additions & 2 deletions metricbeat/module/apache/_meta/docs.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ HTTPD] servers.
[float]
=== Compatibility

The Apache metricsets were tested with Apache 2.4.20 and are expected to work with all versions
>= 2.2.31 and >= 2.4.16.
The Apache metricsets were tested with Apache 2.4.12 and 2.4.20 and are expected to work with
all versions >= 2.2.31 and >= 2.4.16.


[float]
Expand Down
1 change: 1 addition & 0 deletions metricbeat/module/apache/_meta/env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
APACHE_HOST=apache
APACHE_OLD_HOST=apache_2_4_12
APACHE_PORT=80
35 changes: 33 additions & 2 deletions metricbeat/module/apache/status/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,40 @@ var (
"15": c.Float("Load15", s.Optional),
},
}

// Schema used till apache 2.4.12
schemaOld = s.Schema{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must make sure all these fields are also in the fields.yml documented.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

schemaOld contains a subset of the fields of the current schema.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I have removed the server_uptime field, it looks redundant to me with the uptime field. Also I think uptime shouldn't be a group, it should be enough with a long for this value, but changing from group to long looks fearful for backwards compatibility.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not introduce a breaking change here as this potentially goes out in a minor.

We should start a list of fields we want to change in the next master where we can break things.

For server_uptime vs uptime I'm not sure if one is from the actual host itself and the other one apache?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I revert these changes on server_update.

"total_accesses": c.Int("Total Accesses"),
"total_kbytes": c.Int("Total kBytes"),
"requests_per_sec": c.Float("ReqPerSec", s.Optional),
"bytes_per_sec": c.Float("BytesPerSec", s.Optional),
"workers": s.Object{
"busy": c.Int("BusyWorkers"),
"idle": c.Int("IdleWorkers"),
},
"uptime": s.Object{
"uptime": c.Int("Uptime"),
},
"connections": s.Object{
"total": c.Int("ConnsTotal", s.Optional),
"async": s.Object{
"writing": c.Int("ConnsAsyncWriting", s.Optional),
"keep_alive": c.Int("ConnsAsyncKeepAlive", s.Optional),
"closing": c.Int("ConnsAsyncClosing", s.Optional),
},
},
}
)

func applySchema(event common.MapStr, fullEvent map[string]interface{}) *s.Errors {
applicableSchema := schema
if _, found := fullEvent["ServerUptimeSeconds"]; !found {
applicableSchema = schemaOld
}
_, err := applicableSchema.ApplyTo(event, fullEvent)
return err
}

// Map body to MapStr
func eventMapping(scanner *bufio.Scanner, hostname string) (common.MapStr, *s.Errors) {
var (
Expand Down Expand Up @@ -140,9 +172,8 @@ func eventMapping(scanner *bufio.Scanner, hostname string) (common.MapStr, *s.Er
"total": totalAll,
},
}
_, err := schema.ApplyTo(event, fullEvent)

return event, err
return event, applySchema(event, fullEvent)
}

/*
Expand Down
2 changes: 1 addition & 1 deletion metricbeat/module/apache/status/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ func TestFetchEventContents(t *testing.T) {
assert.EqualValues(t, 63, event["total_kbytes"])

uptime := event["uptime"].(common.MapStr)
assert.EqualValues(t, 1026782, uptime["server_uptime"])
assert.EqualValues(t, 1026782, uptime["uptime"])
assert.EqualValues(t, 1026782, uptime["server_uptime"])
}

// TestFetchTimeout verifies that the HTTP request times out and an error is
Expand Down
56 changes: 43 additions & 13 deletions metricbeat/tests/system/test_apache.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@

APACHE_FIELDS = metricbeat.COMMON_FIELDS + ["apache"]

APACHE_STATUS_FIELDS = ["hostname", "total_accesses", "total_kbytes",
"requests_per_sec", "bytes_per_sec", "bytes_per_request",
"workers.busy", "workers.idle", "uptime", "cpu",
"connections", "load", "scoreboard"]
APACHE_STATUS_FIELDS = [
"hostname", "total_accesses", "total_kbytes",
"requests_per_sec", "bytes_per_sec", "bytes_per_request",
"workers.busy", "workers.idle", "uptime", "cpu",
"connections", "load", "scoreboard"
]

CPU_FIELDS = ["load", "user", "system", "children_user",
"children_system"]
APACHE_OLD_STATUS_FIELDS = [
"hostname", "total_accesses", "total_kbytes",
"requests_per_sec", "bytes_per_sec",
"workers.busy", "workers.idle", "uptime",
"connections", "scoreboard"
]


CPU_FIELDS = [
"load", "user", "system", "children_user", "children_system"
]


class ApacheStatusTest(metricbeat.BaseTest):
Expand All @@ -37,7 +48,7 @@ def test_output(self):

found = False
# Waits until CPULoad is part of the status
while found == False:
while not found:
res = urllib2.urlopen(hosts[0] + "/server-status?auto").read()
if "CPULoad" in res:
found = True
Expand All @@ -52,16 +63,35 @@ def test_output(self):
self.assertEqual(len(output), 1)
evt = output[0]

# Verify the required fields are present.
self.assertItemsEqual(self.de_dot(APACHE_FIELDS), evt.keys())
apache_status = evt["apache"]["status"]
self.assertItemsEqual(self.de_dot(APACHE_STATUS_FIELDS), apache_status.keys())
self.assertItemsEqual(self.de_dot(CPU_FIELDS), apache_status["cpu"].keys())
# There are more fields that could be checked.
self.verify_fields(evt)

# Verify all fields present are documented.
self.assert_fields_are_documented(evt)

def verify_fields(self, evt):
self.assertItemsEqual(self.de_dot(APACHE_FIELDS), evt.keys())
apache_status = evt["apache"]["status"]
self.assertItemsEqual(
self.de_dot(APACHE_STATUS_FIELDS), apache_status.keys())
self.assertItemsEqual(
self.de_dot(CPU_FIELDS), apache_status["cpu"].keys())
# There are more fields that could be checked.

def get_hosts(self):
return ['http://' + os.getenv('APACHE_HOST', 'localhost') + ':' +
os.getenv('APACHE_PORT', '80')]


class ApacheOldStatusTest(ApacheStatusTest):

COMPOSE_SERVICES = ['apache_2_4_12']

def verify_fields(self, evt):
self.assertItemsEqual(self.de_dot(APACHE_FIELDS), evt.keys())
apache_status = evt["apache"]["status"]
self.assertItemsEqual(
self.de_dot(APACHE_OLD_STATUS_FIELDS), apache_status.keys())

def get_hosts(self):
return ['http://' + os.getenv('APACHE_OLD_HOST', 'localhost') + ':' +
os.getenv('APACHE_PORT', '80')]