From 13db402b1b3408242e6fc128bb1dc2937eef8cd1 Mon Sep 17 00:00:00 2001 From: Siarhei Navatski Date: Sun, 15 Sep 2019 19:42:35 +0300 Subject: [PATCH 1/2] Optional dependency on `github.com/prometheus/*` Signed-off-by: Siarhei Navatski --- example_test.go | 27 ++++++++++--------- .../metrics_handler.go | 15 ++++++----- .../metrics_handler_test.go | 3 +-- 3 files changed, 23 insertions(+), 22 deletions(-) rename metrics_handler.go => metrics/metrics_handler.go (82%) rename metrics_handler_test.go => metrics/metrics_handler_test.go (99%) diff --git a/example_test.go b/example_test.go index d7d7717..7193291 100644 --- a/example_test.go +++ b/example_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package healthcheck +package healthcheck_test import ( "database/sql" @@ -23,15 +23,16 @@ import ( "strings" "time" - sqlmock "gopkg.in/DATA-DOG/go-sqlmock.v1" - + "github.com/heptiolabs/healthcheck" + "github.com/heptiolabs/healthcheck/metrics" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "gopkg.in/DATA-DOG/go-sqlmock.v1" ) func Example() { // Create a Handler that we can use to register liveness and readiness checks. - health := NewHandler() + health := healthcheck.NewHandler() // Add a readiness check to make sure an upstream dependency resolves in DNS. // If this fails we don't want to receive requests, but we shouldn't be @@ -39,11 +40,11 @@ func Example() { upstreamHost := "upstream.example.com" health.AddReadinessCheck( "upstream-dep-dns", - DNSResolveCheck(upstreamHost, 50*time.Millisecond)) + healthcheck.DNSResolveCheck(upstreamHost, 50*time.Millisecond)) // Add a liveness check to detect Goroutine leaks. If this fails we want // to be restarted/rescheduled. - health.AddLivenessCheck("goroutine-threshold", GoroutineCountCheck(100)) + health.AddLivenessCheck("goroutine-threshold", healthcheck.GoroutineCountCheck(100)) // Serve http://0.0.0.0:8080/live and http://0.0.0.0:8080/ready endpoints. // go http.ListenAndServe("0.0.0.0:8080", health) @@ -65,11 +66,11 @@ func Example_database() { database = connectToDatabase() // Create a Handler that we can use to register liveness and readiness checks. - health := NewHandler() + health := healthcheck.NewHandler() // Add a readiness check to we don't receive requests unless we can reach // the database with a ping in <1 second. - health.AddReadinessCheck("database", DatabasePingCheck(database, 1*time.Second)) + health.AddReadinessCheck("database", healthcheck.DatabasePingCheck(database, 1*time.Second)) // Serve http://0.0.0.0:8080/live and http://0.0.0.0:8080/ready endpoints. // go http.ListenAndServe("0.0.0.0:8080", health) @@ -89,7 +90,7 @@ func Example_database() { func Example_advanced() { // Create a Handler that we can use to register liveness and readiness checks. - health := NewHandler() + health := healthcheck.NewHandler() // Make sure we can connect to an upstream dependency over TCP in less than // 50ms. Run this check asynchronously in the background every 10 seconds @@ -100,16 +101,16 @@ func Example_advanced() { upstreamAddr := "upstream.example.com:5432" health.AddReadinessCheck( "upstream-dep-tcp", - Async(TCPDialCheck(upstreamAddr, 50*time.Millisecond), 10*time.Second)) + healthcheck.Async(healthcheck.TCPDialCheck(upstreamAddr, 50*time.Millisecond), 10*time.Second)) // Add a readiness check against the health of an upstream HTTP dependency upstreamURL := "http://upstream-svc.example.com:8080/healthy" health.AddReadinessCheck( "upstream-dep-http", - HTTPGetCheck(upstreamURL, 500*time.Millisecond)) + healthcheck.HTTPGetCheck(upstreamURL, 500*time.Millisecond)) // Implement a custom check with a 50 millisecond timeout. - health.AddLivenessCheck("custom-check-with-timeout", Timeout(func() error { + health.AddLivenessCheck("custom-check-with-timeout", healthcheck.Timeout(func() error { // Simulate some work that could take a long time time.Sleep(time.Millisecond * 100) return nil @@ -143,7 +144,7 @@ func Example_metrics() { // Create a metrics-exposing Handler for the Prometheus registry // The healthcheck related metrics will be prefixed with the provided namespace - health := NewMetricsHandler(registry, "example") + health := metrics.NewMetricsHandler(registry, "example") // Add a simple readiness check that always fails. health.AddReadinessCheck("failing-check", func() error { diff --git a/metrics_handler.go b/metrics/metrics_handler.go similarity index 82% rename from metrics_handler.go rename to metrics/metrics_handler.go index e95be0f..1bd0aef 100644 --- a/metrics_handler.go +++ b/metrics/metrics_handler.go @@ -12,35 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -package healthcheck +package metrics import ( "net/http" + "github.com/heptiolabs/healthcheck" "github.com/prometheus/client_golang/prometheus" ) type metricsHandler struct { - handler Handler + handler healthcheck.Handler registry prometheus.Registerer namespace string } // NewMetricsHandler returns a healthcheck Handler that also exposes metrics // into the provided Prometheus registry. -func NewMetricsHandler(registry prometheus.Registerer, namespace string) Handler { +func NewMetricsHandler(registry prometheus.Registerer, namespace string) healthcheck.Handler { return &metricsHandler{ - handler: NewHandler(), + handler: healthcheck.NewHandler(), registry: registry, namespace: namespace, } } -func (h *metricsHandler) AddLivenessCheck(name string, check Check) { +func (h *metricsHandler) AddLivenessCheck(name string, check healthcheck.Check) { h.handler.AddLivenessCheck(name, h.wrap(name, check)) } -func (h *metricsHandler) AddReadinessCheck(name string, check Check) { +func (h *metricsHandler) AddReadinessCheck(name string, check healthcheck.Check) { h.handler.AddReadinessCheck(name, h.wrap(name, check)) } @@ -56,7 +57,7 @@ func (h *metricsHandler) ReadyEndpoint(w http.ResponseWriter, r *http.Request) { h.handler.ReadyEndpoint(w, r) } -func (h *metricsHandler) wrap(name string, check Check) Check { +func (h *metricsHandler) wrap(name string, check healthcheck.Check) healthcheck.Check { h.registry.MustRegister(prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: h.namespace, diff --git a/metrics_handler_test.go b/metrics/metrics_handler_test.go similarity index 99% rename from metrics_handler_test.go rename to metrics/metrics_handler_test.go index caea359..0721354 100644 --- a/metrics_handler_test.go +++ b/metrics/metrics_handler_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package healthcheck +package metrics import ( "fmt" @@ -23,7 +23,6 @@ import ( "testing" "github.com/prometheus/client_golang/prometheus" - "github.com/stretchr/testify/assert" ) From 1dbd897014112bb50c774d880655ae512d5b5159 Mon Sep 17 00:00:00 2001 From: Siarhei Navatski Date: Fri, 20 Dec 2019 17:52:52 +0300 Subject: [PATCH 2/2] Fix resources related tests Signed-off-by: Siarhei Navatski --- checks_test.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/checks_test.go b/checks_test.go index debe4ee..a6ff00a 100644 --- a/checks_test.go +++ b/checks_test.go @@ -23,17 +23,23 @@ import ( ) func TestTCPDialCheck(t *testing.T) { - assert.NoError(t, TCPDialCheck("heptio.com:80", 5*time.Second)()) - assert.Error(t, TCPDialCheck("heptio.com:25327", 5*time.Second)()) + t.Parallel() + + assert.NoError(t, TCPDialCheck("heptio.cloud.vmware.com:80", 5*time.Second)()) + assert.Error(t, TCPDialCheck("heptio.cloud.vmware.com:25327", 5*time.Second)()) } func TestHTTPGetCheck(t *testing.T) { - assert.NoError(t, HTTPGetCheck("https://heptio.com", 5*time.Second)()) - assert.Error(t, HTTPGetCheck("http://heptio.com", 5*time.Second)(), "redirect should fail") - assert.Error(t, HTTPGetCheck("https://heptio.com/nonexistent", 5*time.Second)(), "404 should fail") + t.Parallel() + + assert.NoError(t, HTTPGetCheck("https://heptio.cloud.vmware.com", 5*time.Second)()) + assert.Error(t, HTTPGetCheck("http://heptio.cloud.vmware.com", 5*time.Second)(), "redirect should fail") + assert.Error(t, HTTPGetCheck("https://heptio.cloud.vmware.com/nonexistent", 5*time.Second)(), "404 should fail") } func TestDatabasePingCheck(t *testing.T) { + t.Parallel() + assert.Error(t, DatabasePingCheck(nil, 1*time.Second)(), "nil DB should fail") db, _, err := sqlmock.New() @@ -42,11 +48,15 @@ func TestDatabasePingCheck(t *testing.T) { } func TestDNSResolveCheck(t *testing.T) { - assert.NoError(t, DNSResolveCheck("heptio.com", 5*time.Second)()) - assert.Error(t, DNSResolveCheck("nonexistent.heptio.com", 5*time.Second)()) + t.Parallel() + + assert.NoError(t, DNSResolveCheck("heptio.cloud.vmware.com", 5*time.Second)()) + assert.Error(t, DNSResolveCheck("nonexistent.heptio.cloud.vmware.com", 5*time.Second)()) } func TestGoroutineCountCheck(t *testing.T) { + t.Parallel() + assert.NoError(t, GoroutineCountCheck(1000)()) assert.Error(t, GoroutineCountCheck(0)()) }