Skip to content

Commit

Permalink
Merge pull request #34 from rokett/gateway_metrics
Browse files Browse the repository at this point in the history
Added NetScaler Gateway metrics
  • Loading branch information
rokett authored Jan 24, 2020
2 parents 8b6c12f + 92fdfc2 commit 197c8bc
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 15 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [4.3.0] - 2020-01-24
### Added
- VPN Virtual Server (NetScaler Gateway) stats.

## [4.2.0] - 2019-12-31
### Changed
- Minimising the number of API requests needed to retrieve Service Group member stats by getting all service group members for a specific service group in one go. We still have to query for every single service group, but it cuts down the number of API requests by over 50% on the assumption that each service group has multiple members.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.PHONY: build

APP = Citrix-NetScaler-Exporter
VERSION = 4.2.0
VERSION = 4.3.0
BINARY-LINUX = ${APP}_${VERSION}_Linux_amd64

BUILD_VER = $(shell git rev-parse HEAD)
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ For each virtual server, the following metrics are retrieved.
| Current client connections | Gauge | None |
| Current server connections | Gauge | None |
## VPN Virtual Servers (NetScaler Gateway)
For each virtual server, the following metrics are retrieved.
| Metric | Metric Type | Unit |
| ---------------------------| ----------- | ------- |
| Name | N/A | None |
| Total requests | Counter | None |
| Total responses | Counter | None |
| Total request bytes | Counter | Bytes |
| Total response bytes | Counter | Bytes |
| State | Gauge | None |
## Services
For each service, the following metrics are retrieved.
Expand Down
20 changes: 20 additions & 0 deletions collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
level.Error(e.logger).Log("msg", err)
}

vpnVirtualServers, err := netscaler.GetVPNVirtualServerStats(nsClient, "")
if err != nil {
level.Error(e.logger).Log("msg", err)
}

fltModelID, _ := strconv.ParseFloat(nslicense.NSLicense.ModelID, 64)

fltTotRxMB, _ := strconv.ParseFloat(ns.NSStats.TotalReceivedMB, 64)
Expand Down Expand Up @@ -348,6 +353,21 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
e.collectCSVirtualServerCurrentMultipathSubflows(csVirtualServers)
e.csVirtualServersCurrentMultipathSubflows.Collect(ch)

e.collectVPNVirtualServerTotalRequests(vpnVirtualServers)
e.vpnVirtualServersTotalRequests.Collect(ch)

e.collectVPNVirtualServerTotalResponses(vpnVirtualServers)
e.vpnVirtualServersTotalResponses.Collect(ch)

e.collectVPNVirtualServerTotalRequestBytes(vpnVirtualServers)
e.vpnVirtualServersTotalRequestBytes.Collect(ch)

e.collectVPNVirtualServerTotalResponseBytes(vpnVirtualServers)
e.vpnVirtualServersTotalResponseBytes.Collect(ch)

e.collectVPNVirtualServerState(vpnVirtualServers)
e.vpnVirtualServersState.Collect(ch)

