diff --git a/register_metrics_test.go b/register_metrics_test.go index 0a46484..e2dbe12 100644 --- a/register_metrics_test.go +++ b/register_metrics_test.go @@ -4,6 +4,7 @@ import ( "io" "net/http" "net/http/httptest" + "strings" "sync" "testing" "time" @@ -67,4 +68,92 @@ func TestHTTPClient_MetricsIntegration(t *testing.T) { defer metrics.lock.Unlock() return len(metrics.pushToSeriesCalls) > 0 && len(metrics.incrCounterCalls) > 0 && len(metrics.incrCounterWithAttrsCalls) > 0 }, time.Second, 100*time.Millisecond) + + metrics.lock.Lock() + defer metrics.lock.Unlock() + + foundPush := false + for _, key := range metrics.pushToSeriesCalls { + if strings.HasSuffix(key, "response_time") { + foundPush = true + break + } + } + assert.True(t, foundPush, "PushToSeries should register key with suffix response_time") + + foundStatus := false + for _, key := range metrics.incrCounterCalls { + if strings.HasSuffix(key, "status.200") { + foundStatus = true + break + } + } + assert.True(t, foundStatus, "IncrCounter should register key with suffix status.200") + + foundAttrs := false + for _, call := range metrics.incrCounterWithAttrsCalls { + if strings.HasSuffix(call.key, "total") && + call.attrs["status"] == "200" && + call.attrs["host"] != "" { + foundAttrs = true + break + } + } + assert.True(t, foundAttrs, "IncrCounterWithAttrs should register correct attributes and key with suffix total") +} + +func TestHTTPClient_Metrics_Errors(t *testing.T) { + t.Run("circuit open error", func(t *testing.T) { + metrics := &mockMetrics{} + client := httpclient.NewHTTPClient( + &httpclient.LoggerAdapter{Writer: io.Discard}, + httpclient.WithMetrics(metrics), + httpclient.WithChainCallback(func(fn func() (*httpclient.Response, error)) (*httpclient.Response, error) { + return nil, httpclient.ErrCircuitOpen + }), + ) + _, _ = client.NewRequest().Get("/test-circuit-open") + time.Sleep(50 * time.Millisecond) + metrics.lock.Lock() + defer metrics.lock.Unlock() + found := false + for _, call := range metrics.incrCounterCalls { + if strings.HasSuffix(call, "circuit_open") { + found = true + break + } + } + assert.True(t, found, "Should increment circuit_open counter on ErrCircuitOpen") + }) + + t.Run("generic error", func(t *testing.T) { + metrics := &mockMetrics{} + client := httpclient.NewHTTPClient( + &httpclient.LoggerAdapter{Writer: io.Discard}, + httpclient.WithMetrics(metrics), + httpclient.WithChainCallback(func(fn func() (*httpclient.Response, error)) (*httpclient.Response, error) { + return nil, assert.AnError + }), + ) + _, _ = client.NewRequest().Get("/test-generic-error") + time.Sleep(50 * time.Millisecond) + metrics.lock.Lock() + defer metrics.lock.Unlock() + foundError := false + foundAttr := false + for _, call := range metrics.incrCounterCalls { + if strings.HasSuffix(call, "errors") { + foundError = true + break + } + } + for _, call := range metrics.incrCounterWithAttrsCalls { + if val, ok := call.attrs["error"]; ok && val == assert.AnError.Error() { + foundAttr = true + break + } + } + assert.True(t, foundError, "Should increment errors counter on generic error") + assert.True(t, foundAttr, "Should add error attribute on generic error") + }) } diff --git a/request.go b/request.go index 9c2cb13..478489e 100644 --- a/request.go +++ b/request.go @@ -150,7 +150,7 @@ func registerMetrics(key string, metrics Metrics, f func() (*Response, error)) ( if metrics != nil { go func(resp *Response, err error) { - var attrs map[string]string + attrs := map[string]string{} if resp != nil { attrs = map[string]string{ "host": resp.Request().HostURL().Host, @@ -167,6 +167,7 @@ func registerMetrics(key string, metrics Metrics, f func() (*Response, error)) ( metrics.IncrCounter(fmt.Sprintf("%s.%s", key, "circuit_open")) } else { metrics.IncrCounter(fmt.Sprintf("%s.%s", key, "errors")) + attrs["error"] = err.Error() } } metrics.IncrCounterWithAttrs(fmt.Sprintf("%s.%s", key, "total"), attrs)