[VOL-5506] Enable grpc stats

Change-Id: I78fe2235a2df26855053aa91da6f0b2c4fccd5f0
Signed-off-by: Abhay Kumar <abhay.kumar@radisys.com>
diff --git a/VERSION b/VERSION
index 8ac28bf..c78c496 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.6.1
+4.6.2
diff --git a/cmd/openolt-adapter/main.go b/cmd/openolt-adapter/main.go
index af8b52b..4b56d02 100644
--- a/cmd/openolt-adapter/main.go
+++ b/cmd/openolt-adapter/main.go
@@ -21,12 +21,14 @@
 	"context"
 	"errors"
 	"fmt"
+	"net/http"
 	"os"
 	"os/signal"
 	"syscall"
 	"time"
 
 	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
 	codes "google.golang.org/grpc/codes"
 
 	conf "github.com/opencord/voltha-lib-go/v7/pkg/config"
@@ -538,6 +540,24 @@
 	defer cancel()
 
 	ad := newAdapter(cf)
+	http.Handle("/metrics", promhttp.Handler())
+	go func() {
+		logger.Infof(ctx, "Metrics available at %s/metrics", ad.config.PrometheusAddress)
+		// Create HTTP server with explicit timeouts to prevent slowloris attacks and resource exhaustion.
+		// Using http.ListenAndServe() directly doesn't allow setting timeouts, which is a security risk.
+		// The server uses http.DefaultServeMux (nil handler) which includes the /metrics endpoint registered above.
+		metricsServer := &http.Server{
+			Addr:              ad.config.PrometheusAddress,
+			Handler:           nil,
+			ReadHeaderTimeout: 10 * time.Second,
+			ReadTimeout:       30 * time.Second,
+			WriteTimeout:      30 * time.Second,
+			IdleTimeout:       120 * time.Second,
+		}
+		if err := metricsServer.ListenAndServe(); err != nil {
+			logger.Errorw(ctx, "failed to start metrics HTTP server: ", log.Fields{"error": err})
+		}
+	}()
 
 	p := &probe.Probe{}
 	go p.ListenAndServe(ctx, ad.config.ProbeAddress)
diff --git a/go.mod b/go.mod
index 334c2ad..aae02e1 100644
--- a/go.mod
+++ b/go.mod
@@ -7,8 +7,10 @@
 	github.com/gogo/protobuf v1.3.2
 	github.com/golang/protobuf v1.5.4
 	github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
+	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 	github.com/opencord/voltha-lib-go/v7 v7.7.1
 	github.com/opencord/voltha-protos/v5 v5.6.6
+	github.com/prometheus/client_golang v1.23.2
 	github.com/stretchr/testify v1.11.1
 	go.etcd.io/etcd/tests/v3 v3.6.5
 	google.golang.org/grpc v1.76.0
@@ -46,7 +48,6 @@
 	github.com/gorilla/websocket v1.4.2 // indirect
 	github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
 	github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
-	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
 	github.com/hashicorp/go-uuid v1.0.3 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -68,7 +69,6 @@
 	github.com/pierrec/lz4/v4 v4.1.22 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/prometheus/client_golang v1.23.2 // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
 	github.com/prometheus/common v0.66.1 // indirect
 	github.com/prometheus/procfs v0.16.1 // indirect
diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go
index ba0e564..d06607e 100644
--- a/internal/pkg/config/config.go
+++ b/internal/pkg/config/config.go
@@ -39,6 +39,7 @@
 	defaultEventtopic           = "voltha.events"
 	defaultOnunumber            = 1
 	defaultProbeAddress         = ":8080"
+	defaultPrometheusPort       = ":8081"
 	defaultLiveProbeInterval    = 60 * time.Second
 	defaultNotLiveProbeInterval = 5 * time.Second // Probe more frequently when not alive
 	// defaultHeartbeatCheckInterval is the time in seconds the adapter will keep checking the hardware for heartbeat.
@@ -78,6 +79,7 @@
 	EventTopic                         string
 	LogLevel                           string
 	ProbeAddress                       string
+	PrometheusAddress                  string
 	GrpcAddress                        string
 	CoreEndpoint                       string
 	TraceAgentAddress                  string
@@ -123,6 +125,7 @@
 		Banner:                             defaultBanner,
 		DisplayVersionOnly:                 defaultDisplayVersionOnly,
 		ProbeAddress:                       defaultProbeAddress,
+		PrometheusAddress:                  defaultPrometheusPort,
 		LiveProbeInterval:                  defaultLiveProbeInterval,
 		NotLiveProbeInterval:               defaultNotLiveProbeInterval,
 		HeartbeatCheckInterval:             defaultHeartbeatCheckInterval,
@@ -201,6 +204,11 @@
 		defaultProbeAddress,
 		"The address on which to listen to answer liveness and readiness probe queries over HTTP.")
 
+	flag.StringVar(&(so.PrometheusAddress),
+		"prometheus_address",
+		defaultPrometheusPort,
+		"Used for exposing the metrics to prometheus.")
+
 	flag.DurationVar(&(so.LiveProbeInterval),
 		"live_probe_interval",
 		defaultLiveProbeInterval,
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index a72c011..c85be74 100755
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -39,6 +39,7 @@
 	"github.com/gogo/protobuf/proto"
 	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
 	grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
+	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	"github.com/opencord/voltha-lib-go/v7/pkg/config"
 	"github.com/opencord/voltha-lib-go/v7/pkg/events/eventif"
 	flow_utils "github.com/opencord/voltha-lib-go/v7/pkg/flows"
@@ -1209,15 +1210,18 @@
 	}
 
 	logger.Debugw(ctx, "Dailing grpc", log.Fields{"device-id": dh.device.Id})
+	grpc_prometheus.EnableClientHandlingTimeHistogram()
 	// Use Interceptors to automatically inject and publish Open Tracing Spans by this GRPC client
 	dh.clientCon, err = grpc.Dial(dh.device.GetHostAndPort(),
 		grpc.WithInsecure(),
 		grpc.WithBlock(),
 		grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(
 			grpc_opentracing.StreamClientInterceptor(grpc_opentracing.WithTracer(log.ActiveTracerProxy{})),
+			grpc_prometheus.StreamClientInterceptor,
 		)),
 		grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(
 			grpc_opentracing.UnaryClientInterceptor(grpc_opentracing.WithTracer(log.ActiveTracerProxy{})),
+			grpc_prometheus.UnaryClientInterceptor,
 		)))
 
 	if err != nil {