2015-10-12 01:36:21 +00:00
|
|
|
package phpfpm
|
|
|
|
|
|
|
|
import (
|
2016-01-14 22:20:59 +00:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/binary"
|
2015-10-12 01:36:21 +00:00
|
|
|
"fmt"
|
2016-01-14 22:20:59 +00:00
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/http/fcgi"
|
|
|
|
"net/http/httptest"
|
2015-10-12 01:36:21 +00:00
|
|
|
"testing"
|
|
|
|
|
2016-01-20 18:57:35 +00:00
|
|
|
"github.com/influxdata/telegraf/testutil"
|
2015-10-12 01:36:21 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2016-01-14 22:20:59 +00:00
|
|
|
type statServer struct{}
|
|
|
|
|
|
|
|
// We create a fake server to return test data
|
|
|
|
func (s statServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
|
|
w.Header().Set("Content-Length", fmt.Sprint(len(outputSample)))
|
|
|
|
fmt.Fprint(w, outputSample)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPhpFpmGeneratesMetrics_From_Http(t *testing.T) {
|
|
|
|
sv := statServer{}
|
|
|
|
ts := httptest.NewServer(sv)
|
2015-10-12 01:36:21 +00:00
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{ts.URL},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err := acc.GatherError(r.Gather)
|
2015-10-12 01:36:21 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tags := map[string]string{
|
2016-01-14 22:20:59 +00:00
|
|
|
"pool": "www",
|
2018-03-23 18:50:52 +00:00
|
|
|
"url": ts.URL,
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
2019-06-17 19:55:09 +00:00
|
|
|
"start_since": int64(1991),
|
2016-01-14 22:20:59 +00:00
|
|
|
"accepted_conn": int64(3),
|
|
|
|
"listen_queue": int64(1),
|
|
|
|
"max_listen_queue": int64(0),
|
|
|
|
"listen_queue_len": int64(0),
|
|
|
|
"idle_processes": int64(1),
|
|
|
|
"active_processes": int64(1),
|
|
|
|
"total_processes": int64(2),
|
|
|
|
"max_active_processes": int64(1),
|
|
|
|
"max_children_reached": int64(2),
|
|
|
|
"slow_requests": int64(1),
|
|
|
|
}
|
|
|
|
|
|
|
|
acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPhpFpmGeneratesMetrics_From_Fcgi(t *testing.T) {
|
|
|
|
// Let OS find an available port
|
|
|
|
tcp, err := net.Listen("tcp", "127.0.0.1:0")
|
|
|
|
if err != nil {
|
2017-11-01 00:00:06 +00:00
|
|
|
t.Fatal("Cannot initialize test server")
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
defer tcp.Close()
|
|
|
|
|
|
|
|
s := statServer{}
|
|
|
|
go fcgi.Serve(tcp, s)
|
|
|
|
|
|
|
|
//Now we tested again above server
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{"fcgi://" + tcp.Addr().String() + "/status"},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
2017-04-24 18:13:26 +00:00
|
|
|
err = acc.GatherError(r.Gather)
|
2016-01-14 22:20:59 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tags := map[string]string{
|
|
|
|
"pool": "www",
|
2018-03-23 18:50:52 +00:00
|
|
|
"url": r.Urls[0],
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
2019-06-17 19:55:09 +00:00
|
|
|
"start_since": int64(1991),
|
2016-01-14 22:20:59 +00:00
|
|
|
"accepted_conn": int64(3),
|
|
|
|
"listen_queue": int64(1),
|
|
|
|
"max_listen_queue": int64(0),
|
|
|
|
"listen_queue_len": int64(0),
|
|
|
|
"idle_processes": int64(1),
|
|
|
|
"active_processes": int64(1),
|
|
|
|
"total_processes": int64(2),
|
|
|
|
"max_active_processes": int64(1),
|
|
|
|
"max_children_reached": int64(2),
|
|
|
|
"slow_requests": int64(1),
|
|
|
|
}
|
|
|
|
|
|
|
|
acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPhpFpmGeneratesMetrics_From_Socket(t *testing.T) {
|
|
|
|
// Create a socket in /tmp because we always have write permission and if the
|
|
|
|
// removing of socket fail when system restart /tmp is clear so
|
|
|
|
// we don't have junk files around
|
|
|
|
var randomNumber int64
|
|
|
|
binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
|
|
|
|
tcp, err := net.Listen("unix", fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber))
|
|
|
|
if err != nil {
|
2017-11-01 00:00:06 +00:00
|
|
|
t.Fatal("Cannot initialize server on port ")
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
defer tcp.Close()
|
|
|
|
s := statServer{}
|
|
|
|
go fcgi.Serve(tcp, s)
|
|
|
|
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{tcp.Addr().String()},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err = acc.GatherError(r.Gather)
|
2016-01-14 22:20:59 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tags := map[string]string{
|
|
|
|
"pool": "www",
|
2018-03-23 18:50:52 +00:00
|
|
|
"url": r.Urls[0],
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
2019-06-17 19:55:09 +00:00
|
|
|
"start_since": int64(1991),
|
2016-01-14 22:20:59 +00:00
|
|
|
"accepted_conn": int64(3),
|
|
|
|
"listen_queue": int64(1),
|
|
|
|
"max_listen_queue": int64(0),
|
|
|
|
"listen_queue_len": int64(0),
|
|
|
|
"idle_processes": int64(1),
|
|
|
|
"active_processes": int64(1),
|
|
|
|
"total_processes": int64(2),
|
|
|
|
"max_active_processes": int64(1),
|
|
|
|
"max_children_reached": int64(2),
|
|
|
|
"slow_requests": int64(1),
|
|
|
|
}
|
|
|
|
|
|
|
|
acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
|
|
|
|
}
|
|
|
|
|
2020-02-28 22:47:04 +00:00
|
|
|
func TestPhpFpmGeneratesMetrics_From_Multiple_Sockets_With_Glob(t *testing.T) {
|
|
|
|
// Create a socket in /tmp because we always have write permission and if the
|
|
|
|
// removing of socket fail when system restart /tmp is clear so
|
|
|
|
// we don't have junk files around
|
|
|
|
var randomNumber int64
|
|
|
|
binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
|
|
|
|
socket1 := fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber)
|
|
|
|
tcp1, err := net.Listen("unix", socket1)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Cannot initialize server on port ")
|
|
|
|
}
|
|
|
|
defer tcp1.Close()
|
|
|
|
|
|
|
|
binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
|
|
|
|
socket2 := fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber)
|
|
|
|
tcp2, err := net.Listen("unix", socket2)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Cannot initialize server on port ")
|
|
|
|
}
|
|
|
|
defer tcp2.Close()
|
|
|
|
|
|
|
|
s := statServer{}
|
|
|
|
go fcgi.Serve(tcp1, s)
|
|
|
|
go fcgi.Serve(tcp2, s)
|
|
|
|
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{"/tmp/test-fpm[\\-0-9]*.sock"},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc1, acc2 testutil.Accumulator
|
|
|
|
|
|
|
|
err = acc1.GatherError(r.Gather)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = acc2.GatherError(r.Gather)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tags1 := map[string]string{
|
|
|
|
"pool": "www",
|
|
|
|
"url": socket1,
|
|
|
|
}
|
|
|
|
|
|
|
|
tags2 := map[string]string{
|
|
|
|
"pool": "www",
|
|
|
|
"url": socket2,
|
|
|
|
}
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
|
|
|
"start_since": int64(1991),
|
|
|
|
"accepted_conn": int64(3),
|
|
|
|
"listen_queue": int64(1),
|
|
|
|
"max_listen_queue": int64(0),
|
|
|
|
"listen_queue_len": int64(0),
|
|
|
|
"idle_processes": int64(1),
|
|
|
|
"active_processes": int64(1),
|
|
|
|
"total_processes": int64(2),
|
|
|
|
"max_active_processes": int64(1),
|
|
|
|
"max_children_reached": int64(2),
|
|
|
|
"slow_requests": int64(1),
|
|
|
|
}
|
|
|
|
|
|
|
|
acc1.AssertContainsTaggedFields(t, "phpfpm", fields, tags1)
|
|
|
|
acc2.AssertContainsTaggedFields(t, "phpfpm", fields, tags2)
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:20:59 +00:00
|
|
|
func TestPhpFpmGeneratesMetrics_From_Socket_Custom_Status_Path(t *testing.T) {
|
|
|
|
// Create a socket in /tmp because we always have write permission. If the
|
|
|
|
// removing of socket fail we won't have junk files around. Cuz when system
|
|
|
|
// restart, it clears out /tmp
|
|
|
|
var randomNumber int64
|
|
|
|
binary.Read(rand.Reader, binary.LittleEndian, &randomNumber)
|
|
|
|
tcp, err := net.Listen("unix", fmt.Sprintf("/tmp/test-fpm%d.sock", randomNumber))
|
|
|
|
if err != nil {
|
2017-11-01 00:00:06 +00:00
|
|
|
t.Fatal("Cannot initialize server on port ")
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
defer tcp.Close()
|
|
|
|
s := statServer{}
|
|
|
|
go fcgi.Serve(tcp, s)
|
|
|
|
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{tcp.Addr().String() + ":custom-status-path"},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err = acc.GatherError(r.Gather)
|
2016-01-14 22:20:59 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tags := map[string]string{
|
2015-10-12 01:36:21 +00:00
|
|
|
"pool": "www",
|
2018-03-23 18:50:52 +00:00
|
|
|
"url": r.Urls[0],
|
2015-10-12 01:36:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:37:56 +00:00
|
|
|
fields := map[string]interface{}{
|
2019-06-17 19:55:09 +00:00
|
|
|
"start_since": int64(1991),
|
2016-01-07 00:37:56 +00:00
|
|
|
"accepted_conn": int64(3),
|
|
|
|
"listen_queue": int64(1),
|
|
|
|
"max_listen_queue": int64(0),
|
|
|
|
"listen_queue_len": int64(0),
|
|
|
|
"idle_processes": int64(1),
|
|
|
|
"active_processes": int64(1),
|
|
|
|
"total_processes": int64(2),
|
|
|
|
"max_active_processes": int64(1),
|
|
|
|
"max_children_reached": int64(2),
|
|
|
|
"slow_requests": int64(1),
|
2015-10-12 01:36:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:37:56 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "phpfpm", fields, tags)
|
2015-10-12 01:36:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//When not passing server config, we default to localhost
|
|
|
|
//We just want to make sure we did request stat from localhost
|
2016-01-14 22:20:59 +00:00
|
|
|
func TestPhpFpmDefaultGetFromLocalhost(t *testing.T) {
|
2015-10-12 01:36:21 +00:00
|
|
|
r := &phpfpm{}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err := acc.GatherError(r.Gather)
|
2015-10-12 01:36:21 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
assert.Contains(t, err.Error(), "127.0.0.1/status")
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:20:59 +00:00
|
|
|
func TestPhpFpmGeneratesMetrics_Throw_Error_When_Fpm_Status_Is_Not_Responding(t *testing.T) {
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{"http://aninvalidone"},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err := acc.GatherError(r.Gather)
|
2016-01-14 22:20:59 +00:00
|
|
|
require.Error(t, err)
|
2020-03-16 23:07:39 +00:00
|
|
|
assert.Contains(t, err.Error(), `Unable to connect to phpfpm status page 'http://aninvalidone'`)
|
|
|
|
assert.Contains(t, err.Error(), `lookup aninvalidone`)
|
2016-01-14 22:20:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPhpFpmGeneratesMetrics_Throw_Error_When_Socket_Path_Is_Invalid(t *testing.T) {
|
|
|
|
r := &phpfpm{
|
|
|
|
Urls: []string{"/tmp/invalid.sock"},
|
|
|
|
}
|
|
|
|
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err := acc.GatherError(r.Gather)
|
2016-01-14 22:20:59 +00:00
|
|
|
require.Error(t, err)
|
2020-02-28 22:47:04 +00:00
|
|
|
assert.Equal(t, `dial unix /tmp/invalid.sock: connect: no such file or directory`, err.Error())
|
2016-01-14 22:20:59 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-10-12 01:36:21 +00:00
|
|
|
const outputSample = `
|
|
|
|
pool: www
|
|
|
|
process manager: dynamic
|
|
|
|
start time: 11/Oct/2015:23:38:51 +0000
|
|
|
|
start since: 1991
|
|
|
|
accepted conn: 3
|
|
|
|
listen queue: 1
|
|
|
|
max listen queue: 0
|
|
|
|
listen queue len: 0
|
|
|
|
idle processes: 1
|
|
|
|
active processes: 1
|
|
|
|
total processes: 2
|
|
|
|
max active processes: 1
|
|
|
|
max children reached: 2
|
|
|
|
slow requests: 1
|
|
|
|
`
|