@@ -17,6 +17,7 @@ import (
17
17
"fmt"
18
18
"io/ioutil"
19
19
"net"
20
+ "net/http"
20
21
"os"
21
22
"os/signal"
22
23
"regexp"
@@ -28,14 +29,17 @@ import (
28
29
"github.com/cea-hpc/sshproxy/utils"
29
30
30
31
"github.com/op/go-logging"
32
+ "github.com/prometheus/client_golang/prometheus"
33
+ "github.com/prometheus/client_golang/prometheus/promhttp"
31
34
"gopkg.in/yaml.v2"
32
35
)
33
36
34
37
var (
35
38
// SshproxyVersion is set in the Makefile.
36
- SshproxyVersion = "0.0.0+notproperlybuilt"
37
- defaultConfig = "/etc/sshproxy/sshproxy-managerd.yaml"
38
- defaultListenAddr = "127.0.0.1:55555"
39
+ SshproxyVersion = "0.0.0+notproperlybuilt"
40
+ defaultConfig = "/etc/sshproxy/sshproxy-managerd.yaml"
41
+ defaultListenAddr = "127.0.0.1:55555"
42
+ defaultPromListenAddr = ":55556"
39
43
)
40
44
41
45
var (
@@ -56,11 +60,54 @@ var (
56
60
// map of proxied connections (keys are user@host)
57
61
proxiedConnections = make (map [string ]* proxiedConn )
58
62
)
63
+ var (
64
+ promUserStats = prometheus .NewSummaryVec (
65
+ prometheus.SummaryOpts {
66
+ Name : "sshproxy_user_connections_summary" ,
67
+ Help : "SSH Connection distribution" ,
68
+ Objectives : map [float64 ]float64 {0.5 : 0.05 , 0.9 : 0.01 , 0.99 : 0.001 },
69
+ },
70
+ []string {"user" , "server" },
71
+ )
72
+
73
+ promServerStats = prometheus .NewSummaryVec (
74
+ prometheus.SummaryOpts {
75
+ Name : "sshproxy_server_connections_summary" ,
76
+ Help : "SSH Connection distribution" ,
77
+ Objectives : map [float64 ]float64 {0.5 : 0.05 , 0.9 : 0.01 , 0.99 : 0.001 },
78
+ },
79
+ []string {"server" },
80
+ )
81
+
82
+ promInstUserConnection = prometheus .NewGaugeVec (
83
+ prometheus.GaugeOpts {
84
+ Name : "sshproxy_user_connections" ,
85
+ Help : "Current number of Proxied connections" ,
86
+ },
87
+ []string {"user" , "server" },
88
+ )
89
+
90
+ promServers = prometheus .NewGaugeVec (
91
+ prometheus.GaugeOpts {
92
+ Name : "sshproxy_server_up" ,
93
+ Help : "Is this server Up ?" ,
94
+ },
95
+ []string {"server" },
96
+ )
97
+
98
+ promManagerdLatency = prometheus .NewSummary (
99
+ prometheus.SummaryOpts {
100
+ Name : "sshproxy_managerd_latency" ,
101
+ Help : "sshproxy-managerd request handling statistics in microseconds" ,
102
+ },
103
+ )
104
+ )
59
105
60
106
// Configuration
61
107
type managerdConfig struct {
62
108
Debug bool // Debug mode
63
109
Listen string // Listen address [host]:port
110
+ PromListen string // Prometheus Metrics Listen address [host]:port
64
111
Log string // Where to log: empty is for stdout, "syslog" or a file
65
112
CheckInterval utils.Duration `yaml:"check_interval"` // Minimum interval between host checks
66
113
RouteSelect string `yaml:"route_select"` // Algorithm used to select a destination
@@ -115,6 +162,10 @@ func loadConfig(filename string) error {
115
162
config .RouteSelect = route .DefaultAlgorithm
116
163
}
117
164
165
+ if config .PromListen == "" {
166
+ config .PromListen = defaultPromListenAddr
167
+ }
168
+
118
169
return nil
119
170
}
120
171
@@ -185,6 +236,11 @@ func (hc *hostChecker) DoCheck(hostport string) State {
185
236
state = Up
186
237
}
187
238
hc .Update (hostport , state , time .Now ())
239
+ if state == Up {
240
+ promServers .WithLabelValues (hostport ).Set (1 )
241
+ } else {
242
+ promServers .WithLabelValues (hostport ).Set (0 )
243
+ }
188
244
return state
189
245
}
190
246
@@ -368,6 +424,7 @@ func connectHandler(args []string) (string, error) {
368
424
}
369
425
370
426
log .Info ("new connection for %s: %s" , key , dst )
427
+ promInstUserConnection .WithLabelValues (user , dst ).Inc ()
371
428
return fmt .Sprintf ("+%s" , dst ), nil
372
429
}
373
430
@@ -386,6 +443,7 @@ func disableHandler(args []string) (string, error) {
386
443
387
444
managerHostChecker .Update (hostport , Disabled , time .Now ())
388
445
446
+ promServers .WithLabelValues (hostport ).Set (0 )
389
447
return "+OK" , nil
390
448
}
391
449
@@ -415,6 +473,7 @@ func disconnectHandler(args []string) (string, error) {
415
473
delete (proxiedConnections , key )
416
474
}
417
475
476
+ promInstUserConnection .WithLabelValues (user , pc .Dest ).Set (float64 (pc .N ))
418
477
return "+OK" , nil
419
478
}
420
479
@@ -509,6 +568,7 @@ type request struct {
509
568
// It either writes a response in the request.response channel or an error in
510
569
// the request.errc channel.
511
570
func handle (r * request ) {
571
+ start := time .Now ()
512
572
fields := strings .Fields (r .request )
513
573
if len (fields ) == 0 {
514
574
r .errc <- errors .New ("empty request" )
@@ -531,6 +591,8 @@ func handle(r *request) {
531
591
532
592
r .response <- response
533
593
close (r .response )
594
+ elapsed := time .Since (start )
595
+ promManagerdLatency .Observe (float64 (elapsed / time .Microsecond ))
534
596
}
535
597
536
598
// serve processes requests written in the queue channel and quits when the
@@ -676,6 +738,46 @@ func main() {
676
738
ctx , cancel := context .WithCancel (context .Background ())
677
739
defer cancel ()
678
740
741
+ prometheus .MustRegister (promUserStats )
742
+ prometheus .MustRegister (promServerStats )
743
+ prometheus .MustRegister (promInstUserConnection )
744
+ prometheus .MustRegister (promServers )
745
+ prometheus .MustRegister (promManagerdLatency )
746
+
747
+ go func () {
748
+ var UserStats map [string ]map [string ]uint64
749
+ var ServerStats map [string ]uint64
750
+ var user string
751
+ for {
752
+ UserStats = make (map [string ]map [string ]uint64 )
753
+ ServerStats = make (map [string ]uint64 )
754
+ for k , v := range proxiedConnections {
755
+ user , err = getUserFromKey (k )
756
+ if err == nil {
757
+ if _ , ok := UserStats [user ]; ! ok {
758
+ UserStats [user ] = make (map [string ]uint64 )
759
+ }
760
+ UserStats [user ][v.Dest ] = uint64 (v .N )
761
+ ServerStats [v .Dest ] += uint64 (v .N )
762
+ } else {
763
+ continue
764
+ }
765
+ }
766
+ for observed_user , observed_servers := range UserStats {
767
+ for observed_server , nb_connections := range observed_servers {
768
+ promUserStats .WithLabelValues (observed_user , observed_server ).Observe (float64 (nb_connections ))
769
+ }
770
+ }
771
+ for observed_server , nb_connections := range ServerStats {
772
+ promServerStats .WithLabelValues (observed_server ).Observe (float64 (nb_connections ))
773
+ }
774
+ time .Sleep (time .Second )
775
+ }
776
+ }()
777
+
778
+ http .Handle ("/metrics" , promhttp .Handler ())
779
+ go http .ListenAndServe (config .PromListen , nil )
780
+
679
781
go serve (ctx , queue )
680
782
681
783
for {
0 commit comments