Skip to content

Commit

Permalink
Add an option to expose Prometheus metrics via http/s server (#1653)
Browse files Browse the repository at this point in the history
Signed-off-by: Botond Szirtes <botond.szirtes@est.tech>
  • Loading branch information
bszirtes authored and denis-tingaikin committed Sep 17, 2024
1 parent 6c458ac commit b9a63dc
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/networkservicemesh/api v1.13.2
github.com/open-policy-agent/opa v0.44.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.17.0
github.com/r3labs/diff v1.1.0
github.com/sirupsen/logrus v1.9.0
github.com/spiffe/go-spiffe/v2 v2.1.7
Expand Down Expand Up @@ -85,7 +86,6 @@ require (
github.com/nats-io/nuid v1.0.1 // indirect
github.com/openzipkin/zipkin-go v0.4.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
Expand Down
35 changes: 35 additions & 0 deletions pkg/tools/prometheus/prometheus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2024 Nordix Foundation.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package prometheus provides a set of utilities for assisting with Prometheus data
package prometheus

import (
"os"
"strconv"
)

const (
prometheusEnv = "PROMETHEUS"
)

// IsEnabled returns true if prometheus is enabled
func IsEnabled() bool {
if v, err := strconv.ParseBool(os.Getenv(prometheusEnv)); err == nil {
return v
}
return false
}
109 changes: 109 additions & 0 deletions pkg/tools/prometheus/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) 2024 Nordix Foundation.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package prometheus provides a set of utilities for assisting with Prometheus data
package prometheus

import (
"context"
"crypto/tls"
"net/http"
"time"

"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
"github.com/spiffe/go-spiffe/v2/workloadapi"

"github.com/networkservicemesh/sdk/pkg/tools/log"
)

// ListenAndServe gathers the certificate and initiates the server to begin handling incoming requests
func ListenAndServe(ctx context.Context, listenOn string, headerTimeout time.Duration, cancel context.CancelFunc) {
metricsServer := server{
ListenOn: listenOn,
HeaderTimeout: headerTimeout,
}

tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
}
source, err := workloadapi.NewX509Source(ctx)
if err != nil {
log.FromContext(ctx).Fatalf("error getting x509 source: %v", err.Error())
}
tlsConfig.GetCertificate = tlsconfig.GetCertificate(source)
metricsServer.TLSConfig = tlsConfig

select {
case <-ctx.Done():
err = source.Close()
log.FromContext(ctx).Errorf("unable to close x509 source: %v", err.Error())
default:
}

go func() {
err := metricsServer.start(ctx)
if err != nil {
log.FromContext(ctx).Error(err.Error())
cancel()
}
}()
}

type server struct {
TLSConfig *tls.Config
ListenOn string
HeaderTimeout time.Duration
}

func (s *server) start(ctx context.Context) error {
log.FromContext(ctx).Info("Start metrics server on ", s.ListenOn)

server := &http.Server{
Addr: s.ListenOn,
TLSConfig: s.TLSConfig,
ReadHeaderTimeout: s.HeaderTimeout,
}

http.Handle("/metrics", promhttp.Handler())

serverCtx, cancel := context.WithCancel(ctx)
var ListenAndServeErr error

go func() {
ListenAndServeErr = server.ListenAndServeTLS("", "")
if ListenAndServeErr != nil {
cancel()
}
}()

<-serverCtx.Done()

if ListenAndServeErr != nil {
return errors.Errorf("failed to ListenAndServe on metrics server: %s", ListenAndServeErr)
}

shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 1*time.Second)
defer shutdownCancel()

err := server.Shutdown(shutdownCtx)
if err != nil {
return errors.Errorf("failed to shutdown metrics server: %s", err)
}

return nil
}

0 comments on commit b9a63dc

Please sign in to comment.