diff --git a/go.mod b/go.mod index 6fe027f8..21cffd92 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/networkservicemesh/sdk v0.5.1-0.20240820090035-6fad31a9f0aa github.com/networkservicemesh/sdk-kernel v0.0.0-20240820090342-573b7f288d21 github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.17.0 github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2.0.20220630165224-c591ada0fb2b github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 @@ -52,7 +53,6 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/open-policy-agent/opa v0.44.0 // 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/networkservice/metrics/stats/client.go b/pkg/networkservice/metrics/stats/client.go index 6c82f7e4..2c6f2e66 100644 --- a/pkg/networkservice/metrics/stats/client.go +++ b/pkg/networkservice/metrics/stats/client.go @@ -44,6 +44,7 @@ type statsClient struct { // NewClient provides a NetworkServiceClient chain elements that retrieves vpp interface metrics. func NewClient(ctx context.Context, options ...Option) networkservice.NetworkServiceClient { + prometheusInitOnce.Do(registerMetrics) opts := &statsOptions{} for _, opt := range options { opt(opts) diff --git a/pkg/networkservice/metrics/stats/common.go b/pkg/networkservice/metrics/stats/common.go index 60d613d1..8266636c 100644 --- a/pkg/networkservice/metrics/stats/common.go +++ b/pkg/networkservice/metrics/stats/common.go @@ -32,11 +32,14 @@ import ( "github.com/networkservicemesh/api/pkg/api/networkservice" "github.com/networkservicemesh/sdk/pkg/tools/log" + "github.com/networkservicemesh/sdk/pkg/tools/prometheus" "github.com/pkg/errors" "github.com/networkservicemesh/sdk-vpp/pkg/tools/ifindex" ) +const serverPref string = "server_" + // Save retrieved vpp interface metrics in pathSegment func retrieveMetrics(ctx context.Context, statsConn *core.StatsConnection, segment *networkservice.PathSegment, isClient bool) { swIfIndex, ok := ifindex.Load(ctx, isClient) @@ -49,7 +52,7 @@ func retrieveMetrics(ctx context.Context, statsConn *core.StatsConnection, segme return } - addName := "server_" + addName := serverPref if isClient { addName = "client_" } @@ -67,6 +70,23 @@ func retrieveMetrics(ctx context.Context, statsConn *core.StatsConnection, segme segment.Metrics[addName+"rx_packets"] = strconv.FormatUint(iface.Rx.Packets, 10) segment.Metrics[addName+"tx_packets"] = strconv.FormatUint(iface.Tx.Packets, 10) segment.Metrics[addName+"drops"] = strconv.FormatUint(iface.Drops, 10) + + if prometheus.IsEnabled() { + if addName == serverPref { + ServerRxBytes.Set(float64(iface.Rx.Bytes)) + ServerTxBytes.Set(float64(iface.Tx.Bytes)) + ServerRxPackets.Set(float64(iface.Rx.Packets)) + ServerTxPackets.Set(float64(iface.Tx.Packets)) + ServerDrops.Set(float64(iface.Drops)) + } else { + ClientRxBytes.Set(float64(iface.Rx.Bytes)) + ClientTxBytes.Set(float64(iface.Tx.Bytes)) + ClientRxPackets.Set(float64(iface.Rx.Packets)) + ClientTxPackets.Set(float64(iface.Tx.Packets)) + ClientDrops.Set(float64(iface.Drops)) + } + } + break } } diff --git a/pkg/networkservice/metrics/stats/prometheus.go b/pkg/networkservice/metrics/stats/prometheus.go new file mode 100644 index 00000000..3c6df91a --- /dev/null +++ b/pkg/networkservice/metrics/stats/prometheus.go @@ -0,0 +1,114 @@ +// 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 stats + +import ( + "sync" + + prom "github.com/networkservicemesh/sdk/pkg/tools/prometheus" + "github.com/prometheus/client_golang/prometheus" +) + +var ( + prometheusInitOnce sync.Once + + // ClientRxBytes - Total received bytes by client + ClientRxBytes = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "client_rx_bytes_total", + Help: "Total received bytes by client", + }, + ) + // ClientTxBytes - Total transmitted bytes by client + ClientTxBytes = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "client_tx_bytes_total", + Help: "Total transmitted bytes by client", + }, + ) + // ClientRxPackets - Total received packets by client + ClientRxPackets = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "client_rx_packets_total", + Help: "Total received packets by client", + }, + ) + // ClientTxPackets - Total transmitted packets by client + ClientTxPackets = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "client_tx_packets_total", + Help: "Total transmitted packets by client", + }, + ) + // ClientDrops - Total drops by client + ClientDrops = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "client_drops_total", + Help: "Total drops by client", + }, + ) + // ServerRxBytes - Total received bytes by server + ServerRxBytes = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "server_rx_bytes_total", + Help: "Total received bytes by server", + }, + ) + // ServerTxBytes - Total transmitted bytes by server + ServerTxBytes = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "server_tx_bytes_total", + Help: "Total transmitted bytes by server", + }, + ) + // ServerRxPackets - Total received packets by server + ServerRxPackets = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "server_rx_packets_total", + Help: "Total received packets by server", + }, + ) + // ServerTxPackets - Total transmitted packets by server + ServerTxPackets = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "server_tx_packets_total", + Help: "Total transmitted packets by server", + }, + ) + // ServerDrops - Total drops by server + ServerDrops = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "server_drops_total", + Help: "Total drops by server", + }, + ) +) + +func registerMetrics() { + if prom.IsEnabled() { + prometheus.MustRegister(ClientRxBytes) + prometheus.MustRegister(ClientTxBytes) + prometheus.MustRegister(ClientRxPackets) + prometheus.MustRegister(ClientTxPackets) + prometheus.MustRegister(ClientDrops) + prometheus.MustRegister(ServerRxBytes) + prometheus.MustRegister(ServerTxBytes) + prometheus.MustRegister(ServerRxPackets) + prometheus.MustRegister(ServerTxPackets) + prometheus.MustRegister(ServerDrops) + } +} diff --git a/pkg/networkservice/metrics/stats/server.go b/pkg/networkservice/metrics/stats/server.go index 24209b5e..6fc65084 100644 --- a/pkg/networkservice/metrics/stats/server.go +++ b/pkg/networkservice/metrics/stats/server.go @@ -42,6 +42,7 @@ type statsServer struct { // NewServer provides a NetworkServiceServer chain elements that retrieves vpp interface statistics. func NewServer(ctx context.Context, options ...Option) networkservice.NetworkServiceServer { + prometheusInitOnce.Do(registerMetrics) opts := &statsOptions{} for _, opt := range options { opt(opts)