diff --git a/config.sample.yaml b/config.sample.yaml index 20fcb118168535a043ccc850d557ff665ca5f72a..382b0bcccf3fa2ef83083a123e113711a4ca1bf9 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -243,4 +243,17 @@ timeouts: # The maximum amount of time the media repo will spend talking to your configured homeservers. # This is usually used to verify a user's identity. - clientServerTimeoutSeconds: 30 \ No newline at end of file + clientServerTimeoutSeconds: 30 + +# Prometheus metrics configuration +# For an example Grafana dashboard, import the following JSON: +# https://t2bot.io/_matrix/media/r0/download/t2l.io/b89e3f042ff2057abcc470d4366a7977 +metrics: + # If true, the bindAddress and port below will serve GET /metrics for Prometheus to scrape. + enabled: false + + # The address to listen on. Typically "127.0.0.1" or "0.0.0.0" for all interfaces. + bindAddress: "127.0.0.1" + + # The port to listen on. Cannot be the same as the general web server port. + port: 9000 diff --git a/src/github.com/turt2live/matrix-media-repo/api/webserver/route_handler.go b/src/github.com/turt2live/matrix-media-repo/api/webserver/route_handler.go index 83de3b9974a291f840a5f8c4a9ce3eecb0222337..83fde20a81bbfe04bb1d42ad9084226ea316eb08 100644 --- a/src/github.com/turt2live/matrix-media-repo/api/webserver/route_handler.go +++ b/src/github.com/turt2live/matrix-media-repo/api/webserver/route_handler.go @@ -7,19 +7,23 @@ import ( "net" "net/http" "net/url" + "strconv" "strings" "github.com/alioygur/is" + "github.com/prometheus/client_golang/prometheus" "github.com/sebest/xff" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/api/r0" "github.com/turt2live/matrix-media-repo/common" + "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/util" ) type handler struct { h func(r *http.Request, entry *logrus.Entry) interface{} + action string reqCounter *requestCounter } @@ -64,11 +68,20 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var res interface{} = api.AuthFailed() if util.IsServerOurs(r.Host) { contextLog.Info("Server is owned by us, processing request") + metrics.HttpRequests.With(prometheus.Labels{ + "host": r.Host, + "action": h.action, + "method": r.Method, + }).Inc() res = h.h(r, contextLog) if res == nil { res = &api.EmptyResponse{} } } else { + metrics.InvalidHttpRequests.With(prometheus.Labels{ + "action": h.action, + "method": r.Method, + }).Inc() contextLog.Warn("The server name provided in the Host header is not configured, or the request was made directly to the media repo instead of through your reverse proxy. This request is being rejected.") } if res == nil { @@ -102,6 +115,12 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } break case *r0.DownloadMediaResponse: + metrics.HttpResponses.With(prometheus.Labels{ + "host": r.Host, + "action": h.action, + "method": r.Method, + "statusCode": strconv.Itoa(http.StatusOK), + }).Inc() w.Header().Set("Content-Type", result.ContentType) if result.SizeBytes > 0 { w.Header().Set("Content-Length", fmt.Sprint(result.SizeBytes)) @@ -117,6 +136,12 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { io.Copy(w, result.Data) return // Prevent sending conflicting responses case *r0.IdenticonResponse: + metrics.HttpResponses.With(prometheus.Labels{ + "host": r.Host, + "action": h.action, + "method": r.Method, + "statusCode": strconv.Itoa(http.StatusOK), + }).Inc() w.Header().Set("Content-Type", "image/png") io.Copy(w, result.Avatar) return // Prevent sending conflicting responses @@ -124,6 +149,13 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } + metrics.HttpResponses.With(prometheus.Labels{ + "host": r.Host, + "action": h.action, + "method": r.Method, + "statusCode": strconv.Itoa(statusCode), + }).Inc() + // Order is important: Set headers before sending responses w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) diff --git a/src/github.com/turt2live/matrix-media-repo/api/webserver/webserver.go b/src/github.com/turt2live/matrix-media-repo/api/webserver/webserver.go index 6d28bbad3063f49da3f4d650cd807a2559fd7fd6..ca549aa80e062e982db6f7706069a10738bff2eb 100644 --- a/src/github.com/turt2live/matrix-media-repo/api/webserver/webserver.go +++ b/src/github.com/turt2live/matrix-media-repo/api/webserver/webserver.go @@ -25,18 +25,18 @@ func Init() { rtr := mux.NewRouter() counter := &requestCounter{} - optionsHandler := handler{api.EmptyResponseHandler, counter} - uploadHandler := handler{api.AccessTokenRequiredRoute(r0.UploadMedia), counter} - downloadHandler := handler{api.AccessTokenOptionalRoute(r0.DownloadMedia), counter} - thumbnailHandler := handler{api.AccessTokenOptionalRoute(r0.ThumbnailMedia), counter} - previewUrlHandler := handler{api.AccessTokenRequiredRoute(r0.PreviewUrl), counter} - identiconHandler := handler{api.AccessTokenOptionalRoute(r0.Identicon), counter} - purgeHandler := handler{api.RepoAdminRoute(custom.PurgeRemoteMedia), counter} - quarantineHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineMedia), counter} - quarantineRoomHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineRoomMedia), counter} - localCopyHandler := handler{api.AccessTokenRequiredRoute(unstable.LocalCopy), counter} - infoHandler := handler{api.AccessTokenRequiredRoute(unstable.MediaInfo), counter} - configHandler := handler{api.AccessTokenRequiredRoute(r0.PublicConfig), counter} + optionsHandler := handler{api.EmptyResponseHandler, "options_request", counter} + uploadHandler := handler{api.AccessTokenRequiredRoute(r0.UploadMedia), "upload", counter} + downloadHandler := handler{api.AccessTokenOptionalRoute(r0.DownloadMedia), "download", counter} + thumbnailHandler := handler{api.AccessTokenOptionalRoute(r0.ThumbnailMedia), "thumbnail", counter} + previewUrlHandler := handler{api.AccessTokenRequiredRoute(r0.PreviewUrl), "url_preview", counter} + identiconHandler := handler{api.AccessTokenOptionalRoute(r0.Identicon), "identicon", counter} + purgeHandler := handler{api.RepoAdminRoute(custom.PurgeRemoteMedia), "purge_remote_media", counter} + quarantineHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineMedia), "quarantine_media", counter} + quarantineRoomHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineRoomMedia), "quarantine_room", counter} + localCopyHandler := handler{api.AccessTokenRequiredRoute(unstable.LocalCopy), "local_copy", counter} + infoHandler := handler{api.AccessTokenRequiredRoute(unstable.MediaInfo), "info", counter} + configHandler := handler{api.AccessTokenRequiredRoute(r0.PublicConfig), "config", counter} routes := make(map[string]route) versions := []string{"r0", "v1", "unstable"} // r0 is typically clients and v1 is typically servers. v1 is deprecated. @@ -76,8 +76,8 @@ func Init() { rtr.Handle(routePath+"/", optionsHandler).Methods("OPTIONS") } - rtr.NotFoundHandler = handler{api.NotFoundHandler, counter} - rtr.MethodNotAllowedHandler = handler{api.MethodNotAllowedHandler, counter} + rtr.NotFoundHandler = handler{api.NotFoundHandler, "not_found", counter} + rtr.MethodNotAllowedHandler = handler{api.MethodNotAllowedHandler, "method_not_allowed", counter} var handler http.Handler = rtr if config.Get().RateLimit.Enabled { @@ -96,8 +96,9 @@ func Init() { } address := config.Get().General.BindAddress + ":" + strconv.Itoa(config.Get().General.Port) - http.Handle("/", handler) + httpMux := http.NewServeMux() + httpMux.Handle("/", handler) logrus.WithField("address", address).Info("Started up. Listening at http://" + address) - http.ListenAndServe(address, nil) + logrus.Fatal(http.ListenAndServe(address, httpMux)) } diff --git a/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go b/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go index 582e950bede12240b42276ad4c662aca681a7b56..250d777ac7b6a066370f78587b66510dd37c2637 100644 --- a/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go +++ b/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go @@ -7,6 +7,7 @@ import ( "github.com/turt2live/matrix-media-repo/api/webserver" "github.com/turt2live/matrix-media-repo/common/config" "github.com/turt2live/matrix-media-repo/common/logging" + "github.com/turt2live/matrix-media-repo/metrics" ) func main() { @@ -23,5 +24,6 @@ func main() { } logrus.Info("Starting media repository...") + metrics.Init() webserver.Init() // blocks to listen for requests } diff --git a/src/github.com/turt2live/matrix-media-repo/common/config/config.go b/src/github.com/turt2live/matrix-media-repo/common/config/config.go index 8fa232ccedeabee2753ce1376c2825a829a3d3f0..bd1d05d5592e4a7a4a0c8e310944d15257f3f7ab 100644 --- a/src/github.com/turt2live/matrix-media-repo/common/config/config.go +++ b/src/github.com/turt2live/matrix-media-repo/common/config/config.go @@ -107,6 +107,12 @@ type TimeoutsConfig struct { ClientServer int `yaml:"clientServerTimeoutSeconds"` } +type MetricsConfig struct { + Enabled bool `yaml:"enabled"` + BindAddress string `yaml:"bindAddress"` + Port int `yaml:"port"` +} + type MediaRepoConfig struct { General *GeneralConfig `yaml:"repo"` Homeservers []*HomeserverConfig `yaml:"homeservers,flow"` @@ -120,6 +126,7 @@ type MediaRepoConfig struct { Identicons *IdenticonsConfig `yaml:"identicons"` Quarantine *QuarantineConfig `yaml:"quarantine"` TimeoutSeconds *TimeoutsConfig `yaml:"timeouts"` + Metrics *MetricsConfig `yaml:"metrics"` } var instance *MediaRepoConfig @@ -275,5 +282,10 @@ func NewDefaultConfig() *MediaRepoConfig { ClientServer: 30, Federation: 120, }, + Metrics: &MetricsConfig{ + Enabled: false, + BindAddress: "localhost", + Port: 9000, + }, } } diff --git a/src/github.com/turt2live/matrix-media-repo/controllers/download_controller/download_resource_handler.go b/src/github.com/turt2live/matrix-media-repo/controllers/download_controller/download_resource_handler.go index 39305ce13ed89a70495b4d22f6424fdd41ee71a5..7b76345e27d85ffee02347c178aef60a1949c192 100644 --- a/src/github.com/turt2live/matrix-media-repo/controllers/download_controller/download_resource_handler.go +++ b/src/github.com/turt2live/matrix-media-repo/controllers/download_controller/download_resource_handler.go @@ -11,11 +11,13 @@ import ( "github.com/djherbis/stream" "github.com/patrickmn/go-cache" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/config" "github.com/turt2live/matrix-media-repo/controllers/upload_controller" "github.com/turt2live/matrix-media-repo/matrix" + "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" "github.com/turt2live/matrix-media-repo/util/resource_handler" @@ -251,5 +253,6 @@ func DownloadRemoteMediaDirect(server string, mediaId string, log *logrus.Entry) } log.Info("Persisting downloaded media") + metrics.MediaDownloaded.With(prometheus.Labels{"origin": server}).Inc() return request, nil } diff --git a/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/calculated_previewer.go b/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/calculated_previewer.go index d5022828919e155bc0bb9c9977b4c908531fe94d..02194661813217c530ce8574bed1976897e5f844 100644 --- a/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/calculated_previewer.go +++ b/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/calculated_previewer.go @@ -10,10 +10,12 @@ import ( "strconv" "time" + "github.com/prometheus/client_golang/prometheus" "github.com/ryanuber/go-glob" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/util" ) @@ -56,6 +58,7 @@ func GenerateCalculatedPreview(urlStr string, log *logrus.Entry) (PreviewResult, result.Image = img } + metrics.UrlPreviewsGenerated.With(prometheus.Labels{"type":"calculated"}).Inc() return *result, nil } diff --git a/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/opengraph_previewer.go b/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/opengraph_previewer.go index 4c95daea5f7147f58101830e8774f04db4bdb00e..59616c29dae4f074fd71d1297ae90e364fdb5bd2 100644 --- a/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/opengraph_previewer.go +++ b/src/github.com/turt2live/matrix-media-repo/controllers/preview_controller/previewers/opengraph_previewer.go @@ -15,10 +15,12 @@ import ( "github.com/PuerkitoBio/goquery" "github.com/dyatlov/go-opengraph/opengraph" + "github.com/prometheus/client_golang/prometheus" "github.com/ryanuber/go-glob" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/metrics" ) var ogSupportedTypes = []string{"text/*"} @@ -89,6 +91,7 @@ func GenerateOpenGraphPreview(urlStr string, log *logrus.Entry) (PreviewResult, graph.Image = img } + metrics.UrlPreviewsGenerated.With(prometheus.Labels{"type": "opengraph"}).Inc() return *graph, nil } @@ -125,7 +128,7 @@ func doHttpGet(urlStr string, log *logrus.Entry) (*http.Response, error) { Timeout: time.Duration(config.Get().TimeoutSeconds.UrlPreviews) * time.Second, } } - + req, err := http.NewRequest("GET", urlStr, nil) if err != nil { return nil, err diff --git a/src/github.com/turt2live/matrix-media-repo/controllers/thumbnail_controller/thumbnail_resource_handler.go b/src/github.com/turt2live/matrix-media-repo/controllers/thumbnail_controller/thumbnail_resource_handler.go index 1bac90f42dbe8e37ec5638ce4c59b01a8d0ec045..f5efaebd3b08cc3d1c862c6f12849610a638fd7a 100644 --- a/src/github.com/turt2live/matrix-media-repo/controllers/thumbnail_controller/thumbnail_resource_handler.go +++ b/src/github.com/turt2live/matrix-media-repo/controllers/thumbnail_controller/thumbnail_resource_handler.go @@ -12,11 +12,14 @@ import ( "os" "os/exec" "path" + "strconv" "sync" "github.com/disintegration/imaging" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" @@ -158,6 +161,14 @@ func GenerateThumbnail(media *types.Media, width int, height int, method string, log.Info("Aspect ratio is the same, converting method to 'scale'") } + metric := metrics.ThumbnailsGenerated.With(prometheus.Labels{ + "width": strconv.Itoa(width), + "height": strconv.Itoa(height), + "method": method, + "animated": strconv.FormatBool(animated), + "origin": media.Origin, + }) + thumb := &GeneratedThumbnail{ Animated: animated, } @@ -175,6 +186,7 @@ func GenerateThumbnail(media *types.Media, width int, height int, method string, thumb.SizeBytes = media.SizeBytes thumb.Sha256Hash = media.Sha256Hash log.Warn("Image too small, returning raw image") + metric.Inc() return thumb, nil } } @@ -292,6 +304,7 @@ func GenerateThumbnail(media *types.Media, width int, height int, method string, thumb.SizeBytes = fileSize thumb.Sha256Hash = hash + metric.Inc() return thumb, nil } diff --git a/src/github.com/turt2live/matrix-media-repo/internal_cache/media_cache.go b/src/github.com/turt2live/matrix-media-repo/internal_cache/media_cache.go index a614d24e9ca436394593d7fb005c2f5016d38e26..cfd84062bf54c1464c143c4f81d28e9e7a3df08e 100644 --- a/src/github.com/turt2live/matrix-media-repo/internal_cache/media_cache.go +++ b/src/github.com/turt2live/matrix-media-repo/internal_cache/media_cache.go @@ -10,8 +10,10 @@ import ( "time" "github.com/patrickmn/go-cache" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" @@ -90,6 +92,7 @@ func (c *MediaCache) IncrementDownloads(fileHash string) { func (c *MediaCache) GetMedia(media *types.Media, log *logrus.Entry) (*cachedFile, error) { if !c.enabled { + metrics.CacheMisses.With(prometheus.Labels{"cache": "media"}).Inc() return nil, nil } @@ -111,6 +114,7 @@ func (c *MediaCache) GetMedia(media *types.Media, log *logrus.Entry) (*cachedFil func (c *MediaCache) GetThumbnail(thumbnail *types.Thumbnail, log *logrus.Entry) (*cachedFile, error) { if !c.enabled { + metrics.CacheMisses.With(prometheus.Labels{"cache": "media"}).Inc() return nil, nil } @@ -140,6 +144,8 @@ func (c *MediaCache) updateItemInCache(recordId string, mediaSize int64, cacheFn // The cached bytes will leave memory over time if found && !enoughDownloads { log.Info("Removing media from cache because it does not have enough downloads") + metrics.CacheMisses.With(prometheus.Labels{"cache": "media"}).Inc() + metrics.CacheEvictions.With(prometheus.Labels{"cache": "media", "reason": "not_enough_downloads"}).Inc() c.cache.Delete(recordId) c.flagEvicted(recordId) return nil, nil @@ -155,6 +161,7 @@ func (c *MediaCache) updateItemInCache(recordId string, mediaSize int64, cacheFn // Don't bother checking for space if it won't fit anyways if mediaSize > maxSpace { log.Warn("Media too large to cache") + metrics.CacheMisses.With(prometheus.Labels{"cache": "media"}).Inc() return nil, nil } @@ -168,6 +175,8 @@ func (c *MediaCache) updateItemInCache(recordId string, mediaSize int64, cacheFn if err != nil { return nil, err } + metrics.CacheNumItems.With(prometheus.Labels{"cache": "media"}).Inc() + metrics.CacheNumBytes.With(prometheus.Labels{"cache": "media"}).Set(float64(c.size)) c.cache.Set(recordId, cachedItem, cache.DefaultExpiration) } @@ -187,6 +196,9 @@ func (c *MediaCache) updateItemInCache(recordId string, mediaSize int64, cacheFn if err != nil { return nil, err } + metrics.CacheHits.With(prometheus.Labels{"cache": "media"}).Inc() + metrics.CacheNumItems.With(prometheus.Labels{"cache": "media"}).Inc() + metrics.CacheNumBytes.With(prometheus.Labels{"cache": "media"}).Set(float64(c.size)) c.cache.Set(recordId, cachedItem, cache.DefaultExpiration) return cachedItem, nil } @@ -197,8 +209,10 @@ func (c *MediaCache) updateItemInCache(recordId string, mediaSize int64, cacheFn // By now the media should be in the correct state (cached or not) if found { + metrics.CacheHits.With(prometheus.Labels{"cache": "media"}).Inc() return item.(*cachedFile), nil } + metrics.CacheMisses.With(prometheus.Labels{"cache": "media"}).Inc() return nil, nil } @@ -249,8 +263,12 @@ func (c *MediaCache) clearSpace(neededBytes int64, withDownloadsLessThan int, wi toRemove := e.Value.(*removable) c.cache.Delete(toRemove.cacheKey) c.flagEvicted(toRemove.recordId) + metrics.CacheEvictions.With(prometheus.Labels{"cache": "media", "reason": "need_space"}).Inc() + metrics.CacheNumItems.With(prometheus.Labels{"cache": "media"}).Dec() } + c.size -= preppedSpace + metrics.CacheNumBytes.With(prometheus.Labels{"cache": "media"}).Set(float64(c.size)) return preppedSpace } diff --git a/src/github.com/turt2live/matrix-media-repo/metrics/metrics.go b/src/github.com/turt2live/matrix-media-repo/metrics/metrics.go new file mode 100644 index 0000000000000000000000000000000000000000..e607a8a76d9e3e9298e8660a3d8dafee03e8544f --- /dev/null +++ b/src/github.com/turt2live/matrix-media-repo/metrics/metrics.go @@ -0,0 +1,53 @@ +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +var HttpRequests = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_http_requests_total", +}, []string{"host", "action", "method"}) +var InvalidHttpRequests = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_invalid_http_requests_total", +}, []string{"action", "method"}) +var HttpResponses = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_http_responses_total", +}, []string{"host", "action", "method", "statusCode"}) +var CacheHits = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_cache_hits_total", +}, []string{"cache"}) +var CacheMisses = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_cache_misses_total", +}, []string{"cache"}) +var CacheEvictions = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_cache_evictions_total", +}, []string{"cache","reason"}) +var CacheNumItems = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "media_cache_num_items", +}, []string{"cache"}) +var CacheNumBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "media_cache_num_bytes_used", +}, []string{"cache"}) +var ThumbnailsGenerated = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_thumbnails_generated_total", +}, []string{"width","height","method","animated","origin"}) +var MediaDownloaded = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_downloaded_total", +}, []string{"origin"}) +var UrlPreviewsGenerated = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "media_url_previews_generated_total", +}, []string{"type"}) + +func init() { + prometheus.MustRegister(HttpRequests) + prometheus.MustRegister(InvalidHttpRequests) + prometheus.MustRegister(HttpResponses) + prometheus.MustRegister(CacheHits) + prometheus.MustRegister(CacheMisses) + prometheus.MustRegister(CacheEvictions) + prometheus.MustRegister(CacheNumItems) + prometheus.MustRegister(CacheNumBytes) + prometheus.MustRegister(ThumbnailsGenerated) + prometheus.MustRegister(MediaDownloaded) + prometheus.MustRegister(UrlPreviewsGenerated) +} diff --git a/src/github.com/turt2live/matrix-media-repo/metrics/webserver.go b/src/github.com/turt2live/matrix-media-repo/metrics/webserver.go new file mode 100644 index 0000000000000000000000000000000000000000..cdfdf4d3f1312cba8b1c1a0a528c35f96b6ac591 --- /dev/null +++ b/src/github.com/turt2live/matrix-media-repo/metrics/webserver.go @@ -0,0 +1,25 @@ +package metrics + +import ( + "net/http" + "strconv" + + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/common/config" +) + +func Init() { + if !config.Get().Metrics.Enabled { + logrus.Info("Metrics disabled") + return + } + rtr := http.NewServeMux() + rtr.Handle("/metrics", promhttp.Handler()) + rtr.Handle("/_media/metrics", promhttp.Handler()) + go func() { + address := config.Get().Metrics.BindAddress + ":" + strconv.Itoa(config.Get().Metrics.Port) + logrus.WithField("address", address).Info("Started metrics listener. Listening at http://" + address) + logrus.Fatal(http.ListenAndServe(address, rtr)) + }() +} diff --git a/vendor/manifest b/vendor/manifest index 5b50fea7a126738765246d52f13c66bd010d2e89..0fb7d376742b08725729091f97e5adcb180c10b2 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -31,6 +31,13 @@ "revision": "349dd0209470eabd9514242c688c403c0926d266", "branch": "master" }, + { + "importpath": "github.com/beorn7/perks/quantile", + "repository": "https://github.com/beorn7/perks", + "revision": "3a771d992973f24aa725d07868b467d1ddfceafb", + "branch": "master", + "path": "/quantile" + }, { "importpath": "github.com/cenk/backoff", "repository": "https://github.com/cenk/backoff", @@ -100,6 +107,13 @@ "branch": "master", "path": "/truetype" }, + { + "importpath": "github.com/golang/protobuf/proto", + "repository": "https://github.com/golang/protobuf", + "revision": "52132540909e117f2b98b0694383dc0ab1e1deca", + "branch": "master", + "path": "/proto" + }, { "importpath": "github.com/gorilla/mux", "repository": "https://github.com/gorilla/mux", @@ -142,6 +156,13 @@ "revision": "b609790bd85edf8e9ab7e0f8912750a786177bcf", "branch": "master" }, + { + "importpath": "github.com/matttproud/golang_protobuf_extensions/pbutil", + "repository": "https://github.com/matttproud/golang_protobuf_extensions", + "revision": "c12348ce28de40eed0136aa2b644d0ee0650e56c", + "branch": "master", + "path": "/pbutil" + }, { "importpath": "github.com/olebedev/emitter", "repository": "https://github.com/olebedev/emitter", @@ -160,6 +181,46 @@ "revision": "f15c970de5b76fac0b59abb32d62c17cc7bed265", "branch": "master" }, + { + "importpath": "github.com/prometheus/client_golang", + "repository": "https://github.com/prometheus/client_golang", + "revision": "3fb53dff765f8a3e0f9d8b1d5b86d4f8c4eb3a09", + "branch": "master" + }, + { + "importpath": "github.com/prometheus/client_model/go", + "repository": "https://github.com/prometheus/client_model", + "revision": "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f", + "branch": "master", + "path": "/go" + }, + { + "importpath": "github.com/prometheus/common/expfmt", + "repository": "https://github.com/prometheus/common", + "revision": "1f2c4f3cd6db5fd6f68f36af6b6d5d936fd93c4e", + "branch": "master", + "path": "/expfmt" + }, + { + "importpath": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg", + "repository": "https://github.com/prometheus/common", + "revision": "1f2c4f3cd6db5fd6f68f36af6b6d5d936fd93c4e", + "branch": "master", + "path": "/internal/bitbucket.org/ww/goautoneg" + }, + { + "importpath": "github.com/prometheus/common/model", + "repository": "https://github.com/prometheus/common", + "revision": "1f2c4f3cd6db5fd6f68f36af6b6d5d936fd93c4e", + "branch": "master", + "path": "/model" + }, + { + "importpath": "github.com/prometheus/procfs", + "repository": "https://github.com/prometheus/procfs", + "revision": "185b4288413d2a0dd0806f78c90dde719829e5ae", + "branch": "master" + }, { "importpath": "github.com/rifflock/lfshook", "repository": "https://github.com/rifflock/lfshook",