chore(stcrashreceiver): better source cache & metrics
Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
@@ -47,4 +47,14 @@ var (
|
|||||||
Subsystem: "crashreceiver",
|
Subsystem: "crashreceiver",
|
||||||
Name: "ignore_matches_total",
|
Name: "ignore_matches_total",
|
||||||
}, []string{"pattern"})
|
}, []string{"pattern"})
|
||||||
|
metricSourceCodeLoadsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Namespace: "syncthing",
|
||||||
|
Subsystem: "crashreceiver",
|
||||||
|
Name: "source_code_loads_total",
|
||||||
|
}, []string{"result"})
|
||||||
|
metricSourceCodeCacheSize = promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Namespace: "syncthing",
|
||||||
|
Subsystem: "crashreceiver",
|
||||||
|
Name: "source_code_cache_size",
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,23 +15,33 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
lru "github.com/hashicorp/golang-lru/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
urlPrefix = "https://raw.githubusercontent.com/syncthing/syncthing/"
|
urlPrefix = "https://raw.githubusercontent.com/syncthing/syncthing/"
|
||||||
httpTimeout = 10 * time.Second
|
httpTimeout = 10 * time.Second
|
||||||
|
maxCacheEntries = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type cacheKey struct {
|
||||||
|
version string
|
||||||
|
file string
|
||||||
|
}
|
||||||
|
|
||||||
type githubSourceCodeLoader struct {
|
type githubSourceCodeLoader struct {
|
||||||
mut sync.Mutex
|
mut sync.Mutex
|
||||||
version string
|
version string
|
||||||
cache map[string]map[string][][]byte // version -> file -> lines
|
|
||||||
client *http.Client
|
cache *lru.TwoQueueCache[cacheKey, [][]byte] // version & file -> lines
|
||||||
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGithubSourceCodeLoader() *githubSourceCodeLoader {
|
func newGithubSourceCodeLoader() *githubSourceCodeLoader {
|
||||||
|
cache, _ := lru.New2Q[cacheKey, [][]byte](maxCacheEntries)
|
||||||
return &githubSourceCodeLoader{
|
return &githubSourceCodeLoader{
|
||||||
cache: make(map[string]map[string][][]byte),
|
cache: cache,
|
||||||
client: &http.Client{Timeout: httpTimeout},
|
client: &http.Client{Timeout: httpTimeout},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,9 +49,6 @@ func newGithubSourceCodeLoader() *githubSourceCodeLoader {
|
|||||||
func (l *githubSourceCodeLoader) LockWithVersion(version string) {
|
func (l *githubSourceCodeLoader) LockWithVersion(version string) {
|
||||||
l.mut.Lock()
|
l.mut.Lock()
|
||||||
l.version = version
|
l.version = version
|
||||||
if _, ok := l.cache[version]; !ok {
|
|
||||||
l.cache[version] = make(map[string][][]byte)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *githubSourceCodeLoader) Unlock() {
|
func (l *githubSourceCodeLoader) Unlock() {
|
||||||
@@ -50,11 +57,13 @@ func (l *githubSourceCodeLoader) Unlock() {
|
|||||||
|
|
||||||
func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]byte, int) {
|
func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]byte, int) {
|
||||||
filename = filepath.ToSlash(filename)
|
filename = filepath.ToSlash(filename)
|
||||||
lines, ok := l.cache[l.version][filename]
|
key := cacheKey{version: l.version, file: filename}
|
||||||
|
lines, ok := l.cache.Get(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
// Cache whatever we managed to find (or nil if nothing, so we don't try again)
|
// Cache whatever we managed to find (or nil if nothing, so we don't try again)
|
||||||
defer func() {
|
defer func() {
|
||||||
l.cache[l.version][filename] = lines
|
l.cache.Add(key, lines)
|
||||||
|
metricSourceCodeCacheSize.Set(float64(l.cache.Len()))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
knownPrefixes := []string{"/lib/", "/cmd/"}
|
knownPrefixes := []string{"/lib/", "/cmd/"}
|
||||||
@@ -73,19 +82,25 @@ func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]b
|
|||||||
resp, err := l.client.Get(url)
|
resp, err := l.client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Loading source:", err)
|
fmt.Println("Loading source:", err)
|
||||||
|
metricSourceCodeLoadsTotal.WithLabelValues("failed").Inc()
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
fmt.Println("Loading source:", resp.Status)
|
fmt.Println("Loading source:", resp.Status)
|
||||||
|
metricSourceCodeLoadsTotal.WithLabelValues("failed").Inc()
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
data, err := io.ReadAll(resp.Body)
|
data, err := io.ReadAll(resp.Body)
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Loading source:", err.Error())
|
fmt.Println("Loading source:", err.Error())
|
||||||
|
metricSourceCodeLoadsTotal.WithLabelValues("failed").Inc()
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
lines = bytes.Split(data, []byte{'\n'})
|
lines = bytes.Split(data, []byte{'\n'})
|
||||||
|
metricSourceCodeLoadsTotal.WithLabelValues("loaded").Inc()
|
||||||
|
} else {
|
||||||
|
metricSourceCodeLoadsTotal.WithLabelValues("cached").Inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
return getLineFromLines(lines, line, context)
|
return getLineFromLines(lines, line, context)
|
||||||
|
|||||||
Reference in New Issue
Block a user