github.com/arthur-befumo/witchcraft-go-server@v1.12.0/integration/metrics_test.go (about)

     1  // Copyright (c) 2018 Palantir Technologies. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package integration
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"encoding/json"
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/palantir/pkg/httpserver"
    29  	"github.com/palantir/pkg/metrics"
    30  	"github.com/palantir/witchcraft-go-logging/conjure/witchcraft/api/logging"
    31  	"github.com/palantir/witchcraft-go-server/config"
    32  	"github.com/palantir/witchcraft-go-server/witchcraft"
    33  	"github.com/stretchr/testify/assert"
    34  	"github.com/stretchr/testify/require"
    35  )
    36  
    37  // TestEmitMetrics verifies that metrics are printed periodically by a Witchcraft server and that the emitted values
    38  // respect the default blacklist. We verify both custom metrics set in the InitFunc (with tags) and server.response
    39  // metrics from the metrics middleware.
    40  func TestEmitMetrics(t *testing.T) {
    41  	logOutputBuffer := &bytes.Buffer{}
    42  	port, err := httpserver.AvailablePort()
    43  	require.NoError(t, err)
    44  
    45  	// ensure that registry used in this test is unique/does not have any past metrics registered on it
    46  	metrics.DefaultMetricsRegistry = metrics.NewRootMetricsRegistry()
    47  	server, serverErr, cleanup := createAndRunCustomTestServer(t, port, port, func(ctx context.Context, info witchcraft.InitInfo) (deferFn func(), rErr error) {
    48  		ctx = metrics.AddTags(ctx, metrics.MustNewTag("key", "val"))
    49  		metrics.FromContext(ctx).Counter("my-counter").Inc(13)
    50  		return nil, info.Router.Post("/error", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
    51  			rw.WriteHeader(500)
    52  		}))
    53  	}, logOutputBuffer, func(t *testing.T, initFn witchcraft.InitFunc, installCfg config.Install, logOutputBuffer io.Writer) *witchcraft.Server {
    54  		installCfg.MetricsEmitFrequency = 100 * time.Millisecond
    55  		return createTestServer(t, initFn, installCfg, logOutputBuffer)
    56  	})
    57  	defer func() {
    58  		require.NoError(t, server.Close())
    59  	}()
    60  	defer cleanup()
    61  
    62  	// Make POST that will 404 to trigger request size and error rate metrics
    63  	_, err = testServerClient().Post(fmt.Sprintf("https://localhost:%d/%s/%s", port, basePath, "error"), "application/json", strings.NewReader("{}"))
    64  	require.NoError(t, err)
    65  
    66  	// Allow the metric emitter to do its thing.
    67  	time.Sleep(150 * time.Millisecond)
    68  
    69  	parts := strings.Split(logOutputBuffer.String(), "\n")
    70  	var metricLogs []logging.MetricLogV1
    71  	for _, curr := range parts {
    72  		if strings.Contains(curr, `"metric.1"`) {
    73  			var currLog logging.MetricLogV1
    74  			require.NoError(t, json.Unmarshal([]byte(curr), &currLog))
    75  			metricLogs = append(metricLogs, currLog)
    76  		}
    77  	}
    78  
    79  	var seenMyCounter, seenResponseTimer, seenUptime, seenResponseSize, seenRequestSize, seenResponseError bool
    80  	for _, metricLog := range metricLogs {
    81  		switch metricLog.MetricName {
    82  		case "my-counter":
    83  			seenMyCounter = true
    84  			assert.Equal(t, "counter", metricLog.MetricType, "my-counter metric had incorrect type")
    85  			assert.Equal(t, map[string]interface{}{"count": json.Number("13")}, metricLog.Values)
    86  			assert.Equal(t, map[string]string{"key": "val"}, metricLog.Tags)
    87  		case "server.response":
    88  			seenResponseTimer = true
    89  			assert.Equal(t, "timer", metricLog.MetricType, "server.response metric had incorrect type")
    90  			assert.NotNil(t, metricLog.Values["count"])
    91  			assert.NotNil(t, metricLog.Values["max"])
    92  			assert.NotNil(t, metricLog.Values["p95"])
    93  			assert.NotNil(t, metricLog.Values["p99"])
    94  
    95  			// keys are part of the default blacklist and should thus be nil
    96  			assert.Nil(t, metricLog.Values["1m"])
    97  			assert.Nil(t, metricLog.Values["5m"])
    98  			assert.Nil(t, metricLog.Values["15m"])
    99  			assert.Nil(t, metricLog.Values["meanRate"])
   100  			assert.Nil(t, metricLog.Values["min"])
   101  			assert.Nil(t, metricLog.Values["mean"])
   102  			assert.Nil(t, metricLog.Values["stddev"])
   103  			assert.Nil(t, metricLog.Values["p50"])
   104  		case "server.request.size":
   105  			seenRequestSize = true
   106  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   107  			assert.NotNil(t, metricLog.Values["max"])
   108  			assert.NotNil(t, metricLog.Values["p95"])
   109  			assert.NotNil(t, metricLog.Values["p99"])
   110  			assert.NotNil(t, metricLog.Values["count"])
   111  
   112  			// keys are part of the default blacklist and should thus be nil
   113  			assert.Nil(t, metricLog.Values["min"])
   114  			assert.Nil(t, metricLog.Values["mean"])
   115  			assert.Nil(t, metricLog.Values["stddev"])
   116  			assert.Nil(t, metricLog.Values["p50"])
   117  		case "server.response.size":
   118  			seenResponseSize = true
   119  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   120  			assert.NotNil(t, metricLog.Values["max"])
   121  			assert.NotNil(t, metricLog.Values["p95"])
   122  			assert.NotNil(t, metricLog.Values["p99"])
   123  			assert.NotNil(t, metricLog.Values["count"])
   124  
   125  			// keys are part of the default blacklist and should thus be nil
   126  			assert.Nil(t, metricLog.Values["min"])
   127  			assert.Nil(t, metricLog.Values["mean"])
   128  			assert.Nil(t, metricLog.Values["stddev"])
   129  			assert.Nil(t, metricLog.Values["p50"])
   130  		case "server.response.error":
   131  			seenResponseError = true
   132  			assert.Equal(t, "meter", metricLog.MetricType, "server.response metric had incorrect type")
   133  			assert.NotNil(t, metricLog.Values["count"])
   134  
   135  			// keys are part of the default blacklist and should thus be nil
   136  			assert.Nil(t, metricLog.Values["1m"])
   137  			assert.Nil(t, metricLog.Values["5m"])
   138  			assert.Nil(t, metricLog.Values["15m"])
   139  			assert.Nil(t, metricLog.Values["mean"])
   140  		case "server.uptime":
   141  			seenUptime = true
   142  			assert.Equal(t, "gauge", metricLog.MetricType, "server.uptime metric had incorrect type")
   143  			assert.NotZero(t, metricLog.Values["value"])
   144  		default:
   145  			assert.Fail(t, "unexpected metric encountered: %s", metricLog.MetricName)
   146  		}
   147  	}
   148  	assert.True(t, seenMyCounter, "my-counter metric was not emitted")
   149  	assert.True(t, seenResponseTimer, "server.response metric was not emitted")
   150  	assert.True(t, seenRequestSize, "server.request.size metric was not emitted")
   151  	assert.True(t, seenResponseSize, "server.response.size metric was not emitted")
   152  	assert.True(t, seenResponseError, "server.response.error metric was not emitted")
   153  	assert.True(t, seenUptime, "server.uptime metric was not emitted")
   154  
   155  	select {
   156  	case err := <-serverErr:
   157  		require.NoError(t, err)
   158  	default:
   159  	}
   160  }
   161  
   162  // TestEmitMetricsEmptyBlacklist verifies that metrics are printed periodically by a Witchcraft server and that, if the
   163  // blacklist is empty, all values are emitted. We verify both custom metrics set in the InitFunc (with tags) and
   164  // server.response metrics from the metrics middleware.
   165  func TestEmitMetricsEmptyBlacklist(t *testing.T) {
   166  	logOutputBuffer := &bytes.Buffer{}
   167  	port, err := httpserver.AvailablePort()
   168  	require.NoError(t, err)
   169  
   170  	// ensure that registry used in this test is unique/does not have any past metrics registered on it
   171  	metrics.DefaultMetricsRegistry = metrics.NewRootMetricsRegistry()
   172  	server, serverErr, cleanup := createAndRunCustomTestServer(t, port, port, func(ctx context.Context, info witchcraft.InitInfo) (deferFn func(), rErr error) {
   173  		ctx = metrics.AddTags(ctx, metrics.MustNewTag("key", "val"))
   174  		metrics.FromContext(ctx).Counter("my-counter").Inc(13)
   175  		return nil, info.Router.Post("/error", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
   176  			rw.WriteHeader(500)
   177  		}))
   178  	}, logOutputBuffer, func(t *testing.T, initFn witchcraft.InitFunc, installCfg config.Install, logOutputBuffer io.Writer) *witchcraft.Server {
   179  		installCfg.MetricsEmitFrequency = 100 * time.Millisecond
   180  		return createTestServer(t, initFn, installCfg, logOutputBuffer).WithMetricTypeValuesBlacklist(map[string]map[string]struct{}{})
   181  	})
   182  	defer func() {
   183  		require.NoError(t, server.Close())
   184  	}()
   185  	defer cleanup()
   186  
   187  	// Make POST that will 404 to trigger request size and error rate metrics
   188  	_, err = testServerClient().Post(fmt.Sprintf("https://localhost:%d/%s/%s", port, basePath, "error"), "application/json", strings.NewReader("{}"))
   189  	require.NoError(t, err)
   190  
   191  	// Allow the metric emitter to do its thing.
   192  	time.Sleep(150 * time.Millisecond)
   193  
   194  	parts := strings.Split(logOutputBuffer.String(), "\n")
   195  	var metricLogs []logging.MetricLogV1
   196  	for _, curr := range parts {
   197  		if strings.Contains(curr, `"metric.1"`) {
   198  			var currLog logging.MetricLogV1
   199  			require.NoError(t, json.Unmarshal([]byte(curr), &currLog))
   200  			metricLogs = append(metricLogs, currLog)
   201  		}
   202  	}
   203  
   204  	var seenMyCounter, seenResponseTimer, seenResponseSize, seenRequestSize, seenResponseError, seenUptime bool
   205  	for _, metricLog := range metricLogs {
   206  		switch metricLog.MetricName {
   207  		case "my-counter":
   208  			seenMyCounter = true
   209  			assert.Equal(t, "counter", metricLog.MetricType, "my-counter metric had incorrect type")
   210  			assert.Equal(t, map[string]interface{}{"count": json.Number("13")}, metricLog.Values)
   211  			assert.Equal(t, map[string]string{"key": "val"}, metricLog.Tags)
   212  		case "server.response":
   213  			seenResponseTimer = true
   214  			assert.Equal(t, "timer", metricLog.MetricType, "server.response metric had incorrect type")
   215  
   216  			// blacklist is set to empty, so all keys should be non-nil
   217  			assert.NotNil(t, metricLog.Values["count"])
   218  			assert.NotNil(t, metricLog.Values["1m"])
   219  			assert.NotNil(t, metricLog.Values["5m"])
   220  			assert.NotNil(t, metricLog.Values["15m"])
   221  			assert.NotNil(t, metricLog.Values["meanRate"])
   222  			assert.NotNil(t, metricLog.Values["min"])
   223  			assert.NotNil(t, metricLog.Values["max"])
   224  			assert.NotNil(t, metricLog.Values["mean"])
   225  			assert.NotNil(t, metricLog.Values["stddev"])
   226  			assert.NotNil(t, metricLog.Values["p50"])
   227  			assert.NotNil(t, metricLog.Values["p95"])
   228  			assert.NotNil(t, metricLog.Values["p99"])
   229  		case "server.request.size":
   230  			seenRequestSize = true
   231  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   232  
   233  			// blacklist is set to empty, so all keys should be non-nil
   234  			assert.NotNil(t, metricLog.Values["min"])
   235  			assert.NotNil(t, metricLog.Values["max"])
   236  			assert.NotNil(t, metricLog.Values["mean"])
   237  			assert.NotNil(t, metricLog.Values["stddev"])
   238  			assert.NotNil(t, metricLog.Values["p50"])
   239  			assert.NotNil(t, metricLog.Values["p95"])
   240  			assert.NotNil(t, metricLog.Values["p99"])
   241  			assert.NotNil(t, metricLog.Values["count"])
   242  		case "server.response.size":
   243  			seenResponseSize = true
   244  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   245  
   246  			// blacklist is set to empty, so all keys should be non-nil
   247  			assert.NotNil(t, metricLog.Values["min"])
   248  			assert.NotNil(t, metricLog.Values["max"])
   249  			assert.NotNil(t, metricLog.Values["mean"])
   250  			assert.NotNil(t, metricLog.Values["stddev"])
   251  			assert.NotNil(t, metricLog.Values["p50"])
   252  			assert.NotNil(t, metricLog.Values["p95"])
   253  			assert.NotNil(t, metricLog.Values["p99"])
   254  			assert.NotNil(t, metricLog.Values["count"])
   255  		case "server.response.error":
   256  			seenResponseError = true
   257  			assert.Equal(t, "meter", metricLog.MetricType, "server.response metric had incorrect type")
   258  
   259  			// blacklist is set to empty, so all keys should be non-nil
   260  			assert.NotNil(t, metricLog.Values["count"])
   261  			assert.NotNil(t, metricLog.Values["1m"])
   262  			assert.NotNil(t, metricLog.Values["5m"])
   263  			assert.NotNil(t, metricLog.Values["15m"])
   264  			assert.NotNil(t, metricLog.Values["mean"])
   265  		case "server.uptime":
   266  			seenUptime = true
   267  			assert.Equal(t, "gauge", metricLog.MetricType, "server.uptime metric had incorrect type")
   268  			assert.NotZero(t, metricLog.Values["value"])
   269  		default:
   270  			assert.Fail(t, "unexpected metric encountered: %s", metricLog.MetricName)
   271  		}
   272  	}
   273  	assert.True(t, seenMyCounter, "my-counter metric was not emitted")
   274  	assert.True(t, seenResponseTimer, "server.response metric was not emitted")
   275  	assert.True(t, seenRequestSize, "server.request.size metric was not emitted")
   276  	assert.True(t, seenResponseSize, "server.response.size metric was not emitted")
   277  	assert.True(t, seenResponseError, "server.response.error metric was not emitted")
   278  	assert.True(t, seenUptime, "server.uptime metric was not emitted")
   279  
   280  	select {
   281  	case err := <-serverErr:
   282  		require.NoError(t, err)
   283  	default:
   284  	}
   285  }
   286  
   287  // TestMetricTypeValueBlacklist tests that if a metric type value is blacklisted, all metric of that type does not
   288  // contain any of the blacklisted keys.
   289  func TestMetricTypeValueBlacklist(t *testing.T) {
   290  	logOutputBuffer := &bytes.Buffer{}
   291  	port, err := httpserver.AvailablePort()
   292  	require.NoError(t, err)
   293  
   294  	// ensure that registry used in this test is unique/does not have any past metrics registered on it
   295  	metrics.DefaultMetricsRegistry = metrics.NewRootMetricsRegistry()
   296  	server, serverErr, cleanup := createAndRunCustomTestServer(t, port, port, func(ctx context.Context, info witchcraft.InitInfo) (deferFn func(), rErr error) {
   297  		ctx = metrics.AddTags(ctx, metrics.MustNewTag("key", "val"))
   298  		metrics.FromContext(ctx).Counter("my-counter").Inc(13)
   299  		return nil, info.Router.Post("/error", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
   300  			rw.WriteHeader(500)
   301  		}))
   302  	}, logOutputBuffer, func(t *testing.T, initFn witchcraft.InitFunc, installCfg config.Install, logOutputBuffer io.Writer) *witchcraft.Server {
   303  		installCfg.MetricsEmitFrequency = 100 * time.Millisecond
   304  		return createTestServer(t, initFn, installCfg, logOutputBuffer).WithMetricTypeValuesBlacklist(map[string]map[string]struct{}{
   305  			"histogram": {"count": {}},
   306  		})
   307  	})
   308  	defer func() {
   309  		require.NoError(t, server.Close())
   310  	}()
   311  	defer cleanup()
   312  
   313  	// Make POST that will 404 to trigger request size and error rate metrics
   314  	_, err = testServerClient().Post(fmt.Sprintf("https://localhost:%d/%s/%s", port, basePath, "error"), "application/json", strings.NewReader("{}"))
   315  	require.NoError(t, err)
   316  
   317  	// Allow the metric emitter to do its thing.
   318  	time.Sleep(150 * time.Millisecond)
   319  
   320  	parts := strings.Split(logOutputBuffer.String(), "\n")
   321  	var metricLogs []logging.MetricLogV1
   322  	for _, curr := range parts {
   323  		if strings.Contains(curr, `"metric.1"`) {
   324  			var currLog logging.MetricLogV1
   325  			require.NoError(t, json.Unmarshal([]byte(curr), &currLog))
   326  			metricLogs = append(metricLogs, currLog)
   327  		}
   328  	}
   329  
   330  	var seenMyCounter, seenResponseTimer, seenResponseSize, seenRequestSize, seenResponseError, seenUptime bool
   331  	for _, metricLog := range metricLogs {
   332  		switch metricLog.MetricName {
   333  		case "my-counter":
   334  			seenMyCounter = true
   335  			assert.Equal(t, "counter", metricLog.MetricType, "my-counter metric had incorrect type")
   336  			assert.Equal(t, map[string]interface{}{"count": json.Number("13")}, metricLog.Values)
   337  			assert.Equal(t, map[string]string{"key": "val"}, metricLog.Tags)
   338  		case "server.response":
   339  			seenResponseTimer = true
   340  			assert.Equal(t, "timer", metricLog.MetricType, "server.response metric had incorrect type")
   341  			assert.NotNil(t, metricLog.Values["count"])
   342  			assert.NotNil(t, metricLog.Values["mean"])
   343  			assert.NotNil(t, metricLog.Values["max"])
   344  			assert.NotNil(t, metricLog.Values["min"])
   345  		case "server.request.size":
   346  			seenRequestSize = true
   347  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   348  			// there should be no value for "count" because it is blacklisted for the histogram type
   349  			assert.Nil(t, metricLog.Values["count"])
   350  		case "server.response.size":
   351  			seenResponseSize = true
   352  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   353  			// there should be no value for "count" because it is blacklisted for the histogram type
   354  			assert.Nil(t, metricLog.Values["count"])
   355  		case "server.response.error":
   356  			seenResponseError = true
   357  			assert.Equal(t, "meter", metricLog.MetricType, "server.response metric had incorrect type")
   358  			assert.NotNil(t, metricLog.Values["count"])
   359  		case "server.uptime":
   360  			seenUptime = true
   361  			assert.Equal(t, "gauge", metricLog.MetricType, "server.uptime metric had incorrect type")
   362  			assert.NotZero(t, metricLog.Values["value"])
   363  		default:
   364  			assert.Fail(t, "unexpected metric encountered: %s", metricLog.MetricName)
   365  		}
   366  	}
   367  	assert.True(t, seenMyCounter, "my-counter metric was not emitted")
   368  	assert.True(t, seenResponseTimer, "server.response metric was not emitted")
   369  	assert.True(t, seenRequestSize, "server.request.size metric was not emitted")
   370  	assert.True(t, seenResponseSize, "server.response.size metric was not emitted")
   371  	assert.True(t, seenResponseError, "server.response.error metric was not emitted")
   372  	assert.True(t, seenUptime, "server.uptime metric was not emitted")
   373  
   374  	select {
   375  	case err := <-serverErr:
   376  		require.NoError(t, err)
   377  	default:
   378  	}
   379  }
   380  
   381  // TestMetricsBlacklist verifies that blacklisted metrics are not emitted.
   382  func TestMetricsBlacklist(t *testing.T) {
   383  	logOutputBuffer := &bytes.Buffer{}
   384  	port, err := httpserver.AvailablePort()
   385  	require.NoError(t, err)
   386  	server, serverErr, cleanup := createAndRunCustomTestServer(t, port, port, func(ctx context.Context, info witchcraft.InitInfo) (deferFn func(), rErr error) {
   387  		ctx = metrics.AddTags(ctx, metrics.MustNewTag("key", "val"))
   388  		metrics.FromContext(ctx).Counter("my-counter").Inc(13)
   389  		return nil, info.Router.Post("/error", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
   390  			rw.WriteHeader(500)
   391  		}))
   392  	}, logOutputBuffer, func(t *testing.T, initFn witchcraft.InitFunc, installCfg config.Install, logOutputBuffer io.Writer) *witchcraft.Server {
   393  		installCfg.MetricsEmitFrequency = 100 * time.Millisecond
   394  		server := createTestServer(t, initFn, installCfg, logOutputBuffer)
   395  		server.WithMetricsBlacklist(map[string]struct{}{
   396  			"my-counter":          {},
   397  			"server.request.size": {},
   398  			"server.uptime":       {},
   399  		})
   400  		return server
   401  	})
   402  	defer func() {
   403  		require.NoError(t, server.Close())
   404  	}()
   405  	defer cleanup()
   406  
   407  	// Make POST that will 404 to trigger request size and error rate metrics
   408  	_, err = testServerClient().Post(fmt.Sprintf("https://localhost:%d/%s/%s", port, basePath, "error"), "application/json", strings.NewReader("{}"))
   409  	require.NoError(t, err)
   410  
   411  	// Allow the metric emitter to do its thing.
   412  	time.Sleep(150 * time.Millisecond)
   413  
   414  	parts := strings.Split(logOutputBuffer.String(), "\n")
   415  	var metricLogs []logging.MetricLogV1
   416  	for _, curr := range parts {
   417  		if strings.Contains(curr, `"metric.1"`) {
   418  			var currLog logging.MetricLogV1
   419  			require.NoError(t, json.Unmarshal([]byte(curr), &currLog))
   420  			metricLogs = append(metricLogs, currLog)
   421  		}
   422  	}
   423  
   424  	var seenMyCounter, seenResponseTimer, seenResponseSize, seenRequestSize, seenResponseError bool
   425  	for _, metricLog := range metricLogs {
   426  		switch metricLog.MetricName {
   427  		case "my-counter":
   428  			assert.Fail(t, "my-counter metric should not be emitted")
   429  		case "server.response":
   430  			seenResponseTimer = true
   431  			assert.Equal(t, "timer", metricLog.MetricType, "server.response metric had incorrect type")
   432  			assert.NotZero(t, metricLog.Values["count"])
   433  		case "server.request.size":
   434  			assert.Fail(t, "server.request.size metric should not be emitted")
   435  		case "server.response.size":
   436  			seenResponseSize = true
   437  			assert.Equal(t, "histogram", metricLog.MetricType, "server.response metric had incorrect type")
   438  			assert.NotZero(t, metricLog.Values["count"])
   439  		case "server.response.error":
   440  			seenResponseError = true
   441  			assert.Equal(t, "meter", metricLog.MetricType, "server.response metric had incorrect type")
   442  			assert.NotZero(t, metricLog.Values["count"])
   443  		default:
   444  			assert.Fail(t, "unexpected metric encountered: %s", metricLog.MetricName)
   445  		}
   446  	}
   447  	assert.False(t, seenMyCounter, "my-counter metric was emitted")
   448  	assert.False(t, seenRequestSize, "server.request.size metric was emitted")
   449  
   450  	assert.True(t, seenResponseTimer, "server.response metric was not emitted")
   451  	assert.True(t, seenResponseSize, "server.response.size metric was not emitted")
   452  	assert.True(t, seenResponseError, "server.response.error metric was not emitted")
   453  
   454  	select {
   455  	case err := <-serverErr:
   456  		require.NoError(t, err)
   457  	default:
   458  	}
   459  }