@@ -3,6 +3,7 @@ package cmd
33import (
44 "context"
55 "crypto/tls"
6+ "errors"
67 "fmt"
78 "log"
89 "net/http"
5455 globalConfigFile string
5556 conf * config.Config
5657 pluginRegistry * plugin.Registry
58+ metricsServer * http.Server
5759
5860 UsageReportURL = "localhost:59091"
5961
@@ -72,6 +74,7 @@ func StopGracefully(
7274 pluginTimeoutCtx context.Context ,
7375 sig os.Signal ,
7476 metricsMerger * metrics.Merger ,
77+ metricsServer * http.Server ,
7578 pluginRegistry * plugin.Registry ,
7679 logger zerolog.Logger ,
7780 servers map [string ]* network.Server ,
@@ -110,6 +113,16 @@ func StopGracefully(
110113 logger .Info ().Msg ("Stopped metrics merger" )
111114 span .AddEvent ("Stopped metrics merger" )
112115 }
116+ if metricsServer != nil {
117+ //nolint:contextcheck
118+ if err := metricsServer .Shutdown (context .Background ()); err != nil {
119+ logger .Error ().Err (err ).Msg ("Failed to stop metrics server" )
120+ span .RecordError (err )
121+ } else {
122+ logger .Info ().Msg ("Stopped metrics server" )
123+ span .AddEvent ("Stopped metrics server" )
124+ }
125+ }
113126 for name , server := range servers {
114127 logger .Info ().Str ("name" , name ).Msg ("Stopping server" )
115128 server .Shutdown () //nolint:contextcheck
@@ -352,7 +365,14 @@ var runCmd = &cobra.Command{
352365 span .RecordError (err )
353366 sentry .CaptureException (err )
354367 }
355- next .ServeHTTP (responseWriter , request )
368+ // The WriteHeader method intentionally does nothing, to prevent a bug
369+ // in the merging metrics that causes the headers to be written twice,
370+ // which results in an error: "http: superfluous response.WriteHeader call".
371+ next .ServeHTTP (
372+ & metrics.HeaderBypassResponseWriter {
373+ ResponseWriter : responseWriter ,
374+ },
375+ request )
356376 }
357377 return http .HandlerFunc (handler )
358378 }
@@ -371,6 +391,7 @@ var runCmd = &cobra.Command{
371391 if conf .Plugin .EnableMetricsMerger && metricsMerger != nil {
372392 handler = mergedMetricsHandler (handler )
373393 }
394+
374395 // Check if the metrics server is already running before registering the handler.
375396 if _ , err = http .Get (address ); err != nil { //nolint:gosec
376397 http .Handle (metricsConfig .Path , gziphandler .GzipHandler (handler ))
@@ -379,16 +400,21 @@ var runCmd = &cobra.Command{
379400 span .RecordError (err )
380401 }
381402
382- //nolint:gosec
383- if err = http .ListenAndServe (
384- metricsConfig .Address , nil ); err != nil {
403+ // Create a new metrics server.
404+ metricsServer = & http.Server {
405+ Addr : metricsConfig .Address ,
406+ Handler : handler ,
407+ ReadHeaderTimeout : metricsConfig .GetReadHeaderTimeout (),
408+ }
409+
410+ // Start the metrics server.
411+ if err = metricsServer .ListenAndServe (); ! errors .Is (err , http .ErrServerClosed ) {
385412 logger .Error ().Err (err ).Msg ("Failed to start metrics server" )
386413 span .RecordError (err )
387414 }
388415 }(conf .Global .Metrics [config .Default ], logger )
389416
390417 // This is a notification hook, so we don't care about the result.
391- // TODO: Use a context with a timeout
392418 if data , ok := conf .GlobalKoanf .Get ("loggers" ).(map [string ]interface {}); ok {
393419 _ , err = pluginRegistry .Run (
394420 pluginTimeoutCtx , data , v1 .HookName_HOOK_NAME_ON_NEW_LOGGER )
@@ -723,6 +749,7 @@ var runCmd = &cobra.Command{
723749 pluginTimeoutCtx ,
724750 sig ,
725751 metricsMerger ,
752+ metricsServer ,
726753 pluginRegistry ,
727754 logger ,
728755 servers ,
0 commit comments