From 14ae7faf766d9bb6aceab4b917abb2aa7e23f792 Mon Sep 17 00:00:00 2001
From: Travis Ralston <travpc@gmail.com>
Date: Thu, 19 Mar 2020 16:41:55 -0600
Subject: [PATCH] Track real usage of the cache in addition to the perceived
 usage

---
 CHANGELOG.md                  |  1 +
 internal_cache/media_cache.go | 18 ++++++++++++++++++
 metrics/listeners.go          |  7 +++++++
 metrics/metrics.go            |  8 ++++++++
 metrics/webserver.go          | 12 ++++++++++--
 5 files changed, 44 insertions(+), 2 deletions(-)
 create mode 100644 metrics/listeners.go

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00622f2f..eb56601a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 * Pass-through the `Accept-Language` header for URL previews, with options to set a default.
 * Experimental support for IPFS.
 * Consistent inclusion of a charset for certain text `Content-Type`s.
+* New metrics for the cache composition reality (`media_cache_num_live_bytes_used` and `media_cache_num_live_items`).
 
 ### Fixed
 
diff --git a/internal_cache/media_cache.go b/internal_cache/media_cache.go
index 83cea4a6..ab3db53b 100644
--- a/internal_cache/media_cache.go
+++ b/internal_cache/media_cache.go
@@ -70,6 +70,11 @@ func Get() *MediaCache {
 				logrus.Infof("Record %s has been evicted from the cache", recordId)
 			})
 
+			metrics.OnBeforeMetricsRequested(func() {
+				metrics.CacheLiveNumBytes.With(prometheus.Labels{"cache": "media"}).Set(float64(instance.getUnderlyingUsedBytes()))
+				metrics.CacheNumLiveItems.With(prometheus.Labels{"cache": "media"}).Set(float64(instance.getUnderlyingItemCount()))
+			})
+
 			go func() {
 				rctx := rcontext.Initial().LogWithFields(logrus.Fields{"task": "cache_cleanup"})
 				for _ = range instance.cleanupTimer.C {
@@ -102,6 +107,19 @@ func (c *MediaCache) Stop() {
 	c.cleanupTimer.Stop()
 }
 
+func (c *MediaCache) getUnderlyingUsedBytes() int64 {
+	var size int64 = 0
+	for _, entry := range c.cache.Items() {
+		f := entry.Object.(*cachedFile)
+		size += int64(f.Contents.Len())
+	}
+	return size
+}
+
+func (c *MediaCache) getUnderlyingItemCount() int {
+	return c.cache.ItemCount()
+}
+
 func (c *MediaCache) IncrementDownloads(fileHash string) {
 	if !c.enabled {
 		return
diff --git a/metrics/listeners.go b/metrics/listeners.go
new file mode 100644
index 00000000..e757165b
--- /dev/null
+++ b/metrics/listeners.go
@@ -0,0 +1,7 @@
+package metrics
+
+var beforeMetricsCalledFns = make([]func(), 0)
+
+func OnBeforeMetricsRequested(fn func()) {
+	beforeMetricsCalledFns = append(beforeMetricsCalledFns, fn)
+}
diff --git a/metrics/metrics.go b/metrics/metrics.go
index 8260b4ab..47a1336f 100644
--- a/metrics/metrics.go
+++ b/metrics/metrics.go
@@ -25,9 +25,15 @@ var CacheEvictions = prometheus.NewCounterVec(prometheus.CounterOpts{
 var CacheNumItems = prometheus.NewGaugeVec(prometheus.GaugeOpts{
 	Name: "media_cache_num_items",
 }, []string{"cache"})
+var CacheNumLiveItems = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+	Name: "media_cache_num_live_items",
+}, []string{"cache"})
 var CacheNumBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
 	Name: "media_cache_num_bytes_used",
 }, []string{"cache"})
+var CacheLiveNumBytes = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+	Name: "media_cache_num_live_bytes_used",
+}, []string{"cache"})
 var ThumbnailsGenerated = prometheus.NewCounterVec(prometheus.CounterOpts{
 	Name: "media_thumbnails_generated_total",
 }, []string{"width", "height", "method", "animated", "origin"})
@@ -46,7 +52,9 @@ func init() {
 	prometheus.MustRegister(CacheMisses)
 	prometheus.MustRegister(CacheEvictions)
 	prometheus.MustRegister(CacheNumItems)
+	prometheus.MustRegister(CacheNumLiveItems)
 	prometheus.MustRegister(CacheNumBytes)
+	prometheus.MustRegister(CacheLiveNumBytes)
 	prometheus.MustRegister(ThumbnailsGenerated)
 	prometheus.MustRegister(MediaDownloaded)
 	prometheus.MustRegister(UrlPreviewsGenerated)
diff --git a/metrics/webserver.go b/metrics/webserver.go
index 0585eced..14339591 100644
--- a/metrics/webserver.go
+++ b/metrics/webserver.go
@@ -13,14 +13,22 @@ import (
 
 var srv *http.Server
 
+func internalHandler(res http.ResponseWriter, req *http.Request) {
+	logrus.Info("Updating live metrics for cache")
+	for _, fn := range beforeMetricsCalledFns {
+		fn()
+	}
+	promhttp.Handler().ServeHTTP(res, req)
+}
+
 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())
+	rtr.HandleFunc("/metrics", internalHandler)
+	rtr.HandleFunc("/_media/metrics", internalHandler)
 
 	address := config.Get().Metrics.BindAddress + ":" + strconv.Itoa(config.Get().Metrics.Port)
 	srv = &http.Server{Addr: address, Handler: rtr}
-- 
GitLab