From 3302da1c920133dc0d62fa876be68173d7701a61 Mon Sep 17 00:00:00 2001
From: Hector <dev@hsmith.org>
Date: Tue, 12 Oct 2021 20:36:32 +0100
Subject: [PATCH] collect file contents before exporting metrics

---
 src/textfile/collector.go |  9 +++++---
 src/textfile/file.go      | 40 ++++++++++++++++++++++++++++++++---
 src/textfile/writer.go    | 44 +++++----------------------------------
 3 files changed, 48 insertions(+), 45 deletions(-)

diff --git a/src/textfile/collector.go b/src/textfile/collector.go
index 1bcea12..178d828 100644
--- a/src/textfile/collector.go
+++ b/src/textfile/collector.go
@@ -8,18 +8,20 @@ import (
 type Collector struct {
 	enabled bool
 	folderPath string
-	fileMap map[string]fileMetrics
+	fileMap map[string]*fileData
 }
 
-type fileMetrics struct {
+type fileData struct {
 	readErrors int
+	fileName string
+	fileContents []byte
 }
 
 func NewCollector(appSettings *cfg.AppSettings) *Collector {
 	return &Collector{
 		enabled:    appSettings.FileCollectorEnabled,
 		folderPath: appSettings.FileCollectorPath,
-		fileMap:    make(map[string]fileMetrics),
+		fileMap:    make(map[string]*fileData),
 	}
 }
 
@@ -31,6 +33,7 @@ func (c *Collector) Describe(ch chan<- *prometheus.Desc) {
 
 func (c *Collector) Collect(ch chan<- prometheus.Metric) {
 	if c.enabled {
+		c.collectFileContents()
 		c.collectFileErrors(ch)
 	}
 }
diff --git a/src/textfile/file.go b/src/textfile/file.go
index 8e587e2..1bdd378 100644
--- a/src/textfile/file.go
+++ b/src/textfile/file.go
@@ -1,6 +1,12 @@
 package textfile
 
-import "github.com/prometheus/client_golang/prometheus"
+import (
+	"github.com/prometheus/client_golang/prometheus"
+	"io/ioutil"
+	"log"
+	"path/filepath"
+	"strings"
+)
 
 const namespace = "textfile"
 
@@ -12,10 +18,38 @@ var (
 	)
 )
 
+func (c *Collector) collectFileContents() {
+	files, err := ioutil.ReadDir(c.folderPath)
+	if err != nil {
+		log.Printf("error reading directory '%s': %v", c.folderPath, err)
+		return
+	}
+
+	for _, file := range files {
+		fileName := file.Name()
+		if !strings.HasSuffix(fileName, ".prom") {
+			continue
+		}
+		c.fileMap[fileName] = &fileData{
+			readErrors:   0,
+			fileName:     fileName,
+		}
+
+		fullPath := filepath.Join(c.folderPath, file.Name())
+		content, err := ioutil.ReadFile(fullPath)
+		if err != nil {
+			c.appendErrorForPath(fileName)
+			log.Printf("error reading contents of file '%s': %v", fileName, err)
+		}
+
+		c.fileMap[fileName].fileContents = content
+	}
+}
+
 func (c *Collector) collectFileErrors(ch chan<- prometheus.Metric) {
-	for fileName, metrics := range c.fileMap {
+	for _, f := range c.fileMap {
 		ch <- prometheus.MustNewConstMetric(
-			metricReadError, prometheus.GaugeValue, float64(metrics.readErrors), fileName,
+			metricReadError, prometheus.GaugeValue, float64(f.readErrors), f.fileName,
 		)
 	}
 }
diff --git a/src/textfile/writer.go b/src/textfile/writer.go
index 129df6a..9c6b13f 100644
--- a/src/textfile/writer.go
+++ b/src/textfile/writer.go
@@ -1,11 +1,8 @@
 package textfile
 
 import (
-	"io/ioutil"
 	"log"
 	"net/http"
-	"path/filepath"
-	"strings"
 )
 
 func (c *Collector) WriteTextFileMetrics(w http.ResponseWriter, r *http.Request) {
@@ -13,46 +10,15 @@ func (c *Collector) WriteTextFileMetrics(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	files, err := ioutil.ReadDir(c.folderPath)
-	if err != nil {
-		c.appendErrorForPath(c.folderPath)
-		log.Printf("error reading directory '%s': %v", c.folderPath, err)
-		return
-	}
-
-	for _, file := range files {
-		fileName := file.Name()
-		if !strings.HasSuffix(fileName, ".prom") {
-			continue
-		}
-
-		c.setErrorCountForPath(fileName, 0)
-
-		fullPath := filepath.Join(c.folderPath, file.Name())
-		content, err := ioutil.ReadFile(fullPath)
+	for _, f := range c.fileMap {
+		_, err := w.Write(f.fileContents)
 		if err != nil {
-			c.appendErrorForPath(fileName)
-			log.Printf("error reading contents of file '%s': %v", fileName, err)
-		}
-
-		_, err = w.Write(content)
-		if err != nil {
-			c.appendErrorForPath(fileName)
-			log.Printf("error writing file contents to response writer '%s': %v", fileName, err)
+			c.appendErrorForPath(f.fileName)
+			log.Printf("error writing file contents to response writer '%s': %v", f.fileName, err)
 		}
 	}
 }
 
 func (c *Collector) appendErrorForPath(path string) {
-	if _, ok := c.fileMap[path]; !ok {
-		c.setErrorCountForPath(path, 1)
-	} else {
-		c.setErrorCountForPath(path, c.fileMap[path].readErrors + 1)
-	}
-}
-
-func (c *Collector) setErrorCountForPath(path string, count int) {
-	c.fileMap[path] = fileMetrics{
-		readErrors: count,
-	}
+	c.fileMap[path].readErrors++
 }