servicegroups, err := netscaler.GetServiceGroups(nsClient, "attrs=servicegroupname")
if err != nil {
level.Error(e.logger).Log("msg", err)
Expand Down
16 changes: 16 additions & 0 deletions collector/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ type Exporter struct {
csVirtualServersTotalVServerDownBackupHits *prometheus.CounterVec
csVirtualServersCurrentMultipathSessions *prometheus.GaugeVec
csVirtualServersCurrentMultipathSubflows *prometheus.GaugeVec
vpnVirtualServersTotalRequests *prometheus.CounterVec
vpnVirtualServersTotalResponses *prometheus.CounterVec
vpnVirtualServersTotalRequestBytes *prometheus.CounterVec
vpnVirtualServersTotalResponseBytes *prometheus.CounterVec
vpnVirtualServersState *prometheus.GaugeVec
username string
password string
url string
Expand Down Expand Up @@ -229,6 +234,11 @@ func NewExporter(url string, username string, password string, ignoreCert bool,
csVirtualServersTotalVServerDownBackupHits: csVirtualServersTotalVServerDownBackupHits,
csVirtualServersCurrentMultipathSessions: csVirtualServersCurrentMultipathSessions,
csVirtualServersCurrentMultipathSubflows: csVirtualServersCurrentMultipathSubflows,
vpnVirtualServersTotalRequests: vpnVirtualServersTotalRequests,
vpnVirtualServersTotalResponses: vpnVirtualServersTotalResponses,
vpnVirtualServersTotalRequestBytes: vpnVirtualServersTotalRequestBytes,
vpnVirtualServersTotalResponseBytes: vpnVirtualServersTotalResponseBytes,
vpnVirtualServersState: vpnVirtualServersState,
username: username,
password: password,
url: url,
Expand Down Expand Up @@ -345,4 +355,10 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
e.csVirtualServersTotalVServerDownBackupHits.Describe(ch)
e.csVirtualServersCurrentMultipathSessions.Describe(ch)
e.csVirtualServersCurrentMultipathSubflows.Describe(ch)

e.vpnVirtualServersTotalRequests.Describe(ch)
e.vpnVirtualServersTotalResponses.Describe(ch)
e.vpnVirtualServersTotalRequestBytes.Describe(ch)
e.vpnVirtualServersTotalResponseBytes.Describe(ch)
e.vpnVirtualServersState.Describe(ch)
}
114 changes: 114 additions & 0 deletions collector/vpn_virtual_servers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package collector

import (
"strconv"

"github.com/prometheus/client_golang/prometheus"
"github.com/rokett/citrix-netscaler-exporter/netscaler"
)

var (
vpnVirtualServersTotalRequests = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "vpn_virtual_servers_total_requests",
Help: "Total VPN virtual server requests",
},
[]string{
"ns_instance",
"vpn_virtual_server",
},
)

vpnVirtualServersTotalResponses = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "vpn_virtual_servers_total_responses",
Help: "Total VPN virtual server responses",
},
[]string{
"ns_instance",
"vpn_virtual_server",
},
)

vpnVirtualServersTotalRequestBytes = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "vpn_virtual_servers_total_request_bytes",
Help: "Total VPN virtual server request bytes",
},
[]string{
"ns_instance",
"vpn_virtual_server",
},
)
vpnVirtualServersTotalResponseBytes = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "vpn_virtual_servers_total_response_bytes",
Help: "Total VPN virtual server response bytes",
},
[]string{
"ns_instance",
"vpn_virtual_server",
},
)

vpnVirtualServersState = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "vpn_virtual_servers_state",
Help: "Current state of the VPN virtual server",
},
[]string{
"ns_instance",
"vpn_virtual_server",
},
)
)

func (e *Exporter) collectVPNVirtualServerTotalRequests(ns netscaler.NSAPIResponse) {
e.vpnVirtualServersTotalRequests.Reset()

for _, vs := range ns.VPNVirtualServerStats {
totalRequests, _ := strconv.ParseFloat(vs.TotalRequests, 64)
e.vpnVirtualServersTotalRequests.WithLabelValues(e.nsInstance, vs.Name).Set(totalRequests)
}
}

func (e *Exporter) collectVPNVirtualServerTotalResponses(ns netscaler.NSAPIResponse) {
e.vpnVirtualServersTotalResponses.Reset()

for _, vs := range ns.VPNVirtualServerStats {
totalResponses, _ := strconv.ParseFloat(vs.TotalResponses, 64)
e.vpnVirtualServersTotalResponses.WithLabelValues(e.nsInstance, vs.Name).Set(totalResponses)
}
}

func (e *Exporter) collectVPNVirtualServerTotalRequestBytes(ns netscaler.NSAPIResponse) {
e.vpnVirtualServersTotalRequestBytes.Reset()

for _, vs := range ns.VPNVirtualServerStats {
totalRequestBytes, _ := strconv.ParseFloat(vs.TotalRequestBytes, 64)
e.vpnVirtualServersTotalRequestBytes.WithLabelValues(e.nsInstance, vs.Name).Set(totalRequestBytes)
}
}

