From 33e83108690d3a1c1262fe755774632855009702 Mon Sep 17 00:00:00 2001 From: Botond Szirtes Date: Mon, 29 Jul 2024 13:37:55 +0200 Subject: [PATCH] Add an option to expose Prometheus metrics via http/s server Signed-off-by: Botond Szirtes --- go.mod | 2 +- pkg/tools/opentelemetry/opentelemetry.go | 13 +++- pkg/tools/opentelemetry/server.go | 81 ++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 pkg/tools/opentelemetry/server.go diff --git a/go.mod b/go.mod index 893943358..e16b32f94 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/networkservicemesh/api v1.13.1-0.20240424210452-d0df98851760 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 @@ -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 diff --git a/pkg/tools/opentelemetry/opentelemetry.go b/pkg/tools/opentelemetry/opentelemetry.go index aa8b75cca..abf4abddc 100644 --- a/pkg/tools/opentelemetry/opentelemetry.go +++ b/pkg/tools/opentelemetry/opentelemetry.go @@ -2,6 +2,8 @@ // // Copyright (c) 2023 Cisco and/or its affiliates. // +// Copyright (c) 2024 Nordix Foundation. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,7 +38,8 @@ import ( ) const ( - telemetryEnv = "TELEMETRY" + telemetryEnv = "TELEMETRY" + prometheusEnv = "PROMETHEUS" ) // IsEnabled returns true if opentelemetry enabled @@ -47,6 +50,14 @@ func IsEnabled() bool { return false } +// IsPrometheusEnabled returns true if prometheus enabled +func IsPrometheusEnabled() bool { + if v, err := strconv.ParseBool(os.Getenv(prometheusEnv)); err == nil { + return v + } + return false +} + type opentelemetry struct { io.Closer diff --git a/pkg/tools/opentelemetry/server.go b/pkg/tools/opentelemetry/server.go new file mode 100644 index 000000000..e28d1cf1e --- /dev/null +++ b/pkg/tools/opentelemetry/server.go @@ -0,0 +1,81 @@ +// 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 opentelemetry provides a set of utilities for assisting with telemetry data +package opentelemetry + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus/promhttp" + + "github.com/networkservicemesh/sdk/pkg/tools/log" +) + +// Server is a server type for handling requests +type Server struct { + IP string + TLSCertFile string + TLSKeyFile string + Port int + HeaderTimeout time.Duration +} + +// Start initiates the server to begin handling incoming requests +func (s *Server) Start(ctx context.Context) error { + log.FromContext(ctx).Info("Start metrics server", "ip", s.IP, "port", s.Port) + + server := &http.Server{ + Addr: fmt.Sprintf("%s:%d", s.IP, s.Port), + ReadHeaderTimeout: s.HeaderTimeout, + } + + http.Handle("/metrics", promhttp.Handler()) + + serverCtx, cancel := context.WithCancel(ctx) + var ListenAndServeErr error + + go func() { + if s.TLSCertFile != "" && s.TLSKeyFile != "" { + ListenAndServeErr = server.ListenAndServeTLS(s.TLSCertFile, s.TLSKeyFile) + } else { + ListenAndServeErr = server.ListenAndServe() + } + 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 +}