From 03d87088d79054ac2f736d6b30cb0bd05a11f37d Mon Sep 17 00:00:00 2001 From: Stanislav Antic Date: Wed, 27 Jun 2018 01:23:50 +0200 Subject: [PATCH] fix: json: cannot unmarshal number (#28) * fixes hipages/php-fpm_exporter#26 * better comments & fix tests --- phpfpm/phpfpm.go | 47 +++++++++++++++++++++++++++++++------------ phpfpm/phpfpm_test.go | 4 +++- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/phpfpm/phpfpm.go b/phpfpm/phpfpm.go index 5bc3454..8e80e14 100644 --- a/phpfpm/phpfpm.go +++ b/phpfpm/phpfpm.go @@ -84,21 +84,23 @@ type Pool struct { Processes []PoolProcess `json:"processes"` } +type requestDuration int64 + // PoolProcess describes a single PHP-FPM process. A pool can have multiple processes. type PoolProcess struct { - PID int64 `json:"pid"` - State string `json:"state"` - StartTime int64 `json:"start time"` - StartSince int64 `json:"start since"` - Requests int64 `json:"requests"` - RequestDuration int64 `json:"request duration"` - RequestMethod string `json:"request method"` - RequestURI string `json:"request uri"` - ContentLength int64 `json:"content length"` - User string `json:"user"` - Script string `json:"script"` - LastRequestCPU float64 `json:"last request cpu"` - LastRequestMemory int64 `json:"last request memory"` + PID int64 `json:"pid"` + State string `json:"state"` + StartTime int64 `json:"start time"` + StartSince int64 `json:"start since"` + Requests int64 `json:"requests"` + RequestDuration requestDuration `json:"request duration"` + RequestMethod string `json:"request method"` + RequestURI string `json:"request uri"` + ContentLength int64 `json:"content length"` + User string `json:"user"` + Script string `json:"script"` + LastRequestCPU float64 `json:"last request cpu"` + LastRequestMemory int64 `json:"last request memory"` } // PoolProcessStateCounter holds the calculated metrics for pool processes. @@ -257,6 +259,25 @@ func (t *timestamp) UnmarshalJSON(b []byte) error { return nil } +// This is because of bug in php-fpm that can return 'request duration' which can't +// fit to int64. For details check links: +// https://bugs.php.net/bug.php?id=62382 +// https://serverfault.com/questions/624977/huge-request-duration-value-for-a-particular-php-script +func (rd *requestDuration) MarshalJSON() ([]byte, error) { + stamp := fmt.Sprint(rd) + return []byte(stamp), nil +} + +func (rd *requestDuration) UnmarshalJSON(b []byte) error { + rdc, err := strconv.Atoi(string(b)) + if err != nil { + *rd = 0 + } else { + *rd = requestDuration(rdc) + } + return nil +} + // SetLogger configures the used logger func SetLogger(logger logger) { log = logger diff --git a/phpfpm/phpfpm_test.go b/phpfpm/phpfpm_test.go index b23044b..4f031d2 100644 --- a/phpfpm/phpfpm_test.go +++ b/phpfpm/phpfpm_test.go @@ -91,7 +91,9 @@ func TestCannotUnmarshalNumberIssue10(t *testing.T) { err := json.Unmarshal(content, &pool) - assert.NotNil(t, err, err.Error()) + assert.Nil(t, err, "successfully unmarshal on invalid 'request duration'") + assert.Equal(t, int(pool.Processes[0].RequestDuration), 295, "request duration set to 0 because it couldn't be deserialized") + assert.Equal(t, int(pool.Processes[1].RequestDuration), 0, "request duration set to 0 because it couldn't be deserialized") } func TestParseURL(t *testing.T) {