diff --git a/app/multitenant/aws_collector.go b/app/multitenant/aws_collector.go index ab14816cb..769679550 100644 --- a/app/multitenant/aws_collector.go +++ b/app/multitenant/aws_collector.go @@ -76,7 +76,7 @@ var ( }, []string{"method", "status_code"}) ) -func init() { +func registerAWSCollectorMetrics() { prometheus.MustRegister(dynamoRequestDuration) prometheus.MustRegister(dynamoConsumedCapacity) prometheus.MustRegister(dynamoValueSize) @@ -86,6 +86,8 @@ func init() { prometheus.MustRegister(natsRequests) } +var registerAWSCollectorMetricsOnce sync.Once + // AWSCollector is a Collector which can also CreateTables type AWSCollector interface { app.Collector @@ -137,6 +139,7 @@ type watchKey struct { // NewAWSCollector the elastic reaper of souls // https://github.com/aws/aws-sdk-go/wiki/common-examples func NewAWSCollector(config AWSCollectorConfig) (AWSCollector, error) { + registerAWSCollectorMetricsOnce.Do(registerAWSCollectorMetrics) var nc *nats.Conn if config.NatsHost != "" { var err error diff --git a/app/multitenant/memcache_client.go b/app/multitenant/memcache_client.go index 5393c3141..a4443c342 100644 --- a/app/multitenant/memcache_client.go +++ b/app/multitenant/memcache_client.go @@ -39,12 +39,14 @@ var ( }, []string{"method", "status_code"}) ) -func init() { +func registerMemcacheClientMetrics() { prometheus.MustRegister(memcacheRequests) prometheus.MustRegister(memcacheHits) prometheus.MustRegister(memcacheRequestDuration) } +var registerMemcacheClientMetricsOnce sync.Once + // MemcacheClient is a memcache client that gets its server list from SRV // records, and periodically updates that ServerList. type MemcacheClient struct { @@ -72,6 +74,7 @@ type MemcacheConfig struct { // NewMemcacheClient creates a new MemcacheClient that gets its server list // from SRV and updates the server list on a regular basis. func NewMemcacheClient(config MemcacheConfig) *MemcacheClient { + registerMemcacheClientMetricsOnce.Do(registerMemcacheClientMetrics) var servers memcache.ServerList client := memcache.NewFromSelector(&servers) client.Timeout = config.Timeout diff --git a/app/multitenant/s3_client.go b/app/multitenant/s3_client.go index 586a28f9c..ef67c981f 100644 --- a/app/multitenant/s3_client.go +++ b/app/multitenant/s3_client.go @@ -2,6 +2,7 @@ package multitenant import ( "bytes" + "sync" "context" "github.com/aws/aws-sdk-go/aws" @@ -28,12 +29,15 @@ type S3Store struct { bucketName string } -func init() { +func registerS3ClientMetrics() { prometheus.MustRegister(s3RequestDuration) } +var registerS3ClientMetricsOnce sync.Once + // NewS3Client creates a new S3 client. func NewS3Client(config *aws.Config, bucketName string) S3Store { + registerS3ClientMetricsOnce.Do(registerS3ClientMetrics) return S3Store{ s3: s3.New(session.New(config)), bucketName: bucketName, diff --git a/app/multitenant/sqs_control_router.go b/app/multitenant/sqs_control_router.go index a9b17aead..fdfcd6f7b 100644 --- a/app/multitenant/sqs_control_router.go +++ b/app/multitenant/sqs_control_router.go @@ -30,10 +30,12 @@ var ( }, []string{"method", "status_code"}) ) -func init() { +func registerSQSMetrics() { prometheus.MustRegister(sqsRequestDuration) } +var registerSQSMetricsOnce sync.Once + // sqsControlRouter: // Creates a queue for every probe that connects to it, and a queue for // responses back to it. When it receives a request, posts it to the @@ -64,6 +66,7 @@ type sqsResponseMessage struct { // NewSQSControlRouter the harbinger of death func NewSQSControlRouter(config *aws.Config, userIDer UserIDer, prefix string, rpcTimeout time.Duration) app.ControlRouter { + registerSQSMetricsOnce.Do(registerSQSMetrics) result := &sqsControlRouter{ service: sqs.New(session.New(config)), responseQueueURL: nil, diff --git a/prog/app.go b/prog/app.go index 533f80eb7..27050e8ec 100644 --- a/prog/app.go +++ b/prog/app.go @@ -10,6 +10,7 @@ import ( "runtime" "strconv" "strings" + "sync" "time" "github.com/goji/httpauth" @@ -47,11 +48,13 @@ var ( }, []string{"method", "route", "status_code", "ws"}) ) -func init() { +func registerAppMetrics() { prometheus.MustRegister(requestDuration) billing.MustRegisterMetrics() } +var registerAppMetricsOnce sync.Once + // Router creates the mux for all the various app components. func router(collector app.Collector, controlRouter app.ControlRouter, pipeRouter app.PipeRouter, externalUI bool, capabilities map[string]bool, metricsGraphURL string) http.Handler { router := mux.NewRouter().SkipClean(true) @@ -209,6 +212,8 @@ func appMain(flags appFlags) { setLogFormatter(flags.logPrefix) runtime.SetBlockProfileRate(flags.blockProfileRate) + registerAppMetricsOnce.Do(registerAppMetrics) + traceCloser := tracing.NewFromEnv(fmt.Sprintf("scope-%s", flags.serviceName)) defer traceCloser.Close()