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

New PHP-FPM metricbeat module #3415

Merged
merged 10 commits into from
Jan 24, 2017
Merged

New PHP-FPM metricbeat module #3415

merged 10 commits into from
Jan 24, 2017

Conversation

tsouza
Copy link

@tsouza tsouza commented Jan 19, 2017

This adds PHP-FPM support for metricbeat (#2247)

It is my first attempt writing a metricbeat module. One minor configuration that is not clear to me is how to externalize configuration of DefaultPath of the HostParser. Currently it is set to /status (which is php-fpm's default) but I just don't know how to make it user-configurable.

Also, I believe metricbeat creates sample dashboards, I would like to build a php-fpm sample dashboard and add it. Where to start?

@ruflin ruflin added the in progress Pull request is currently in progress. label Jan 19, 2017
@ruflin
Copy link
Member

ruflin commented Jan 19, 2017

@tsouza I recommend you to run make fmt and make update before the next commit. This will clean up the source code and update all generated files. This should get you closer to a green build :-)

Add pool start time and start since stats

Add support for proc stats

Refactor stats api call

Fix listen_queue => listen_queue_len"

Revert "Fix listen_queue => listen_queue_len""

This reverts commit 46ff489fa8cce8d73c2aba42758a51bde4d68a77.

Add suport for "listen_queue_len"

Add documentation

Minor const refactor

Add generated doc

Add basic testing

Fix illegal char in asciidoc

Fix type

Update generated files

Fix package name

Add integration tests
@ruflin
Copy link
Member

ruflin commented Jan 20, 2017

@tsouza Travis failures are unrelated to your PR. They should be fixed as soon as #3425 is merged.

Copy link
Member

@ruflin ruflin left a comment

Choose a reason for hiding this comment

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

I left you a few notes mainly on the schema of the events.

It would be nice to have a simple system tests that checks if docs and the generate events are in sync. See https://github.com/elastic/beats/blob/master/metricbeat/tests/system/test_mysql.py#L41 as an example.

Let me know if I can help in any way.

metricsets: ["pool"]
enabled: true
period: 10s
hosts: ["localhost"]
Copy link
Member

Choose a reason for hiding this comment

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

What is the default port the metrics are exposed? 80 or is it 9000 ?

Copy link
Author

@tsouza tsouza Jan 20, 2017

Choose a reason for hiding this comment

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

php-fpm default port is 9000 and default status endpoint is /status. But these defaults does matter much since it's fastcgi protocol and can't be accessed directly. So there is a need to configure a proxy (with fastcgi support) and that can be any port and path (no defaults)

Copy link
Member

Choose a reason for hiding this comment

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

Hm, problem is with the above port 80 is the default. Not sure what we should set here best.

Copy link
Author

Choose a reason for hiding this comment

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

Maybe we can use the "default non-default" 8080 (which is at least nginx's default, iirc)

Copy link
Member

Choose a reason for hiding this comment

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

SGTM

@@ -0,0 +1,6 @@
- module: php_fpm
Copy link
Member

Choose a reason for hiding this comment

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

We currently have all module configs commented out which are not enabled by default. This might change in the near future, but for consistency it should be commented out here

Copy link
Author

Choose a reason for hiding this comment

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

The module I started looking at to learn is haproxy, which is no commented out. But I'll do it then!

Copy link
Member

Choose a reason for hiding this comment

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

Ah, haproxy has a config.yml and a config.full.yml, that is why it also works there.

title: "php_fpm"
description: >
PHP-FPM server status metrics collected from PHP-FPM.
fields:
Copy link
Member

Choose a reason for hiding this comment

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

Can you add here the experimental[] flag? We do that for all new modules so we can still break compatibility after the first release. This might be a beta flag soonish.

Also please add short_config: false so it does not show up in the short config. See https://github.com/elastic/beats/blob/master/metricbeat/module/prometheus/_meta/fields.yml#L7 as example.

Copy link
Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

I think I forgot to mention it in the review, but also the metricsets should have a log line in the New(...) part that has a warning that it is experimental. Also see prometheus.

// HostParser is used for parsing the configured php-fpm hosts.
var HostParser = parse.URLHostParserBuilder{
DefaultScheme: defaultScheme,
DefaultPath: defaultPath,
Copy link
Member

Choose a reason for hiding this comment

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

To define a config option to change the defaultPath you can use PathConfigKey. See https://github.com/elastic/beats/blob/master/metricbeat/module/prometheus/collector/collector.go#L25 as an example. I would suggest to use path or status_path as the config option. All other parts are done automatically by the HostParser.

Copy link
Author

Choose a reason for hiding this comment

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

done

// configuration entries if needed.
func New(base mb.BaseMetricSet) (mb.MetricSet, error) {

config := struct{}{}
Copy link
Member

Choose a reason for hiding this comment

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

You can remove the config part as it is empty in your case.

description: >
The size of the socket queue of pending connections.

- name: idle_processes
Copy link
Member

Choose a reason for hiding this comment

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

processes.idle

description: >
The number of idle processes.

- name: active_processes
Copy link
Member

Choose a reason for hiding this comment

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

processes.active

description: >
The number of active processes.

- name: total_processes
Copy link
Member

Choose a reason for hiding this comment

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

processes.total

description: >
The number of idle + active processes.

- name: max_active_processes
Copy link
Member

Choose a reason for hiding this comment

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

processes.max_active

}

// PoolStats defines all stats fields from a php-fpm pool
type PoolStats struct {
Copy link
Member

Choose a reason for hiding this comment

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

If the response is in JSON, you could use the schema package to do the conversion. But we can also do that in a follow up PR.

Copy link
Author

Choose a reason for hiding this comment

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

Indeed the response is in JSON and also it came to me that there would be a better way of handling this situation. But I wonder what will happen to the field names itself, since php-fpm replies a JSON with whitespace in field names (e.g. accepted conn)

Mind pointing out an implementation that uses it?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

@andrewkroh andrewkroh left a comment

Choose a reason for hiding this comment

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

Nice job!

// NewStatsClient creates a new StatsClient
func NewStatsClient(m mb.BaseMetricSet, isFullStats bool) *StatsClient {
var address string
address = m.HostData().SanitizedURI + "?json"
Copy link
Member

Choose a reason for hiding this comment

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

You can move the query param to the URLHostParserBuilder by setting QueryParams: "json".

Copy link
Member

Choose a reason for hiding this comment

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

You can just write address := m.HostData().SanitizedURI and drop the var address string. (https://golang.org/ref/spec#Short_variable_declarations)


// Fetch php-fpm stats
func (c *StatsClient) Fetch() (io.ReadCloser, error) {
req, err := http.NewRequest("GET", c.address, nil)
Copy link
Member

Choose a reason for hiding this comment

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

Once #3413 merges we should update this to use it.

Copy link
Author

Choose a reason for hiding this comment

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

Actually, I was thinking of skipping the http proxy and directly access php-fpm using a fastcgi client. I could find this one go-fastcgi-client (since golang's fcgi package is for server only). What do you think?

@tsouza
Copy link
Author

tsouza commented Jan 21, 2017

The current metric names and it's description was copied directly from php-fpm configuration file. As they do not follow beats convention much (as pointed out by @ruflin), I decided to take a closer look to find proper names.

It seems that the process metrics regarding request IMO are useless. The metrics request duration, request method and request uri are from the current request at the time the status endpoint was invoked (which might temporarily become the last, if no request is being served by the process). Whereas the last request cpu/memory are calculated only after the request is done. Thus, in a running system serving several requests per second, there won't be any real correlation between last request cpu/memory and those request* metrics (or might be just too difficult to correlate).

So I am worried about that users might start to correlate between request uri and last request cpu, which might be misleading. This makes me wonder how useful those last request cpu/memory metrics might actually be (as the user could actually correlate with data generated by process metricbeat).

@ruflin
Copy link
Member

ruflin commented Jan 23, 2017

@tsouza If possible I would suggest to leave out calculated values as this can also be potentially done on the elasticsearch side. The way you describe it above it seems even to be temporary so not too usefule as you said.

To move this PR forward I suggest to remove the values you are not sure about are useful. The hard part of doing a Metricset is getting all the data and do the conversion. Adding a field is fairly easy. So in case someone requests it, we get the opportunity to ask why it is needed and how it is used and we can easily add it. WDYT?

@tsouza
Copy link
Author

tsouza commented Jan 24, 2017

@ruflin Agreed. I'll just keep the minimum set of metrics that I judge useful.

Also, thanks to this article for providing a much better documentation. I am leaving here for future reference.

"hostname": m.Host(),

"pool": stats.Pool,
"connections.queued": stats.ListenQueue,
Copy link
Member

Choose a reason for hiding this comment

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

You have to nest this into a common.MapStr as otherwise elasticsearch 2.x will complain here. So this becomes:

"connections": common.MapStr{
  "queued": stats.ListenQueue,
  "accepted" : stats.AcceptdConn,
}

Copy link
Author

Choose a reason for hiding this comment

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

Ok! The docs was not clear in that sense to me! So I just took a shot hah

Copy link
Member

Choose a reason for hiding this comment

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

I think we actually detected this problem with 2.x only after we wrote the docs ;-)

@ruflin ruflin added review and removed in progress Pull request is currently in progress. labels Jan 24, 2017
@ruflin ruflin merged commit 58ed51f into elastic:master Jan 24, 2017
@ruflin ruflin mentioned this pull request Jan 24, 2017
ruflin added a commit to ruflin/beats that referenced this pull request Jan 25, 2017
* Add docker environment for integration and system testing
* Add system test file to check for correct docs.
* Brings docs in line with generated output
* Update data.json
* Remove hostname fields as already part of metricset
* Apply schema instead of manual conversion
* Rename pool.pool to pool.name
* Remove separate http client as not needed anymore

This is a follow up PR for elastic#3415
tsg pushed a commit that referenced this pull request Jan 25, 2017
* Add docker environment for integration and system testing
* Add system test file to check for correct docs.
* Brings docs in line with generated output
* Update data.json
* Remove hostname fields as already part of metricset
* Apply schema instead of manual conversion
* Rename pool.pool to pool.name
* Remove separate http client as not needed anymore

This is a follow up PR for #3415
douaejeouit pushed a commit to douaejeouit/beats that referenced this pull request Jan 25, 2017
* Add docker environment for integration and system testing
* Add system test file to check for correct docs.
* Brings docs in line with generated output
* Update data.json
* Remove hostname fields as already part of metricset
* Apply schema instead of manual conversion
* Rename pool.pool to pool.name
* Remove separate http client as not needed anymore

This is a follow up PR for elastic#3415
@tsouza tsouza deleted the metricset-php_fpm branch January 25, 2017 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants