2017-03-10 13:01:26 +00:00
/ *
Copyright 2017 The Kubernetes Authors .
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 .
* /
2018-07-07 17:46:18 +00:00
package collectors
2017-03-10 13:01:26 +00:00
import (
2019-01-21 14:29:36 +00:00
"log"
2018-06-14 00:55:07 +00:00
"regexp"
"strconv"
2017-03-10 13:01:26 +00:00
"github.com/prometheus/client_golang/prometheus"
2019-01-21 14:29:36 +00:00
"k8s.io/ingress-nginx/internal/nginx"
2020-08-08 23:31:02 +00:00
"k8s.io/klog/v2"
2017-03-10 13:01:26 +00:00
)
2018-06-14 00:55:07 +00:00
var (
ac = regexp . MustCompile ( ` Active connections: (\d+) ` )
sahr = regexp . MustCompile ( ` (\d+)\s(\d+)\s(\d+) ` )
reading = regexp . MustCompile ( ` Reading: (\d+) ` )
writing = regexp . MustCompile ( ` Writing: (\d+) ` )
waiting = regexp . MustCompile ( ` Waiting: (\d+) ` )
)
2017-03-10 13:01:26 +00:00
type (
nginxStatusCollector struct {
2018-07-07 17:46:18 +00:00
scrapeChan chan scrapeRequest
data * nginxStatusData
2017-03-12 15:27:05 +00:00
}
nginxStatusData struct {
2018-01-19 11:32:19 +00:00
connectionsTotal * prometheus . Desc
requestsTotal * prometheus . Desc
connections * prometheus . Desc
2017-03-10 13:01:26 +00:00
}
2018-06-14 00:55:07 +00:00
basicStatus struct {
// Active total number of active connections
Active int
// Accepted total number of accepted client connections
Accepted int
// Handled total number of handled connections. Generally, the parameter value is the same as accepts unless some resource limits have been reached (for example, the worker_connections limit).
Handled int
// Requests total number of client requests.
Requests int
// Reading current number of connections where nginx is reading the request header.
Reading int
// Writing current number of connections where nginx is writing the response back to the client.
Writing int
// Waiting current number of idle client connections waiting for a request.
Waiting int
}
)
2017-04-04 12:32:08 +00:00
2018-07-07 17:46:18 +00:00
// NGINXStatusCollector defines a status collector interface
type NGINXStatusCollector interface {
prometheus . Collector
Start ( )
Stop ( )
}
// NewNGINXStatus returns a new prometheus collector the default nginx status module
2019-01-21 14:29:36 +00:00
func NewNGINXStatus ( podName , namespace , ingressClass string ) ( NGINXStatusCollector , error ) {
2018-07-07 17:46:18 +00:00
2017-03-10 13:01:26 +00:00
p := nginxStatusCollector {
2019-01-21 14:29:36 +00:00
scrapeChan : make ( chan scrapeRequest ) ,
2018-07-07 17:46:18 +00:00
}
constLabels := prometheus . Labels {
"controller_namespace" : namespace ,
"controller_class" : ingressClass ,
"controller_pod" : podName ,
2017-03-12 15:27:05 +00:00
}
p . data = & nginxStatusData {
2018-01-19 11:32:19 +00:00
connectionsTotal : prometheus . NewDesc (
2018-07-07 17:46:18 +00:00
prometheus . BuildFQName ( PrometheusNamespace , subSystem , "connections_total" ) ,
2019-03-04 21:35:45 +00:00
"total number of connections with state {accepted, handled}" ,
2018-07-07 17:46:18 +00:00
[ ] string { "state" } , constLabels ) ,
2017-03-12 15:27:05 +00:00
2018-01-19 11:32:19 +00:00
requestsTotal : prometheus . NewDesc (
2018-07-07 17:46:18 +00:00
prometheus . BuildFQName ( PrometheusNamespace , subSystem , "requests_total" ) ,
2017-03-12 15:27:05 +00:00
"total number of client requests" ,
2018-07-07 17:46:18 +00:00
nil , constLabels ) ,
2017-03-12 15:27:05 +00:00
2018-01-19 11:32:19 +00:00
connections : prometheus . NewDesc (
2018-07-07 17:46:18 +00:00
prometheus . BuildFQName ( PrometheusNamespace , subSystem , "connections" ) ,
2019-03-04 21:35:45 +00:00
"current number of client connections with state {active, reading, writing, waiting}" ,
2018-07-07 17:46:18 +00:00
[ ] string { "state" } , constLabels ) ,
2017-03-10 13:01:26 +00:00
}
2018-07-07 17:46:18 +00:00
return p , nil
2017-03-10 13:01:26 +00:00
}
// Describe implements prometheus.Collector.
func ( p nginxStatusCollector ) Describe ( ch chan <- * prometheus . Desc ) {
2018-01-19 11:32:19 +00:00
ch <- p . data . connectionsTotal
ch <- p . data . requestsTotal
ch <- p . data . connections
2017-03-10 13:01:26 +00:00
}
// Collect implements prometheus.Collector.
func ( p nginxStatusCollector ) Collect ( ch chan <- prometheus . Metric ) {
req := scrapeRequest { results : ch , done : make ( chan struct { } ) }
p . scrapeChan <- req
<- req . done
}
2018-07-07 17:46:18 +00:00
func ( p nginxStatusCollector ) Start ( ) {
2017-03-10 13:01:26 +00:00
for req := range p . scrapeChan {
ch := req . results
p . scrape ( ch )
req . done <- struct { } { }
}
}
func ( p nginxStatusCollector ) Stop ( ) {
close ( p . scrapeChan )
}
2018-06-14 00:55:07 +00:00
func toInt ( data [ ] string , pos int ) int {
if len ( data ) == 0 {
return 0
}
if pos > len ( data ) {
return 0
}
if v , err := strconv . Atoi ( data [ pos ] ) ; err == nil {
return v
}
return 0
}
func parse ( data string ) * basicStatus {
acr := ac . FindStringSubmatch ( data )
sahrr := sahr . FindStringSubmatch ( data )
readingr := reading . FindStringSubmatch ( data )
writingr := writing . FindStringSubmatch ( data )
waitingr := waiting . FindStringSubmatch ( data )
return & basicStatus {
toInt ( acr , 1 ) ,
toInt ( sahrr , 1 ) ,
toInt ( sahrr , 2 ) ,
toInt ( sahrr , 3 ) ,
toInt ( readingr , 1 ) ,
toInt ( writingr , 1 ) ,
toInt ( waitingr , 1 ) ,
}
}
2017-09-14 19:35:52 +00:00
// nginxStatusCollector scrape the nginx status
2017-03-10 13:01:26 +00:00
func ( p nginxStatusCollector ) scrape ( ch chan <- prometheus . Metric ) {
2020-09-27 20:32:40 +00:00
klog . V ( 3 ) . InfoS ( "starting scraping socket" , "path" , nginx . StatusPath )
2019-01-21 14:29:36 +00:00
status , data , err := nginx . NewGetStatusRequest ( nginx . StatusPath )
2017-03-10 13:01:26 +00:00
if err != nil {
2019-01-21 14:29:36 +00:00
log . Printf ( "%v" , err )
2018-12-05 16:27:55 +00:00
klog . Warningf ( "unexpected error obtaining nginx status info: %v" , err )
2017-03-10 13:01:26 +00:00
return
}
2019-01-21 14:29:36 +00:00
if status < 200 || status >= 400 {
klog . Warningf ( "unexpected error obtaining nginx status info (status %v)" , status )
return
}
s := parse ( string ( data ) )
2018-01-19 11:32:19 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . connectionsTotal ,
2018-07-07 17:46:18 +00:00
prometheus . CounterValue , float64 ( s . Accepted ) , "accepted" )
2018-01-19 11:32:19 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . connectionsTotal ,
2018-07-07 17:46:18 +00:00
prometheus . CounterValue , float64 ( s . Handled ) , "handled" )
2018-01-19 11:32:19 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . requestsTotal ,
2018-07-07 17:46:18 +00:00
prometheus . CounterValue , float64 ( s . Requests ) )
2019-03-04 21:35:45 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . connections ,
prometheus . GaugeValue , float64 ( s . Active ) , "active" )
2018-01-19 11:32:19 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . connections ,
2018-07-07 17:46:18 +00:00
prometheus . GaugeValue , float64 ( s . Reading ) , "reading" )
2018-01-19 11:32:19 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . connections ,
2018-07-07 17:46:18 +00:00
prometheus . GaugeValue , float64 ( s . Writing ) , "writing" )
2018-01-19 11:32:19 +00:00
ch <- prometheus . MustNewConstMetric ( p . data . connections ,
2018-07-07 17:46:18 +00:00
prometheus . GaugeValue , float64 ( s . Waiting ) , "waiting" )
2017-03-10 13:01:26 +00:00
}