Skip to content

Commit 4a47e91

Browse files
committed
implement servicediscovery with go-cache
Signed-off-by: Markus Blaschke <mblaschke82@gmail.com>
1 parent 4f234ea commit 4a47e91

File tree

8 files changed

+147
-117
lines changed

8 files changed

+147
-117
lines changed

collector_base.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@ package main
33
import (
44
log "github.com/sirupsen/logrus"
55
devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client"
6-
"sync"
76
"time"
87
)
98

109
type CollectorBase struct {
1110
Name string
1211
scrapeTime *time.Duration
1312

14-
azureDevOpsProjects *devopsClient.ProjectList
15-
azureDevOpsProjectsMutex sync.Mutex
16-
1713
logger *log.Entry
1814

1915
LastScrapeDuration *time.Duration
@@ -34,17 +30,8 @@ func (c *CollectorBase) GetScrapeTime() *time.Duration {
3430
return c.scrapeTime
3531
}
3632

37-
func (c *CollectorBase) SetAzureProjects(projects *devopsClient.ProjectList) {
38-
c.azureDevOpsProjectsMutex.Lock()
39-
c.azureDevOpsProjects = projects
40-
c.azureDevOpsProjectsMutex.Unlock()
41-
}
42-
43-
func (c *CollectorBase) GetAzureProjects() (projects *devopsClient.ProjectList) {
44-
c.azureDevOpsProjectsMutex.Lock()
45-
projects = c.azureDevOpsProjects
46-
c.azureDevOpsProjectsMutex.Unlock()
47-
return
33+
func (c *CollectorBase) GetAzureProjects() (projects []devopsClient.Project) {
34+
return AzureDevopsServiceDiscovery.ProjectList()
4835
}
4936

5037
func (c *CollectorBase) collectionStart() {

collector_general.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func (c *CollectorGeneral) Collect() {
2727
var wg sync.WaitGroup
2828
var wgCallback sync.WaitGroup
2929

30-
if c.GetAzureProjects() == nil {
30+
if len(c.GetAzureProjects()) == 0 {
3131
c.logger.Info("no projects found, skipping")
3232
return
3333
}

collector_project.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func (c *CollectorProject) Collect() {
4040

4141
c.collectionStart()
4242

43-
for _, project := range c.GetAzureProjects().List {
43+
for _, project := range c.GetAzureProjects() {
4444
wg.Add(1)
4545
go func(ctx context.Context, callback chan<- func(), project devopsClient.Project) {
4646
defer wg.Done()

config/opts.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ type (
5454
QueriesWithProjects []string `long:"list.query" env:"AZURE_DEVOPS_QUERIES" env-delim:" " description:"Pairs of query and project UUIDs in the form: '<queryId>@<projectId>'"`
5555
}
5656

57+
// cache settings
58+
Cache struct {
59+
Expiry time.Duration `long:"cache.expiry" env:"CACHE_EXPIRY" description:"Internal cache expiry time (time.duration)" default:"30m"`
60+
}
61+
5762
Request struct {
5863
ConcurrencyLimit int64 `long:"request.concurrency" env:"REQUEST_CONCURRENCY" description:"Number of concurrent requests against dev.azure.com" default:"10"`
5964
Retries int `long:"request.retries" env:"REQUEST_RETRIES" description:"Number of retried requests against dev.azure.com" default:"3"`

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ require (
1717
gopkg.in/resty.v1 v1.12.0
1818
)
1919

20+
require github.com/patrickmn/go-cache v2.1.0+incompatible
21+
2022
require (
2123
github.com/beorn7/perks v1.0.1 // indirect
2224
github.com/cespare/xxhash/v2 v2.1.2 // indirect
23-
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
2425
github.com/prometheus/client_model v0.2.0 // indirect
2526
)

main.go

Lines changed: 4 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"path"
1313
"runtime"
1414
"strings"
15-
"time"
1615
)
1716

1817
const (
@@ -23,7 +22,8 @@ var (
2322
argparser *flags.Parser
2423
opts config.Opts
2524

26-
AzureDevopsClient *AzureDevops.AzureDevopsClient
25+
AzureDevopsClient *AzureDevops.AzureDevopsClient
26+
AzureDevopsServiceDiscovery *azureDevopsServiceDiscovery
2727

2828
collectorGeneralList map[string]*CollectorGeneral
2929
collectorProjectList map[string]*CollectorProject
@@ -43,6 +43,8 @@ func main() {
4343

4444
log.Infof("init AzureDevOps connection")
4545
initAzureDevOpsConnection()
46+
AzureDevopsServiceDiscovery = NewAzureDevopsServiceDiscovery()
47+
AzureDevopsServiceDiscovery.Update()
4648

4749
log.Info("init metrics collection")
4850
initMetricCollector()
@@ -200,55 +202,16 @@ func initAzureDevOpsConnection() {
200202
AzureDevopsClient.LimitReleaseDefinitionsPerProject = opts.Limit.ReleaseDefinitionsPerProject
201203
AzureDevopsClient.LimitReleasesPerProject = opts.Limit.ReleasesPerProject
202204
}
203-
204-
func getAzureDevOpsProjects() (list AzureDevops.ProjectList) {
205-
rawList, err := AzureDevopsClient.ListProjects()
206-
207-
if err != nil {
208-
panic(err)
209-
}
210-
211-
list = rawList
212-
213-
// whitelist
214-
if len(opts.AzureDevops.FilterProjects) > 0 {
215-
rawList = list
216-
list = AzureDevops.ProjectList{}
217-
for _, project := range rawList.List {
218-
if arrayStringContains(opts.AzureDevops.FilterProjects, project.Id) {
219-
list.List = append(list.List, project)
220-
}
221-
}
222-
}
223-
224-
// blacklist
225-
if len(opts.AzureDevops.BlacklistProjects) > 0 {
226-
// filter ignored azure devops projects
227-
rawList = list
228-
list = AzureDevops.ProjectList{}
229-
for _, project := range rawList.List {
230-
if !arrayStringContains(opts.AzureDevops.BlacklistProjects, project.Id) {
231-
list.List = append(list.List, project)
232-
}
233-
}
234-
}
235-
236-
return
237-
}
238-
239205
func initMetricCollector() {
240206
var collectorName string
241207
collectorGeneralList = map[string]*CollectorGeneral{}
242208
collectorProjectList = map[string]*CollectorProject{}
243209
collectorAgentPoolList = map[string]*CollectorAgentPool{}
244210
collectorQueryList = map[string]*CollectorQuery{}
245211

246-
projectList := getAzureDevOpsProjects()
247-
248212
collectorName = "General"
249213
if opts.Scrape.TimeLive.Seconds() > 0 {
250214
collectorGeneralList[collectorName] = NewCollectorGeneral(collectorName, &MetricsCollectorGeneral{})
251-
collectorGeneralList[collectorName].SetAzureProjects(&projectList)
252215
collectorGeneralList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive)
253216
} else {
254217
log.Infof("collector[%s]: disabled", collectorName)
@@ -257,7 +220,6 @@ func initMetricCollector() {
257220
collectorName = "Project"
258221
if opts.Scrape.TimeLive.Seconds() > 0 {
259222
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorProject{})
260-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
261223
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive)
262224
} else {
263225
log.Infof("collector[%s]: disabled", collectorName)
@@ -266,7 +228,6 @@ func initMetricCollector() {
266228
collectorName = "AgentPool"
267229
if opts.Scrape.TimeLive.Seconds() > 0 {
268230
collectorAgentPoolList[collectorName] = NewCollectorAgentPool(collectorName, &MetricsCollectorAgentPool{})
269-
collectorAgentPoolList[collectorName].SetAzureProjects(&projectList)
270231
collectorAgentPoolList[collectorName].AgentPoolIdList = opts.AzureDevops.AgentPoolIdList
271232
collectorAgentPoolList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive)
272233
} else {
@@ -276,7 +237,6 @@ func initMetricCollector() {
276237
collectorName = "LatestBuild"
277238
if opts.Scrape.TimeLive.Seconds() > 0 {
278239
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorLatestBuild{})
279-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
280240
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive)
281241
} else {
282242
log.Infof("collector[%s]: disabled", collectorName)
@@ -285,7 +245,6 @@ func initMetricCollector() {
285245
collectorName = "Repository"
286246
if opts.Scrape.TimeRepository.Seconds() > 0 {
287247
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorRepository{})
288-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
289248
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeRepository)
290249
} else {
291250
log.Infof("collector[%s]: disabled", collectorName)
@@ -294,7 +253,6 @@ func initMetricCollector() {
294253
collectorName = "PullRequest"
295254
if opts.Scrape.TimePullRequest.Seconds() > 0 {
296255
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorPullRequest{})
297-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
298256
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimePullRequest)
299257
} else {
300258
log.Infof("collector[%s]: disabled", collectorName)
@@ -303,7 +261,6 @@ func initMetricCollector() {
303261
collectorName = "Build"
304262
if opts.Scrape.TimeBuild.Seconds() > 0 {
305263
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorBuild{})
306-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
307264
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeBuild)
308265
} else {
309266
log.Infof("collector[%s]: disabled", collectorName)
@@ -312,7 +269,6 @@ func initMetricCollector() {
312269
collectorName = "Release"
313270
if opts.Scrape.TimeRelease.Seconds() > 0 {
314271
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorRelease{})
315-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
316272
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeRelease)
317273
} else {
318274
log.Infof("collector[%s]: disabled", collectorName)
@@ -321,7 +277,6 @@ func initMetricCollector() {
321277
collectorName = "Deployment"
322278
if opts.Scrape.TimeDeployment.Seconds() > 0 {
323279
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorDeployment{})
324-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
325280
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeDeployment)
326281
} else {
327282
log.Infof("collector[%s]: disabled", collectorName)
@@ -330,7 +285,6 @@ func initMetricCollector() {
330285
collectorName = "Stats"
331286
if opts.Scrape.TimeStats.Seconds() > 0 {
332287
collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorStats{})
333-
collectorProjectList[collectorName].SetAzureProjects(&projectList)
334288
collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeStats)
335289
} else {
336290
log.Infof("collector[%s]: disabled", collectorName)
@@ -339,7 +293,6 @@ func initMetricCollector() {
339293
collectorName = "ResourceUsage"
340294
if opts.Scrape.TimeResourceUsage.Seconds() > 0 {
341295
collectorGeneralList[collectorName] = NewCollectorGeneral(collectorName, &MetricsCollectorResourceUsage{})
342-
collectorGeneralList[collectorName].SetAzureProjects(&projectList)
343296
collectorGeneralList[collectorName].SetScrapeTime(*opts.Scrape.TimeResourceUsage)
344297
} else {
345298
log.Infof("collector[%s]: disabled", collectorName)
@@ -348,7 +301,6 @@ func initMetricCollector() {
348301
collectorName = "Query"
349302
if opts.Scrape.TimeQuery.Seconds() > 0 {
350303
collectorQueryList[collectorName] = NewCollectorQuery(collectorName, &MetricsCollectorQuery{})
351-
collectorQueryList[collectorName].SetAzureProjects(&projectList)
352304
collectorQueryList[collectorName].QueryList = opts.AzureDevops.QueriesWithProjects
353305
collectorQueryList[collectorName].SetScrapeTime(*opts.Scrape.TimeQuery)
354306
} else {
@@ -370,36 +322,6 @@ func initMetricCollector() {
370322
for _, collector := range collectorQueryList {
371323
collector.Run()
372324
}
373-
374-
// background auto update of projects
375-
if opts.Scrape.TimeProjects.Seconds() > 0 {
376-
go func() {
377-
// initial sleep
378-
time.Sleep(*opts.Scrape.TimeProjects)
379-
380-
for {
381-
log.Info("daemon: updating project list")
382-
383-
projectList := getAzureDevOpsProjects()
384-
log.Infof("daemon: found %v projects", projectList.Count)
385-
386-
for _, collector := range collectorGeneralList {
387-
collector.SetAzureProjects(&projectList)
388-
}
389-
390-
for _, collector := range collectorProjectList {
391-
collector.SetAzureProjects(&projectList)
392-
}
393-
394-
for _, collector := range collectorAgentPoolList {
395-
collector.SetAzureProjects(&projectList)
396-
}
397-
398-
log.Info("daemon: skipping Query collectors; they don't use projects")
399-
time.Sleep(*opts.Scrape.TimeProjects)
400-
}
401-
}()
402-
}
403325
}
404326

405327
// start and handle prometheus handler

metrics_agentpool.go

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -131,29 +131,14 @@ func (m *MetricsCollectorAgentPool) Reset() {
131131
}
132132

133133
func (m *MetricsCollectorAgentPool) Collect(ctx context.Context, logger *log.Entry, callback chan<- func()) {
134-
for _, project := range m.CollectorReference.azureDevOpsProjects.List {
134+
for _, project := range m.CollectorReference.GetAzureProjects() {
135135
contextLogger := logger.WithFields(log.Fields{
136136
"project": project.Name,
137137
})
138138
m.collectAgentInfo(ctx, contextLogger, callback, project)
139139
}
140140

141-
agentPoolList := []int64{}
142-
if m.CollectorReference.AgentPoolIdList != nil {
143-
agentPoolList = *m.CollectorReference.AgentPoolIdList
144-
} else {
145-
result, err := AzureDevopsClient.ListAgentPools()
146-
if err != nil {
147-
logger.Error(err)
148-
return
149-
}
150-
151-
for _, agentPool := range result.Value {
152-
agentPoolList = append(agentPoolList, agentPool.ID)
153-
}
154-
}
155-
156-
for _, agentPoolId := range agentPoolList {
141+
for _, agentPoolId := range AzureDevopsServiceDiscovery.AgentPoolList() {
157142
contextLogger := logger.WithFields(log.Fields{
158143
"agentPoolId": agentPoolId,
159144
})

0 commit comments

Comments
 (0)