diff --git a/.gitignore b/.gitignore index 56959ef..3ff9171 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ private go-discord-irc .vscode +config_dev.yml diff --git a/bridge/discord.go b/bridge/discord.go index 7d3494d..9b97b8a 100644 --- a/bridge/discord.go +++ b/bridge/discord.go @@ -407,7 +407,7 @@ func (d *discordBot) OnTypingStart(s *discordgo.Session, m *discordgo.TypingStar } func (d *discordBot) OnReady(s *discordgo.Session, m *discordgo.Ready) { - err := d.RequestGuildMembers(d.guildID, "", 0) + err := d.RequestGuildMembers(d.guildID, "", 0, true) if err != nil { log.Warningln(errors.Wrap(err, "could not request guild members").Error()) return diff --git a/bridge/irc_listener.go b/bridge/irc_listener.go index ae46e92..484b1d5 100644 --- a/bridge/irc_listener.go +++ b/bridge/irc_listener.go @@ -16,7 +16,7 @@ type ircListener struct { } func newIRCListener(dib *Bridge, webIRCPass string) *ircListener { - irccon := irc.IRC(dib.Config.IRCListenerName, "discord") + irccon := irc.IRC(dib.Config.IRCListenerName, "butlerx") listener := &ircListener{irccon, dib, nil} dib.SetupIRCConnection(irccon, "discord.", "fd75:f5f5:226f::") diff --git a/bridge/irc_manager.go b/bridge/irc_manager.go index b57890e..0474657 100644 --- a/bridge/irc_manager.go +++ b/bridge/irc_manager.go @@ -8,13 +8,22 @@ import ( "github.com/mozillazg/go-unidecode" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ircnick "github.com/qaisjp/go-discord-irc/irc/nick" irc "github.com/qaisjp/go-ircevent" log "github.com/sirupsen/logrus" ) -var indev = false +var ( + indev = false + usersConnected = promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "discord_irc", + Name: "users_total", + Help: "The total number of users connected from discord to irc", + }) +) // IRCManager should only be used from one thread. type IRCManager struct { @@ -34,6 +43,7 @@ func newIRCManager(bridge *Bridge) *IRCManager { // CloseConnection shuts down a particular connection and its channels. func (m *IRCManager) CloseConnection(i *ircConnection) { log.WithField("nick", i.nick).Println("Closing connection.") + usersConnected.Dec() // Destroy the cooldown timer if i.cooldownTimer != nil { i.cooldownTimer.Stop() @@ -144,7 +154,7 @@ func (m *IRCManager) HandleUser(user DiscordUser) { // DEV MODE: Only create a connection if it sounds like qaisjp or if we have 10 connections if indev { - if len(m.ircConnections) > 4 && !strings.Contains(user.Username, "qais") { + if len(m.ircConnections) > 4 && !strings.Contains(user.Username, "butlerx") { connectionsIgnored++ fmt.Println("Not letting", user.Username, "connect. We have", len(m.ircConnections), "connections. Ignored", connectionsIgnored, "connections.") return @@ -202,6 +212,8 @@ func (m *IRCManager) HandleUser(user DiscordUser) { fmt.Println("Incrementing total connections. It's now", len(m.ircConnections)) } + usersConnected.Inc() + err := con.innerCon.Connect(m.bridge.Config.IRCServer) if err != nil { log.WithField("error", err).Errorln("error opening irc connection") diff --git a/config.yml b/config.yml index 666bd4b..45153f0 100644 --- a/config.yml +++ b/config.yml @@ -25,3 +25,7 @@ no_tls: false debug: false webhook_prefix: "(auto-test)" # simple: true + +prometheus: + enabled: false # Disabled by default + # port: 2112 diff --git a/go.mod b/go.mod index 7d8b094..1842ed1 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,13 @@ module github.com/qaisjp/go-discord-irc go 1.12 require ( - github.com/bwmarrin/discordgo v0.20.2 + github.com/bwmarrin/discordgo v0.22.0 github.com/fsnotify/fsnotify v1.4.7 github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/go-multierror v1.0.0 github.com/mozillazg/go-unidecode v0.1.1 github.com/pkg/errors v0.8.1 + github.com/prometheus/client_golang v0.9.3 github.com/qaisjp/go-ircevent v0.0.0-20180911155239-e71f5fec2a8d github.com/sirupsen/logrus v1.4.2 github.com/spf13/viper v1.4.0 diff --git a/go.sum b/go.sum index 88d0743..2d47a08 100644 --- a/go.sum +++ b/go.sum @@ -6,9 +6,12 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bwmarrin/discordgo v0.20.2 h1:nA7jiTtqUA9lT93WL2jPjUp8ZTEInRujBdx1C9gkr20= github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= +github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIxDdFM= +github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -33,6 +36,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -63,6 +67,7 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -78,12 +83,16 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/qaisjp/go-ircevent v0.0.0-20180911155239-e71f5fec2a8d h1:I1q/elCk4+7JBvJwIf/CmiShndsTu0ka2diGjL0dV20= diff --git a/main.go b/main.go index 0e41e95..bfb308b 100644 --- a/main.go +++ b/main.go @@ -2,22 +2,28 @@ package main import ( "flag" + "fmt" + "net/http" "os" "os/signal" "path/filepath" "reflect" + "strconv" "strings" "syscall" "time" "github.com/fsnotify/fsnotify" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/qaisjp/go-discord-irc/bridge" ircnick "github.com/qaisjp/go-discord-irc/irc/nick" log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) +var version = "development" + func main() { config := flag.String("config", "", "Config file to read configuration stuff from") simple := flag.Bool("simple", false, "When in simple mode, the bridge will only spawn one IRC connection for listening and speaking") @@ -25,10 +31,16 @@ func main() { notls := flag.Bool("no-tls", false, "Avoids using TLS att all when connecting to IRC server ") insecure := flag.Bool("insecure", false, "Skip TLS certificate verification? (INSECURE MODE) (false = use value from settings)") + flag.Usage = func() { + fmt.Fprintf(os.Stdout, "Usage of %s, version %s:\n", os.Args[0], version) + flag.PrintDefaults() + } + flag.Parse() if *config == "" { log.Fatalln("--config argument is required!") + return } @@ -41,6 +53,7 @@ func main() { configName := strings.TrimSuffix(filepath.Base(*config), ext) configType := ext[1:] configPath := filepath.Dir(*config) + viper.SetConfigName(configName) viper.SetConfigType(configType) viper.AddConfigPath(configPath) @@ -56,13 +69,20 @@ func main() { log.Fatalln(errors.Wrap(err, "could not read config")) } - discordBotToken := viper.GetString("discord_token") // Discord Bot User Token - channelMappings := viper.GetStringMapString("channel_mappings") // Discord:IRC mappings in format '#discord1:#irc1,#discord2:#irc2,...' - ircServer := viper.GetString("irc_server") // Server address to use, example `irc.freenode.net:7000`. - ircPassword := viper.GetString("irc_pass") // Optional password for connecting to the IRC server - guildID := viper.GetString("guild_id") // Guild to use - webIRCPass := viper.GetString("webirc_pass") // Password for WEBIRC - identify := viper.GetString("nickserv_identify") // NickServ IDENTIFY for Listener + // Discord Bot User Token + discordBotToken := viper.GetString("discord_token") + // Discord:IRC mappings in format '#discord1:#irc1,#discord2:#irc2,...' + channelMappings := viper.GetStringMapString("channel_mappings") + // Server address to use, example `irc.freenode.net:7000`. + ircServer := viper.GetString("irc_server") + // Optional password for connecting to the IRC server + ircPassword := viper.GetString("irc_pass") + // Guild to use + guildID := viper.GetString("guild_id") + // Password for WEBIRC + webIRCPass := viper.GetString("webirc_pass") + // NickServ IDENTIFY for Listener + identify := viper.GetString("nickserv_identify") // if !*debugMode { *debugMode = viper.GetBool("debug") @@ -71,6 +91,7 @@ func main() { if !*notls { *notls = viper.GetBool("no_tls") } + // if !*insecure { *insecure = viper.GetBool("insecure") } @@ -98,6 +119,11 @@ func main() { viper.SetDefault("max_nick_length", ircnick.MAXLENGTH) maxNickLength := viper.GetInt("max_nick_length") + viper.SetDefault("prometheus.enabled", false) + viper.SetDefault("prometheus.port", 2112) + promEnabled := viper.GetBool("prometheus.enabled") + metricsPort := viper.GetInt("prometheus.port") + if webIRCPass == "" { log.Warnln("webirc_pass is empty") } @@ -107,7 +133,11 @@ func main() { log.Warnln("Channel mappings are missing!") } - SetLogDebug(*debugMode) + setLogDebug(*debugMode) + + if promEnabled { + enableMetrics(metricsPort) + } dib, err := bridge.New(&bridge.Config{ DiscordBotToken: discordBotToken, @@ -135,6 +165,7 @@ func main() { if err != nil { log.WithField("error", err).Fatalln("Go-Discord-IRC failed to initialise.") + return } @@ -146,6 +177,7 @@ func main() { err = dib.Open() if err != nil { log.WithField("error", err).Fatalln("Go-Discord-IRC failed to start.") + return } @@ -167,7 +199,7 @@ func main() { log.Printf("Debug changed from %+v to %+v", *debugMode, debug) *debugMode = debug dib.SetDebugMode(debug) - SetLogDebug(debug) + setLogDebug(debug) } chans := viper.GetStringMapString("channel_mappings") @@ -195,11 +227,29 @@ func main() { dib.Close() } -func SetLogDebug(debug bool) { +func setLogDebug(debug bool) { logger := log.StandardLogger() + if debug { logger.SetLevel(log.DebugLevel) } else { logger.SetLevel(log.InfoLevel) } } + +func enableMetrics(port int) { + http.Handle("/metrics", promhttp.Handler()) + + portStr := strconv.Itoa(port) + address := ":" + portStr + + go func() { + if err := http.ListenAndServe(address, nil); err != nil { + log.WithFields(log.Fields{ + "error": err, + "address": address, + }).Error("could not start prometheus metric endpoint") + } + }() + log.WithField("address", address).Info("prometheus metric endpoint started") +}