func (e *Exporter) collectVPNVirtualServerTotalResponseBytes(ns netscaler.NSAPIResponse) {
e.vpnVirtualServersTotalResponseBytes.Reset()

for _, vs := range ns.VPNVirtualServerStats {
totalResponseBytes, _ := strconv.ParseFloat(vs.TotalResponseBytes, 64)
e.vpnVirtualServersTotalResponseBytes.WithLabelValues(e.nsInstance, vs.Name).Set(totalResponseBytes)
}
}

func (e *Exporter) collectVPNVirtualServerState(ns netscaler.NSAPIResponse) {
e.vpnVirtualServersState.Reset()

for _, vs := range ns.VPNVirtualServerStats {
state := 0.0

if vs.State == "UP" {
state = 1.0
}

e.vpnVirtualServersState.WithLabelValues(e.nsInstance, vs.Name).Set(state)
}
}
2 changes: 1 addition & 1 deletion make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
SETLOCAL

set APP=Citrix-NetScaler-Exporter
set VERSION=4.2.0
set VERSION=4.3.0
set BINARY-WINDOWS-X64=%APP%_%VERSION%_Windows_amd64.exe
set BINARY-LINUX=%APP%_%VERSION%_Linux_amd64

Expand Down
34 changes: 34 additions & 0 deletions netscaler/get_vpn_virtual_server_stats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package netscaler

import (
"encoding/json"

"github.com/pkg/errors"
)

// VPNVirtualServerStats represents the data returned from the /stat/vpnvserver Nitro API endpoint
type VPNVirtualServerStats struct {
Name string `json:"name"`
TotalRequests string `json:"totalrequests"`
TotalResponses string `json:"totalresponses"`
TotalRequestBytes string `json:"totalrequestbytes"`
TotalResponseBytes string `json:"totalresponsebytes"`
State string `json:"state"`
}

// GetVPNVirtualServerStats queries the Nitro API for VPN virtual server stats
func GetVPNVirtualServerStats(c *NitroClient, querystring string) (NSAPIResponse, error) {
stats, err := c.GetStats("vpnvserver", querystring)
if err != nil {
return NSAPIResponse{}, err
}

var response = new(NSAPIResponse)

err = json.Unmarshal(stats, &response)
if err != nil {
return NSAPIResponse{}, errors.Wrap(err, "error unmarshalling response body")
}

return *response, nil
}
27 changes: 14 additions & 13 deletions netscaler/nsapiresponse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package netscaler

// NSAPIResponse represents the main portion of the Nitro API response
type NSAPIResponse struct {
Errorcode int64 `json:"errorcode"`
Message string `json:"message"`
Severity string `json:"severity"`
NSLicense NSLicense `json:"nslicense"`
NSStats NSStats `json:"ns"`
InterfaceStats []InterfaceStats `json:"Interface"`
VirtualServerStats []VirtualServerStats `json:"lbvserver"`
ServiceStats []ServiceStats `json:"service"`
ServiceGroups []ServiceGroups `json:"servicegroup"`
ServiceGroupMemberStats []ServiceGroupMemberStats `json:"servicegroupmember"`
GSLBServiceStats []GSLBServiceStats `json:"gslbservice"`
GSLBVirtualServerStats []GSLBVirtualServerStats `json:"gslbvserver"`
CSVirtualServerStats []CSVirtualServerStats `json:"csvserver"`
Errorcode int64 `json:"errorcode"`
Message string `json:"message"`
Severity string `json:"severity"`
NSLicense NSLicense `json:"nslicense"`
NSStats NSStats `json:"ns"`
InterfaceStats []InterfaceStats `json:"Interface"`
VirtualServerStats []VirtualServerStats `json:"lbvserver"`
ServiceStats []ServiceStats `json:"service"`
ServiceGroups []ServiceGroups `json:"servicegroup"`
ServiceGroupMemberStats []ServiceGroupMemberStats `json:"servicegroupmember"`
GSLBServiceStats []GSLBServiceStats `json:"gslbservice"`
GSLBVirtualServerStats []GSLBVirtualServerStats `json:"gslbvserver"`
CSVirtualServerStats []CSVirtualServerStats `json:"csvserver"`
VPNVirtualServerStats []VPNVirtualServerStats `json:"vpnvserver"`
}

0 comments on commit 197c8bc

Please sign in to comment.