diff --git a/src/github.com/matrix-org/go-neb/api.go b/src/github.com/matrix-org/go-neb/api.go index 4a7881d..09ec2c2 100644 --- a/src/github.com/matrix-org/go-neb/api.go +++ b/src/github.com/matrix-org/go-neb/api.go @@ -8,6 +8,7 @@ import ( "github.com/matrix-org/go-neb/clients" "github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/errors" + "github.com/matrix-org/go-neb/metrics" "github.com/matrix-org/go-neb/polling" "github.com/matrix-org/go-neb/types" "net/http" @@ -180,7 +181,6 @@ func (wh *webhookHandler) handle(w http.ResponseWriter, req *http.Request) { // but we've base64d it. base64srvID := segments[len(segments)-1] bytesSrvID, err := base64.RawURLEncoding.DecodeString(base64srvID) - srvID := string(bytesSrvID) if err != nil { log.WithError(err).WithField("base64_service_id", base64srvID).Print( "Not a b64 encoded string", @@ -188,6 +188,7 @@ func (wh *webhookHandler) handle(w http.ResponseWriter, req *http.Request) { w.WriteHeader(400) return } + srvID := string(bytesSrvID) service, err := wh.db.LoadService(srvID) if err != nil { @@ -203,9 +204,10 @@ func (wh *webhookHandler) handle(w http.ResponseWriter, req *http.Request) { return } log.WithFields(log.Fields{ - "service_id": service.ServiceID(), - "service_typ": service.ServiceType(), + "service_id": service.ServiceID(), + "service_type": service.ServiceType(), }).Print("Incoming webhook for service") + metrics.IncrementWebhook(service.ServiceType()) service.OnReceiveWebhook(w, req, cli) } @@ -319,6 +321,7 @@ func (s *configureServiceHandler) OnIncomingRequest(req *http.Request) (interfac } service.PostRegister(old) + metrics.IncrementConfigureService(service.ServiceType()) return &struct { ID string diff --git a/src/github.com/matrix-org/go-neb/metrics/metrics.go b/src/github.com/matrix-org/go-neb/metrics/metrics.go index f9f80c4..3023210 100644 --- a/src/github.com/matrix-org/go-neb/metrics/metrics.go +++ b/src/github.com/matrix-org/go-neb/metrics/metrics.go @@ -4,45 +4,47 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -// CommandStatus is the status of a incoming command -type CommandStatus int +// Status is the status of a measurable metric (incoming commands, outgoing polls, etc) +type Status string -// The command status values +// Common status values const ( - StatusPending CommandStatus = iota - StatusSuccess - StatusFailure + StatusSuccess = "success" + StatusFailure = "failure" ) var ( - numIncomingCmds = prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "num_incoming_commands_total", + cmdCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "goneb_pling_cmd_total", Help: "The number of incoming commands from matrix clients", - }, []string{"cmd"}) - numSuccessCmds = prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "num_success_commands_total", - Help: "The number of incoming commands from matrix clients which were successful", - }, []string{"cmd"}) - numErrorCmds = prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "num_error_commands_total", - Help: "The number of incoming commands from matrix clients which failed", - }, []string{"cmd"}) + }, []string{"cmd", "status"}) + configureServicesCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "goneb_configure_services_total", + Help: "The total number of configured services requests", + }, []string{"service_type"}) + webhookCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "goneb_webhook_total", + Help: "The total number of recognised incoming webhook requests", + }, []string{"service_type"}) ) -// IncrementCommand increments the incoming command counter -func IncrementCommand(cmdName string, st CommandStatus) { - switch st { - case StatusPending: - numIncomingCmds.With(prometheus.Labels{"cmd": cmdName}).Inc() - case StatusSuccess: - numSuccessCmds.With(prometheus.Labels{"cmd": cmdName}).Inc() - case StatusFailure: - numErrorCmds.With(prometheus.Labels{"cmd": cmdName}).Inc() - } +// IncrementCommand increments the pling command counter +func IncrementCommand(cmdName string, st Status) { + cmdCounter.With(prometheus.Labels{"cmd": cmdName, "status": string(st)}).Inc() +} + +// IncrementConfigureService increments the /configureService counter +func IncrementConfigureService(serviceType string) { + configureServicesCounter.With(prometheus.Labels{"service_type": serviceType}).Inc() +} + +// IncrementWebhook increments the incoming webhook request counter +func IncrementWebhook(serviceType string) { + webhookCounter.With(prometheus.Labels{"service_type": serviceType}).Inc() } func init() { - prometheus.MustRegister(numIncomingCmds) - prometheus.MustRegister(numSuccessCmds) - prometheus.MustRegister(numErrorCmds) + prometheus.MustRegister(cmdCounter) + prometheus.MustRegister(configureServicesCounter) + prometheus.MustRegister(webhookCounter) } diff --git a/src/github.com/matrix-org/go-neb/plugin/plugin.go b/src/github.com/matrix-org/go-neb/plugin/plugin.go index 0f170c0..0007bec 100644 --- a/src/github.com/matrix-org/go-neb/plugin/plugin.go +++ b/src/github.com/matrix-org/go-neb/plugin/plugin.go @@ -72,7 +72,6 @@ func runCommandForPlugin(plugin Plugin, event *matrix.Event, arguments []string) "user_id": event.Sender, "command": bestMatch.Path, }).Info("Executing command") - metrics.IncrementCommand(bestMatch.Path[0], metrics.StatusPending) content, err := bestMatch.Command(event.RoomID, event.Sender, cmdArgs) if err != nil { if content != nil { diff --git a/src/github.com/matrix-org/go-neb/services/guggy/guggy.go b/src/github.com/matrix-org/go-neb/services/guggy/guggy.go index 5045694..4d6a2d3 100644 --- a/src/github.com/matrix-org/go-neb/services/guggy/guggy.go +++ b/src/github.com/matrix-org/go-neb/services/guggy/guggy.go @@ -3,10 +3,12 @@ package services import ( "bytes" "encoding/json" + "fmt" log "github.com/Sirupsen/logrus" "github.com/matrix-org/go-neb/matrix" "github.com/matrix-org/go-neb/plugin" "github.com/matrix-org/go-neb/types" + "io/ioutil" "math" "net/http" "strings" @@ -54,7 +56,7 @@ func (s *guggyService) cmdGuggy(client *matrix.Client, roomID, userID string, ar querySentence := strings.Join(args, " ") gifResult, err := s.text2gifGuggy(querySentence) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to query Guggy: %s", err.Error()) } if gifResult.GIF == "" { @@ -66,7 +68,7 @@ func (s *guggyService) cmdGuggy(client *matrix.Client, roomID, userID string, ar mxc, err := client.UploadLink(gifResult.GIF) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to upload Guggy image to matrix: %s", err.Error()) } return matrix.ImageMessage{ @@ -114,9 +116,20 @@ func (s *guggyService) text2gifGuggy(querySentence string) (*guggyGifResult, err log.Error(err) return nil, err } + if res.StatusCode < 200 || res.StatusCode >= 300 { + resBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + log.WithError(err).Error("Failed to decode Guggy response body") + } + log.WithFields(log.Fields{ + "code": res.StatusCode, + "body": string(resBytes), + }).Error("Failed to query Guggy") + return nil, fmt.Errorf("Failed to decode response (HTTP %d)", res.StatusCode) + } var result guggyGifResult if err := json.NewDecoder(res.Body).Decode(&result); err != nil { - return nil, err + return nil, fmt.Errorf("Failed to decode response (HTTP %d): %s", res.StatusCode, err.Error()) } return &result, nil diff --git a/src/github.com/matrix-org/go-neb/services/rssbot/rssbot.go b/src/github.com/matrix-org/go-neb/services/rssbot/rssbot.go index 226d83a..3fd8069 100644 --- a/src/github.com/matrix-org/go-neb/services/rssbot/rssbot.go +++ b/src/github.com/matrix-org/go-neb/services/rssbot/rssbot.go @@ -11,6 +11,7 @@ import ( "github.com/matrix-org/go-neb/polling" "github.com/matrix-org/go-neb/types" "github.com/mmcdole/gofeed" + "github.com/prometheus/client_golang/prometheus" "html" "net/http" "time" @@ -18,6 +19,13 @@ import ( var cachingClient *http.Client +var ( + pollCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "goneb_rss_polls_total", + Help: "The number of feed polls from RSS services", + }, []string{"url", "http_status"}) +) + const minPollingIntervalSeconds = 60 * 5 // 5 min (News feeds can be genuinely spammy) type rssBotService struct { @@ -127,8 +135,15 @@ func (s *rssBotService) OnPoll(cli *matrix.Client) time.Time { feed, items, err := s.queryFeed(u) if err != nil { logger.WithField("feed_url", u).WithError(err).Error("Failed to query feed") + herr, ok := err.(gofeed.HTTPError) + statusCode := 0 // e.g. network timeout + if ok { + statusCode = herr.StatusCode + } + pollCounter.With(prometheus.Labels{"url": u, "http_status": string(statusCode)}).Inc() continue } + pollCounter.With(prometheus.Labels{"url": u, "http_status": "200"}).Inc() // technically 2xx but gofeed doesn't tell us which // Loop backwards since [0] is the most recent and we want to send in chronological order for i := len(items) - 1; i >= 0; i-- { item := items[i] @@ -285,4 +300,5 @@ func init() { } return r }) + prometheus.MustRegister(pollCounter) }