diff --git a/daemon.go b/daemon.go index 4b29257..97e9854 100644 --- a/daemon.go +++ b/daemon.go @@ -28,6 +28,8 @@ import ( "strings" "sync" "time" + + "github.com/prometheus/client_golang/prometheus" ) const ( @@ -60,15 +62,20 @@ func GetRoom(name string) (r *Room, found bool) { return r, found } -func SendLusers(client *Client) { - lusers := 0 +func GetNumberOfRegisteredUsers(client *Client) (nusers float64){ + nusers = 0 clientsM.RLock() for client := range clients { if client.registered { - lusers++ + nusers++ } } clientsM.RUnlock() + return nusers +} + +func SendLusers(client *Client) { + lusers := GetNumberOfRegisteredUsers(client) client.ReplyNicknamed("251", fmt.Sprintf("There are %d users and 0 invisible on 1 servers", lusers)) } @@ -268,6 +275,8 @@ func ClientRegister(client *Client, cmd string, cols []string) { } } client.registered = true + clients_irc_total.Inc() + clients_connected.Set(GetNumberOfRegisteredUsers(client)) client.ReplyNicknamed("001", "Hi, welcome to IRC") client.ReplyNicknamed("002", "Your host is "+*hostname+", running goircd "+version) client.ReplyNicknamed("003", "This server was created sometime") @@ -338,17 +347,22 @@ func HandlerJoin(client *Client, cmd string) { Denied: client.ReplyNicknamed("475", room, "Cannot join channel (+k) - bad key") Joined: + clients_irc_rooms_total.With(prometheus.Labels{"room":"all"}).Inc() + clients_irc_rooms_total.With(prometheus.Labels{"room":room}).Inc() } } func Processor(events chan ClientEvent, finished chan struct{}) { var now time.Time + go func() { for { time.Sleep(10 * time.Second) events <- ClientEvent{eventType: EventTick} } }() + + for event := range events { now = time.Now() client := event.client @@ -618,6 +632,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) { default: client.ReplyNicknamed("421", cmd, "Unknown command") } + clients_connected.Set(GetNumberOfRegisteredUsers(client)) } } } diff --git a/goircd.go b/goircd.go index fa32bb1..d827d0c 100644 --- a/goircd.go +++ b/goircd.go @@ -24,12 +24,15 @@ import ( "io/ioutil" "log" "net" + "net/http" "path" "path/filepath" "strings" "time" proxyproto "github.com/Freeaqingme/go-proxyproto" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" ) const ( @@ -47,7 +50,37 @@ var ( tlsBind = flag.String("tlsbind", "", "TLS address to bind to") tlsPEM = flag.String("tlspem", "", "Path to TLS certificat+key PEM file") proxyTimeout = flag.Uint("proxytimeout", PROXY_TIMEOUT, "Timeout when using proxy protocol") + metrics = flag.Bool("metrics", false, "Enable metrics export") verbose = flag.Bool("v", false, "Enable verbose logging.") + + clients_tls_total = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "clients_tls_connected_total", + Help: "Number of connected clients during the lifetime of the server.", + }, + ) + + clients_irc_total = prometheus.NewCounter( + prometheus.CounterOpts{ + Name: "clients_irc_connected_total", + Help: "Number of connected irc clients during the lifetime of the server.", + }, + ) + + clients_irc_rooms_total = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "clients_irc_rooms_connected_total", + Help: "Number of clients joined to rooms during the lifetime of the server.", + }, + []string{"room"}, + ) + + clients_connected = prometheus.NewGauge( + prometheus.GaugeOpts{ + Name: "clients_connected", + Help: "Number of connected clients.", + }, + ) ) func listenerLoop(sock net.Listener, events chan ClientEvent) { @@ -58,6 +91,7 @@ func listenerLoop(sock net.Listener, events chan ClientEvent) { continue } client := NewClient(conn) + clients_tls_total.Inc() go client.Processor(events) } } @@ -149,9 +183,25 @@ func Run() { go listenerLoop(listenerTLS, events) } + + // Create endpoint for prometheus metrics export + if *metrics { + go prom_export() + } + Processor(events, make(chan struct{})) } +func prom_export() { + prometheus.MustRegister(clients_tls_total) + prometheus.MustRegister(clients_irc_total) + prometheus.MustRegister(clients_irc_rooms_total) + prometheus.MustRegister(clients_connected) + + http.Handle("/metrics", promhttp.Handler()) + log.Fatal(http.ListenAndServe(":8080", nil)) +} + func main() { flag.Parse() Run()