Skip to content

Commit 7e642a4

Browse files
fihuerarno
authored andcommitted
managerd: Exposing metrics as a prometheus endpoint
1 parent 0f02832 commit 7e642a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+27189
-4
lines changed

Diff for: Gopkg.lock

+55-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Gopkg.toml

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ ignored = [
4242
name = "github.com/op/go-logging"
4343
version = "1.0.0"
4444

45+
[[constraint]]
46+
name = "github.com/prometheus/client_golang"
47+
version = "~0.9.0-pre1"
48+
4549
[[constraint]]
4650
name = "gopkg.in/yaml.v2"
4751
branch = "v2"

Diff for: doc/sshproxy-managerd.yaml.txt

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ The following keys can be defined:
3232
a string specifying the listening address. The format is '[host]:port'
3333
and the default is '127.0.0.1:55555'.
3434

35+
*promlisten*::
36+
a string specifying the listening address of the prometheus exporter.
37+
The format is '[host]:port' and the default is ':55556'.
38+
3539
*log*::
3640
a string which can be:
3741
- empty ('""') to display the logs on the standard output. It is the
@@ -92,6 +96,8 @@ debug: false
9296

9397
listen: 127.0.0.1:55555
9498

99+
promlisten: :55556
100+
95101
log: syslog
96102

97103
check_interval: 10m

Diff for: sshproxy-managerd/sshproxy-managerd.go

+105-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"fmt"
1818
"io/ioutil"
1919
"net"
20+
"net/http"
2021
"os"
2122
"os/signal"
2223
"regexp"
@@ -28,14 +29,17 @@ import (
2829
"github.com/cea-hpc/sshproxy/utils"
2930

3031
"github.com/op/go-logging"
32+
"github.com/prometheus/client_golang/prometheus"
33+
"github.com/prometheus/client_golang/prometheus/promhttp"
3134
"gopkg.in/yaml.v2"
3235
)
3336

3437
var (
3538
// 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"
3943
)
4044

4145
var (
@@ -56,11 +60,54 @@ var (
5660
// map of proxied connections (keys are user@host)
5761
proxiedConnections = make(map[string]*proxiedConn)
5862
)
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+
)
59105

60106
// Configuration
61107
type managerdConfig struct {
62108
Debug bool // Debug mode
63109
Listen string // Listen address [host]:port
110+
PromListen string // Prometheus Metrics Listen address [host]:port
64111
Log string // Where to log: empty is for stdout, "syslog" or a file
65112
CheckInterval utils.Duration `yaml:"check_interval"` // Minimum interval between host checks
66113
RouteSelect string `yaml:"route_select"` // Algorithm used to select a destination
@@ -115,6 +162,10 @@ func loadConfig(filename string) error {
115162
config.RouteSelect = route.DefaultAlgorithm
116163
}
117164

165+
if config.PromListen == "" {
166+
config.PromListen = defaultPromListenAddr
167+
}
168+
118169
return nil
119170
}
120171

@@ -185,6 +236,11 @@ func (hc *hostChecker) DoCheck(hostport string) State {
185236
state = Up
186237
}
187238
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+
}
188244
return state
189245
}
190246

@@ -368,6 +424,7 @@ func connectHandler(args []string) (string, error) {
368424
}
369425

370426
log.Info("new connection for %s: %s", key, dst)
427+
promInstUserConnection.WithLabelValues(user, dst).Inc()
371428
return fmt.Sprintf("+%s", dst), nil
372429
}
373430

@@ -386,6 +443,7 @@ func disableHandler(args []string) (string, error) {
386443

387444
managerHostChecker.Update(hostport, Disabled, time.Now())
388445

446+
promServers.WithLabelValues(hostport).Set(0)
389447
return "+OK", nil
390448
}
391449

@@ -415,6 +473,7 @@ func disconnectHandler(args []string) (string, error) {
415473
delete(proxiedConnections, key)
416474
}
417475

476+
promInstUserConnection.WithLabelValues(user, pc.Dest).Set(float64(pc.N))
418477
return "+OK", nil
419478
}
420479

@@ -509,6 +568,7 @@ type request struct {
509568
// It either writes a response in the request.response channel or an error in
510569
// the request.errc channel.
511570
func handle(r *request) {
571+
start := time.Now()
512572
fields := strings.Fields(r.request)
513573
if len(fields) == 0 {
514574
r.errc <- errors.New("empty request")
@@ -531,6 +591,8 @@ func handle(r *request) {
531591

532592
r.response <- response
533593
close(r.response)
594+
elapsed := time.Since(start)
595+
promManagerdLatency.Observe(float64(elapsed / time.Microsecond))
534596
}
535597

536598
// serve processes requests written in the queue channel and quits when the
@@ -676,6 +738,46 @@ func main() {
676738
ctx, cancel := context.WithCancel(context.Background())
677739
defer cancel()
678740

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+
679781
go serve(ctx, queue)
680782

681783
for {

Diff for: vendor/github.com/beorn7/perks/LICENSE

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)