From 8b8b1a2cd592097b47b26786602e3d180a38216d Mon Sep 17 00:00:00 2001 From: Markus Blaschke Date: Mon, 8 May 2023 22:21:55 +0200 Subject: [PATCH] migrate to go-common collector with caching Signed-off-by: Markus Blaschke --- collector_agentpool.go | 67 -------------- collector_base.go | 63 ------------- collector_general.go | 71 --------------- collector_processor_agentpool.go | 30 ------- collector_processor_general.go | 30 ------- collector_processor_project.go | 32 ------- collector_processor_query.go | 30 ------- collector_project.go | 80 ----------------- collector_query.go | 67 -------------- config/opts.go | 15 +++- go.mod | 17 +++- go.sum | 39 +++++++- main.go | 148 +++++++++++++++++-------------- metrics_agentpool.go | 104 +++++++++------------- metrics_build.go | 84 +++++++----------- metrics_deployment.go | 37 ++++---- metrics_general.go | 85 ------------------ metrics_latest_build.go | 38 ++++---- metrics_project.go | 34 +++---- metrics_pullrequest.go | 61 ++++++------- metrics_query.go | 44 ++++----- metrics_release.go | 75 +++++++--------- metrics_repository.go | 81 +++++++++-------- metrics_resourceusage.go | 45 ++++------ metrics_stats.go | 51 ++++++----- misc.go | 7 -- servicediscovery.go | 10 +-- 27 files changed, 456 insertions(+), 989 deletions(-) delete mode 100644 collector_agentpool.go delete mode 100644 collector_base.go delete mode 100644 collector_general.go delete mode 100644 collector_processor_agentpool.go delete mode 100644 collector_processor_general.go delete mode 100644 collector_processor_project.go delete mode 100644 collector_processor_query.go delete mode 100644 collector_project.go delete mode 100644 collector_query.go delete mode 100644 metrics_general.go diff --git a/collector_agentpool.go b/collector_agentpool.go deleted file mode 100644 index 95f8ca0..0000000 --- a/collector_agentpool.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "context" - "sync" -) - -type CollectorAgentPool struct { - CollectorBase - - Processor CollectorProcessorAgentPoolInterface - AgentPoolIdList *[]int64 -} - -func (c *CollectorAgentPool) Run() { - c.Processor.Setup(c) - go func() { - for { - go func() { - c.Collect() - }() - c.sleepUntilNextCollection() - } - }() -} - -func (c *CollectorAgentPool) Collect() { - var wg sync.WaitGroup - var wgCallback sync.WaitGroup - - ctx := context.Background() - - callbackChannel := make(chan func()) - - c.collectionStart() - - wg.Add(1) - go func(ctx context.Context, callback chan<- func()) { - defer wg.Done() - c.Processor.Collect(ctx, c.logger, callbackChannel) - }(ctx, callbackChannel) - - // collect metrics (callbacks) and proceses them - wgCallback.Add(1) - go func() { - defer wgCallback.Done() - var callbackList []func() - for callback := range callbackChannel { - callbackList = append(callbackList, callback) - } - - // reset metric values - c.Processor.Reset() - - // process callbacks (set metrics) - for _, callback := range callbackList { - callback() - } - }() - - // wait for all funcs - wg.Wait() - close(callbackChannel) - wgCallback.Wait() - - c.collectionFinish() -} diff --git a/collector_base.go b/collector_base.go deleted file mode 100644 index 0c79031..0000000 --- a/collector_base.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "time" - - log "github.com/sirupsen/logrus" - - devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" -) - -type CollectorBase struct { - Name string - scrapeTime *time.Duration - - logger *log.Entry - - LastScrapeDuration *time.Duration - collectionStartTime *time.Time - collectionLastTime *time.Time -} - -func (c *CollectorBase) Init() { - c.logger = log.WithField("collector", c.Name) - -} - -func (c *CollectorBase) SetScrapeTime(scrapeTime time.Duration) { - c.scrapeTime = &scrapeTime -} - -func (c *CollectorBase) GetScrapeTime() *time.Duration { - return c.scrapeTime -} - -func (c *CollectorBase) GetAzureProjects() (projects []devopsClient.Project) { - return AzureDevopsServiceDiscovery.ProjectList() -} - -func (c *CollectorBase) collectionStart() { - startTime := time.Now() - c.collectionStartTime = &startTime - - if c.collectionLastTime == nil { - lastTime := startTime.Add(-*c.GetScrapeTime()) - c.collectionLastTime = &lastTime - } - - c.logger.Info("starting metrics collection") -} - -func (c *CollectorBase) collectionFinish() { - duration := time.Since(*c.collectionStartTime) - c.LastScrapeDuration = &duration - - c.collectionLastTime = c.collectionStartTime - - c.logger.WithField("duration", c.LastScrapeDuration.Seconds()).Infof("finished metrics collection (duration: %v)", c.LastScrapeDuration) -} - -func (c *CollectorBase) sleepUntilNextCollection() { - c.logger.Debugf("sleeping %v", c.GetScrapeTime().String()) - time.Sleep(*c.GetScrapeTime()) -} diff --git a/collector_general.go b/collector_general.go deleted file mode 100644 index 5405a79..0000000 --- a/collector_general.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "context" - "sync" -) - -type CollectorGeneral struct { - CollectorBase - - Processor CollectorProcessorGeneralInterface -} - -func (c *CollectorGeneral) Run() { - c.Processor.Setup(c) - go func() { - for { - go func() { - c.Collect() - }() - c.sleepUntilNextCollection() - } - }() -} - -func (c *CollectorGeneral) Collect() { - var wg sync.WaitGroup - var wgCallback sync.WaitGroup - - if len(c.GetAzureProjects()) == 0 { - c.logger.Info("no projects found, skipping") - return - } - - ctx := context.Background() - - callbackChannel := make(chan func()) - - c.collectionStart() - - wg.Add(1) - go func() { - defer wg.Done() - c.Processor.Collect(ctx, c.logger, callbackChannel) - }() - - // collect metrics (callbacks) and proceses them - wgCallback.Add(1) - go func() { - defer wgCallback.Done() - var callbackList []func() - for callback := range callbackChannel { - callbackList = append(callbackList, callback) - } - - // reset metric values - c.Processor.Reset() - - // process callbacks (set metrics) - for _, callback := range callbackList { - callback() - } - }() - - // wait for all funcs - wg.Wait() - close(callbackChannel) - wgCallback.Wait() - - c.collectionFinish() -} diff --git a/collector_processor_agentpool.go b/collector_processor_agentpool.go deleted file mode 100644 index 17eb17a..0000000 --- a/collector_processor_agentpool.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "context" - - log "github.com/sirupsen/logrus" -) - -type CollectorProcessorAgentPoolInterface interface { - Setup(collector *CollectorAgentPool) - Reset() - Collect(ctx context.Context, contextLogger *log.Entry, callback chan<- func()) -} - -type CollectorProcessorAgentPool struct { - CollectorProcessorAgentPoolInterface - CollectorReference *CollectorAgentPool -} - -func NewCollectorAgentPool(name string, processor CollectorProcessorAgentPoolInterface) *CollectorAgentPool { - collector := CollectorAgentPool{ - CollectorBase: CollectorBase{ - Name: name, - }, - Processor: processor, - } - collector.CollectorBase.Init() - - return &collector -} diff --git a/collector_processor_general.go b/collector_processor_general.go deleted file mode 100644 index 83911d6..0000000 --- a/collector_processor_general.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "context" - - log "github.com/sirupsen/logrus" -) - -type CollectorProcessorGeneralInterface interface { - Setup(collector *CollectorGeneral) - Reset() - Collect(ctx context.Context, contextLogger *log.Entry, callback chan<- func()) -} - -type CollectorProcessorGeneral struct { - CollectorProcessorGeneralInterface - CollectorReference *CollectorGeneral -} - -func NewCollectorGeneral(name string, processor CollectorProcessorGeneralInterface) *CollectorGeneral { - collector := CollectorGeneral{ - CollectorBase: CollectorBase{ - Name: name, - }, - Processor: processor, - } - collector.CollectorBase.Init() - - return &collector -} diff --git a/collector_processor_project.go b/collector_processor_project.go deleted file mode 100644 index 2f9b3d4..0000000 --- a/collector_processor_project.go +++ /dev/null @@ -1,32 +0,0 @@ -package main - -import ( - "context" - - log "github.com/sirupsen/logrus" - - devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" -) - -type CollectorProcessorProjectInterface interface { - Setup(collector *CollectorProject) - Reset() - Collect(ctx context.Context, contextLogger *log.Entry, callback chan<- func(), project devopsClient.Project) -} - -type CollectorProcessorProject struct { - CollectorProcessorProjectInterface - CollectorReference *CollectorProject -} - -func NewCollectorProject(name string, processor CollectorProcessorProjectInterface) *CollectorProject { - collector := CollectorProject{ - CollectorBase: CollectorBase{ - Name: name, - }, - Processor: processor, - } - collector.CollectorBase.Init() - - return &collector -} diff --git a/collector_processor_query.go b/collector_processor_query.go deleted file mode 100644 index 2b3365c..0000000 --- a/collector_processor_query.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "context" - - log "github.com/sirupsen/logrus" -) - -type CollectorProcessorQueryInterface interface { - Setup(collector *CollectorQuery) - Reset() - Collect(ctx context.Context, contextLogger *log.Entry, callback chan<- func()) -} - -type CollectorProcessorQuery struct { - CollectorProcessorQueryInterface - CollectorReference *CollectorQuery -} - -func NewCollectorQuery(name string, processor CollectorProcessorQueryInterface) *CollectorQuery { - collector := CollectorQuery{ - CollectorBase: CollectorBase{ - Name: name, - }, - Processor: processor, - } - collector.CollectorBase.Init() - - return &collector -} diff --git a/collector_project.go b/collector_project.go deleted file mode 100644 index 66e3186..0000000 --- a/collector_project.go +++ /dev/null @@ -1,80 +0,0 @@ -package main - -import ( - "context" - "sync" - - log "github.com/sirupsen/logrus" - - devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" -) - -type CollectorProject struct { - CollectorBase - - Processor CollectorProcessorProjectInterface -} - -func (c *CollectorProject) Run() { - c.Processor.Setup(c) - go func() { - for { - go func() { - c.Collect() - }() - c.sleepUntilNextCollection() - } - }() -} - -func (c *CollectorProject) Collect() { - var wg sync.WaitGroup - var wgCallback sync.WaitGroup - - if c.GetAzureProjects() == nil { - c.logger.Info("no projects found, skipping") - return - } - - ctx := context.Background() - - callbackChannel := make(chan func()) - - c.collectionStart() - - for _, project := range c.GetAzureProjects() { - wg.Add(1) - go func(ctx context.Context, callback chan<- func(), project devopsClient.Project) { - defer wg.Done() - contextLogger := c.logger.WithFields(log.Fields{ - "project": project.Name, - }) - c.Processor.Collect(ctx, contextLogger, callbackChannel, project) - }(ctx, callbackChannel, project) - } - - // collect metrics (callbacks) and proceses them - wgCallback.Add(1) - go func() { - defer wgCallback.Done() - var callbackList []func() - for callback := range callbackChannel { - callbackList = append(callbackList, callback) - } - - // reset metric values - c.Processor.Reset() - - // process callbacks (set metrics) - for _, callback := range callbackList { - callback() - } - }() - - // wait for all funcs - wg.Wait() - close(callbackChannel) - wgCallback.Wait() - - c.collectionFinish() -} diff --git a/collector_query.go b/collector_query.go deleted file mode 100644 index 1f489bc..0000000 --- a/collector_query.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "context" - "sync" -) - -type CollectorQuery struct { - CollectorBase - - Processor CollectorProcessorQueryInterface - QueryList []string -} - -func (c *CollectorQuery) Run() { - c.Processor.Setup(c) - go func() { - for { - go func() { - c.Collect() - }() - c.sleepUntilNextCollection() - } - }() -} - -func (c *CollectorQuery) Collect() { - var wg sync.WaitGroup - var wgCallback sync.WaitGroup - - ctx := context.Background() - - callbackChannel := make(chan func()) - - c.collectionStart() - - wg.Add(1) - go func(ctx context.Context, callback chan<- func()) { - defer wg.Done() - c.Processor.Collect(ctx, c.logger, callbackChannel) - }(ctx, callbackChannel) - - // collect metrics (callbacks) and process them - wgCallback.Add(1) - go func() { - defer wgCallback.Done() - var callbackList []func() - for callback := range callbackChannel { - callbackList = append(callbackList, callback) - } - - // reset metric values - c.Processor.Reset() - - // process callbacks (set metrics) - for _, callback := range callbackList { - callback() - } - }() - - // wait for all funcs - wg.Wait() - close(callbackChannel) - wgCallback.Wait() - - c.collectionFinish() -} diff --git a/config/opts.go b/config/opts.go index 8fa2fa1..b4e55dc 100644 --- a/config/opts.go +++ b/config/opts.go @@ -57,7 +57,7 @@ type ( // cache settings Cache struct { - Expiry time.Duration `long:"cache.expiry" env:"CACHE_EXPIRY" description:"Internal cache expiry time (time.duration)" default:"30m"` + Path string `long:"cache.path" env:"CACHE_PATH" description:"Cache path (to folder, file://path... or azblob://storageaccount.blob.core.windows.net/containername)"` } Request struct { @@ -65,6 +65,10 @@ type ( Retries int `long:"request.retries" env:"REQUEST_RETRIES" description:"Number of retried requests against dev.azure.com" default:"3"` } + ServiceDiscovery struct { + RefreshDuration time.Duration `long:"servicediscovery.refresh" env:"SERVICEDISCOVERY_REFRESH" description:"Refresh duration for servicediscovery (time.duration)" default:"30m"` + } + Limit struct { Project int64 `long:"limit.project" env:"LIMIT_PROJECT" description:"Limit number of projects" default:"100"` BuildsPerProject int64 `long:"limit.builds-per-project" env:"LIMIT_BUILDS_PER_PROJECT" description:"Limit builds per project" default:"100"` @@ -86,6 +90,15 @@ type ( } ) +func (o *Opts) GetCachePath(path string) (ret *string) { + if o.Cache.Path != "" { + tmp := o.Cache.Path + "/" + path + ret = &tmp + } + + return +} + func (o *Opts) GetJson() []byte { jsonBytes, err := json.Marshal(o) if err != nil { diff --git a/go.mod b/go.mod index ed1b7f2..70818d5 100644 --- a/go.mod +++ b/go.mod @@ -18,14 +18,29 @@ require ( require ( github.com/jessevdk/go-flags v1.5.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/webdevops/go-common v0.0.0-20230430202837-da27003be3a5 + github.com/remeh/sizedwaitgroup v1.0.0 + github.com/webdevops/go-common v0.0.0-20230502000651-d37d46be8ee7 go.uber.org/zap v1.24.0 ) require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0-beta.5 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.1.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/prometheus/client_model v0.3.0 // indirect + github.com/robfig/cron v1.2.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect ) diff --git a/go.sum b/go.sum index d414404..ab326fb 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,19 @@ +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 h1:xGLAFFd9D3iLGxYiUGPdITSzsFmU1K8VtfuUHWAoN7M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0-beta.5 h1:F8ii3ek6K2tnf9gmv/YFktyOci9DuJboh/rKXMS2FaQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0-beta.5/go.mod h1:ZJteiLBLt8CmYc6yJFe5YErRHQ4FpTEwgXomR1ikcy8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.1.1 h1:A+a54F7ygu4ANdV9hYsLMfiHFgjuwIUCG+6opLAvxJE= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.1.1/go.mod h1:ThfyMjs6auYrWPnYJjI3H4H++oVPrz01pizpu8lfl3A= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -6,8 +22,11 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -15,12 +34,18 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -32,13 +57,17 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= +github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/webdevops/go-common v0.0.0-20230430202837-da27003be3a5 h1:jVTIaZtgrCO1aYMn9nht2+V9cZtDXlvNV7gOQKyPIF4= -github.com/webdevops/go-common v0.0.0-20230430202837-da27003be3a5/go.mod h1:/gBgzF9JefrEJqAqgPlDgwMcBtYwGmqFa3p4g39RvIU= +github.com/webdevops/go-common v0.0.0-20230502000651-d37d46be8ee7 h1:DPIp1yL33mrFetoqAavviyt2iqKCuD2PRaR3hd+Nvr8= +github.com/webdevops/go-common v0.0.0-20230502000651-d37d46be8ee7/go.mod h1:/gBgzF9JefrEJqAqgPlDgwMcBtYwGmqFa3p4g39RvIU= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -46,6 +75,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= @@ -53,11 +84,14 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= @@ -65,5 +99,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/main.go b/main.go index 4eefbd7..4143880 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,8 @@ import ( "github.com/jessevdk/go-flags" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" AzureDevops "github.com/webdevops/azure-devops-exporter/azure-devops-client" "github.com/webdevops/azure-devops-exporter/config" @@ -26,11 +28,6 @@ var ( AzureDevopsClient *AzureDevops.AzureDevopsClient AzureDevopsServiceDiscovery *azureDevopsServiceDiscovery - collectorGeneralList map[string]*CollectorGeneral - collectorProjectList map[string]*CollectorProject - collectorAgentPoolList map[string]*CollectorAgentPool - collectorQueryList map[string]*CollectorQuery - // Git version information gitCommit = "" gitTag = "" @@ -174,125 +171,140 @@ func initAzureDevOpsConnection() { AzureDevopsClient.LimitReleaseDefinitionsPerProject = opts.Limit.ReleaseDefinitionsPerProject AzureDevopsClient.LimitReleasesPerProject = opts.Limit.ReleasesPerProject } + func initMetricCollector() { var collectorName string - collectorGeneralList = map[string]*CollectorGeneral{} - collectorProjectList = map[string]*CollectorProject{} - collectorAgentPoolList = map[string]*CollectorAgentPool{} - collectorQueryList = map[string]*CollectorQuery{} - - collectorName = "General" - if opts.Scrape.TimeLive.Seconds() > 0 { - collectorGeneralList[collectorName] = NewCollectorGeneral(collectorName, &MetricsCollectorGeneral{}) - collectorGeneralList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive) - } else { - logger.Infof("collector[%s]: disabled", collectorName) - } collectorName = "Project" if opts.Scrape.TimeLive.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorProject{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive) + c := collector.New(collectorName, &MetricsCollectorProject{}, logger) + c.SetScapeTime(*opts.Scrape.TimeLive) + c.SetCache(opts.GetCachePath("project.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "AgentPool" if opts.Scrape.TimeLive.Seconds() > 0 { - collectorAgentPoolList[collectorName] = NewCollectorAgentPool(collectorName, &MetricsCollectorAgentPool{}) - collectorAgentPoolList[collectorName].AgentPoolIdList = opts.AzureDevops.AgentPoolIdList - collectorAgentPoolList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive) + c := collector.New(collectorName, &MetricsCollectorAgentPool{}, logger) + c.SetScapeTime(*opts.Scrape.TimeLive) + c.SetCache(opts.GetCachePath("agentpool.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "LatestBuild" if opts.Scrape.TimeLive.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorLatestBuild{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeLive) + c := collector.New(collectorName, &MetricsCollectorLatestBuild{}, logger) + c.SetScapeTime(*opts.Scrape.TimeLive) + c.SetCache(opts.GetCachePath("latestbuild.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "Repository" if opts.Scrape.TimeRepository.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorRepository{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeRepository) + c := collector.New(collectorName, &MetricsCollectorRepository{}, logger) + c.SetScapeTime(*opts.Scrape.TimeRepository) + c.SetCache(opts.GetCachePath("latestbuild.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "PullRequest" if opts.Scrape.TimePullRequest.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorPullRequest{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimePullRequest) + c := collector.New(collectorName, &MetricsCollectorPullRequest{}, logger) + c.SetScapeTime(*opts.Scrape.TimePullRequest) + c.SetCache(opts.GetCachePath("pullrequest.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "Build" if opts.Scrape.TimeBuild.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorBuild{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeBuild) + c := collector.New(collectorName, &MetricsCollectorBuild{}, logger) + c.SetScapeTime(*opts.Scrape.TimeBuild) + c.SetCache(opts.GetCachePath("build.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "Release" if opts.Scrape.TimeRelease.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorRelease{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeRelease) + c := collector.New(collectorName, &MetricsCollectorRelease{}, logger) + c.SetScapeTime(*opts.Scrape.TimeRelease) + c.SetCache(opts.GetCachePath("release.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "Deployment" if opts.Scrape.TimeDeployment.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorDeployment{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeDeployment) + c := collector.New(collectorName, &MetricsCollectorDeployment{}, logger) + c.SetScapeTime(*opts.Scrape.TimeDeployment) + c.SetCache(opts.GetCachePath("deployment.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "Stats" if opts.Scrape.TimeStats.Seconds() > 0 { - collectorProjectList[collectorName] = NewCollectorProject(collectorName, &MetricsCollectorStats{}) - collectorProjectList[collectorName].SetScrapeTime(*opts.Scrape.TimeStats) + c := collector.New(collectorName, &MetricsCollectorStats{}, logger) + c.SetScapeTime(*opts.Scrape.TimeStats) + c.SetCache(opts.GetCachePath("stats.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "ResourceUsage" if opts.Scrape.TimeResourceUsage.Seconds() > 0 { - collectorGeneralList[collectorName] = NewCollectorGeneral(collectorName, &MetricsCollectorResourceUsage{}) - collectorGeneralList[collectorName].SetScrapeTime(*opts.Scrape.TimeResourceUsage) + c := collector.New(collectorName, &MetricsCollectorResourceUsage{}, logger) + c.SetScapeTime(*opts.Scrape.TimeResourceUsage) + c.SetCache(opts.GetCachePath("resourceusage.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } collectorName = "Query" if opts.Scrape.TimeQuery.Seconds() > 0 { - collectorQueryList[collectorName] = NewCollectorQuery(collectorName, &MetricsCollectorQuery{}) - collectorQueryList[collectorName].QueryList = opts.AzureDevops.QueriesWithProjects - collectorQueryList[collectorName].SetScrapeTime(*opts.Scrape.TimeQuery) + c := collector.New(collectorName, &MetricsCollectorQuery{}, logger) + c.SetScapeTime(*opts.Scrape.TimeQuery) + c.SetCache(opts.GetCachePath("query.json")) + if err := c.Start(); err != nil { + logger.Fatal(err.Error()) + } } else { - logger.Infof("collector[%s]: disabled", collectorName) - } - - for _, collector := range collectorGeneralList { - collector.Run() - } - - for _, collector := range collectorProjectList { - collector.Run() - } - - for _, collector := range collectorAgentPoolList { - collector.Run() - } - - for _, collector := range collectorQueryList { - collector.Run() + logger.With(zap.String("collector", collectorName)).Info("collector disabled") } } diff --git a/metrics_agentpool.go b/metrics_agentpool.go index 4f7c520..df81f53 100644 --- a/metrics_agentpool.go +++ b/metrics_agentpool.go @@ -4,14 +4,15 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "github.com/webdevops/go-common/utils/to" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorAgentPool struct { - CollectorProcessorAgentPool + collector.Processor prometheus struct { agentPool *prometheus.GaugeVec @@ -24,8 +25,8 @@ type MetricsCollectorAgentPool struct { } } -func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { - m.CollectorReference = collector +func (m *MetricsCollectorAgentPool) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.agentPool = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -39,7 +40,7 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "isHosted", }, ) - prometheus.MustRegister(m.prometheus.agentPool) + m.Collector.RegisterMetricList("agentPool", m.prometheus.agentPool, true) m.prometheus.agentPoolSize = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -50,7 +51,7 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "agentPoolID", }, ) - prometheus.MustRegister(m.prometheus.agentPoolSize) + m.Collector.RegisterMetricList("agentPoolSize", m.prometheus.agentPoolSize, true) m.prometheus.agentPoolUsage = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -61,7 +62,7 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "agentPoolID", }, ) - prometheus.MustRegister(m.prometheus.agentPoolUsage) + m.Collector.RegisterMetricList("agentPoolUsage", m.prometheus.agentPoolUsage, true) m.prometheus.agentPoolAgent = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -81,7 +82,7 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "hasAssignedRequest", }, ) - prometheus.MustRegister(m.prometheus.agentPoolAgent) + m.Collector.RegisterMetricList("agentPoolAgent", m.prometheus.agentPoolAgent, true) m.prometheus.agentPoolAgentStatus = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -93,7 +94,7 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "type", }, ) - prometheus.MustRegister(m.prometheus.agentPoolAgentStatus) + m.Collector.RegisterMetricList("agentPoolAgentStatus", m.prometheus.agentPoolAgentStatus, true) m.prometheus.agentPoolAgentJob = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -109,7 +110,7 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "scopeID", }, ) - prometheus.MustRegister(m.prometheus.agentPoolAgentJob) + m.Collector.RegisterMetricList("agentPoolAgentJob", m.prometheus.agentPoolAgentJob, true) m.prometheus.agentPoolQueueLength = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -120,51 +121,42 @@ func (m *MetricsCollectorAgentPool) Setup(collector *CollectorAgentPool) { "agentPoolID", }, ) - prometheus.MustRegister(m.prometheus.agentPoolQueueLength) + m.Collector.RegisterMetricList("agentPoolQueueLength", m.prometheus.agentPoolQueueLength, true) } -func (m *MetricsCollectorAgentPool) Reset() { - m.prometheus.agentPool.Reset() - m.prometheus.agentPoolSize.Reset() - m.prometheus.agentPoolAgent.Reset() - m.prometheus.agentPoolAgentStatus.Reset() - m.prometheus.agentPoolAgentJob.Reset() - m.prometheus.agentPoolQueueLength.Reset() -} +func (m *MetricsCollectorAgentPool) Reset() {} + +func (m *MetricsCollectorAgentPool) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() -func (m *MetricsCollectorAgentPool) Collect(ctx context.Context, logger *log.Entry, callback chan<- func()) { - for _, project := range m.CollectorReference.GetAzureProjects() { - contextLogger := logger.WithFields(log.Fields{ - "project": project.Name, - }) - m.collectAgentInfo(ctx, contextLogger, callback, project) + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.collectAgentInfo(ctx, projectLogger, callback, project) } for _, agentPoolId := range AzureDevopsServiceDiscovery.AgentPoolList() { - contextLogger := logger.WithFields(log.Fields{ - "agentPoolId": agentPoolId, - }) - - m.collectAgentQueues(ctx, contextLogger, callback, agentPoolId) - m.collectAgentPoolJobs(ctx, contextLogger, callback, agentPoolId) + agentPoolLogger := logger.With(zap.Int64("agentPoolId", agentPoolId)) + m.collectAgentQueues(ctx, agentPoolLogger, callback, agentPoolId) + m.collectAgentPoolJobs(ctx, agentPoolLogger, callback, agentPoolId) } } -func (m *MetricsCollectorAgentPool) collectAgentInfo(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorAgentPool) collectAgentInfo(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { list, err := AzureDevopsClient.ListAgentQueues(project.Id) if err != nil { logger.Error(err) return } - agentPoolInfoMetric := prometheusCommon.NewMetricsList() - agentPoolSizeMetric := prometheusCommon.NewMetricsList() + agentPoolInfoMetric := m.Collector.GetMetricList("agentPool") + agentPoolSizeMetric := m.Collector.GetMetricList("agentPoolSize") for _, agentQueue := range list.List { agentPoolInfoMetric.Add(prometheus.Labels{ "agentPoolID": int64ToString(agentQueue.Pool.Id), "agentPoolName": agentQueue.Name, - "isHosted": boolToString(agentQueue.Pool.IsHosted), + "isHosted": to.BoolString(agentQueue.Pool.IsHosted), "agentPoolType": agentQueue.Pool.PoolType, }, 1) @@ -172,24 +164,19 @@ func (m *MetricsCollectorAgentPool) collectAgentInfo(ctx context.Context, logger "agentPoolID": int64ToString(agentQueue.Pool.Id), }, float64(agentQueue.Pool.Size)) } - - callback <- func() { - agentPoolInfoMetric.GaugeSet(m.prometheus.agentPool) - agentPoolSizeMetric.GaugeSet(m.prometheus.agentPoolSize) - } } -func (m *MetricsCollectorAgentPool) collectAgentQueues(ctx context.Context, logger *log.Entry, callback chan<- func(), agentPoolId int64) { +func (m *MetricsCollectorAgentPool) collectAgentQueues(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), agentPoolId int64) { list, err := AzureDevopsClient.ListAgentPoolAgents(agentPoolId) if err != nil { logger.Error(err) return } - agentPoolUsageMetric := prometheusCommon.NewMetricsList() - agentPoolAgentMetric := prometheusCommon.NewMetricsList() - agentPoolAgentStatusMetric := prometheusCommon.NewMetricsList() - agentPoolAgentJobMetric := prometheusCommon.NewMetricsList() + agentPoolUsageMetric := m.Collector.GetMetricList("agentPoolUsage") + agentPoolAgentMetric := m.Collector.GetMetricList("agentPoolAgent") + agentPoolAgentStatusMetric := m.Collector.GetMetricList("agentPoolAgentStatus") + agentPoolAgentJobMetric := m.Collector.GetMetricList("agentPoolAgentJob") agentPoolSize := 0 agentPoolUsed := 0 @@ -203,9 +190,9 @@ func (m *MetricsCollectorAgentPool) collectAgentQueues(ctx context.Context, logg "provisioningState": agentPoolAgent.ProvisioningState, "maxParallelism": int64ToString(agentPoolAgent.MaxParallelism), "agentPoolAgentOs": agentPoolAgent.OsDescription, - "enabled": boolToString(agentPoolAgent.Enabled), + "enabled": to.BoolString(agentPoolAgent.Enabled), "status": agentPoolAgent.Status, - "hasAssignedRequest": boolToString(agentPoolAgent.AssignedRequest.RequestId > 0), + "hasAssignedRequest": to.BoolString(agentPoolAgent.AssignedRequest.RequestId > 0), } agentPoolAgentMetric.Add(infoLabels, 1) @@ -230,26 +217,23 @@ func (m *MetricsCollectorAgentPool) collectAgentQueues(ctx context.Context, logg } } + usage := float64(0) + if agentPoolSize > 0 { + usage = float64(agentPoolUsed) / float64(agentPoolSize) + } agentPoolUsageMetric.Add(prometheus.Labels{ "agentPoolID": int64ToString(agentPoolId), - }, float64(agentPoolUsed)/float64(agentPoolSize)) - - callback <- func() { - agentPoolUsageMetric.GaugeSet(m.prometheus.agentPoolUsage) - agentPoolAgentMetric.GaugeSet(m.prometheus.agentPoolAgent) - agentPoolAgentStatusMetric.GaugeSet(m.prometheus.agentPoolAgentStatus) - agentPoolAgentJobMetric.GaugeSet(m.prometheus.agentPoolAgentJob) - } + }, usage) } -func (m *MetricsCollectorAgentPool) collectAgentPoolJobs(ctx context.Context, logger *log.Entry, callback chan<- func(), agentPoolId int64) { +func (m *MetricsCollectorAgentPool) collectAgentPoolJobs(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), agentPoolId int64) { list, err := AzureDevopsClient.ListAgentPoolJobs(agentPoolId) if err != nil { logger.Error(err) return } - agentPoolQueueLengthMetric := prometheusCommon.NewMetricsList() + agentPoolQueueLengthMetric := m.Collector.GetMetricList("agentPoolQueueLength") notStartedJobCount := 0 @@ -264,8 +248,4 @@ func (m *MetricsCollectorAgentPool) collectAgentPoolJobs(ctx context.Context, lo } agentPoolQueueLengthMetric.Add(infoLabels, float64(notStartedJobCount)) - - callback <- func() { - agentPoolQueueLengthMetric.GaugeSet(m.prometheus.agentPoolQueueLength) - } } diff --git a/metrics_build.go b/metrics_build.go index eb6a76c..41efdb6 100644 --- a/metrics_build.go +++ b/metrics_build.go @@ -6,14 +6,14 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorBuild struct { - CollectorProcessorProject + collector.Processor prometheus struct { build *prometheus.GaugeVec @@ -31,8 +31,8 @@ type MetricsCollectorBuild struct { } } -func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorBuild) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.build = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -55,7 +55,7 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "url", }, ) - prometheus.MustRegister(m.prometheus.build) + m.Collector.RegisterMetricList("build", m.prometheus.build, true) m.prometheus.buildStatus = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -71,7 +71,7 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.buildStatus) + m.Collector.RegisterMetricList("buildStatus", m.prometheus.buildStatus, true) m.prometheus.buildStage = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -90,7 +90,7 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.buildStage) + m.Collector.RegisterMetricList("buildStage", m.prometheus.buildStage, true) m.prometheus.buildPhase = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -110,7 +110,7 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.buildPhase) + m.Collector.RegisterMetricList("buildPhase", m.prometheus.buildPhase, true) m.prometheus.buildJob = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -130,7 +130,7 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.buildJob) + m.Collector.RegisterMetricList("buildJob", m.prometheus.buildJob, true) m.prometheus.buildTask = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -150,7 +150,7 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.buildTask) + m.Collector.RegisterMetricList("buildTask", m.prometheus.buildTask, true) m.prometheus.buildDefinition = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -166,33 +166,31 @@ func (m *MetricsCollectorBuild) Setup(collector *CollectorProject) { "url", }, ) - prometheus.MustRegister(m.prometheus.buildDefinition) + m.Collector.RegisterMetricList("buildDefinition", m.prometheus.buildDefinition, true) } -func (m *MetricsCollectorBuild) Reset() { - m.prometheus.build.Reset() - m.prometheus.buildDefinition.Reset() - m.prometheus.buildStatus.Reset() - m.prometheus.buildStage.Reset() - m.prometheus.buildPhase.Reset() - m.prometheus.buildJob.Reset() - m.prometheus.buildTask.Reset() -} +func (m *MetricsCollectorBuild) Reset() {} + +func (m *MetricsCollectorBuild) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() -func (m *MetricsCollectorBuild) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - m.collectDefinition(ctx, logger, callback, project) - m.collectBuilds(ctx, logger, callback, project) - m.collectBuildsTimeline(ctx, logger, callback, project) + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.collectDefinition(ctx, projectLogger, callback, project) + m.collectBuilds(ctx, projectLogger, callback, project) + m.collectBuildsTimeline(ctx, projectLogger, callback, project) + } } -func (m *MetricsCollectorBuild) collectDefinition(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorBuild) collectDefinition(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { list, err := AzureDevopsClient.ListBuildDefinitions(project.Id) if err != nil { logger.Error(err) return } - buildDefinitonMetric := prometheusCommon.NewMetricsList() + buildDefinitonMetric := m.Collector.GetMetricList("buildDefinition") for _, buildDefinition := range list.List { buildDefinitonMetric.Add(prometheus.Labels{ @@ -204,13 +202,9 @@ func (m *MetricsCollectorBuild) collectDefinition(ctx context.Context, logger *l "url": buildDefinition.Links.Web.Href, }, 1) } - - callback <- func() { - buildDefinitonMetric.GaugeSet(m.prometheus.buildDefinition) - } } -func (m *MetricsCollectorBuild) collectBuilds(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorBuild) collectBuilds(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { minTime := time.Now().Add(-opts.Limit.BuildHistoryDuration) list, err := AzureDevopsClient.ListBuildHistory(project.Id, minTime) @@ -219,8 +213,8 @@ func (m *MetricsCollectorBuild) collectBuilds(ctx context.Context, logger *log.E return } - buildMetric := prometheusCommon.NewMetricsList() - buildStatusMetric := prometheusCommon.NewMetricsList() + buildMetric := m.Collector.GetMetricList("build") + buildStatusMetric := m.Collector.GetMetricList("buildStatus") for _, build := range list.List { buildMetric.AddInfo(prometheus.Labels{ @@ -284,14 +278,9 @@ func (m *MetricsCollectorBuild) collectBuilds(ctx context.Context, logger *log.E "type": "jobDuration", }, build.FinishTime.Sub(build.StartTime)) } - - callback <- func() { - buildMetric.GaugeSet(m.prometheus.build) - buildStatusMetric.GaugeSet(m.prometheus.buildStatus) - } } -func (m *MetricsCollectorBuild) collectBuildsTimeline(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorBuild) collectBuildsTimeline(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { minTime := time.Now().Add(-opts.Limit.BuildHistoryDuration) list, err := AzureDevopsClient.ListBuildHistoryWithStatus(project.Id, minTime, "completed") if err != nil { @@ -299,10 +288,10 @@ func (m *MetricsCollectorBuild) collectBuildsTimeline(ctx context.Context, logge return } - buildStageMetric := prometheusCommon.NewMetricsList() - buildPhaseMetric := prometheusCommon.NewMetricsList() - buildJobMetric := prometheusCommon.NewMetricsList() - buildTaskMetric := prometheusCommon.NewMetricsList() + buildStageMetric := m.Collector.GetMetricList("buildStage") + buildPhaseMetric := m.Collector.GetMetricList("buildPhase") + buildJobMetric := m.Collector.GetMetricList("buildJob") + buildTaskMetric := m.Collector.GetMetricList("buildTask") for _, build := range list.List { timelineRecordList, _ := AzureDevopsClient.ListBuildTimeline(project.Id, int64ToString(build.Id)) @@ -621,11 +610,4 @@ func (m *MetricsCollectorBuild) collectBuildsTimeline(ctx context.Context, logge } } } - - callback <- func() { - buildStageMetric.GaugeSet(m.prometheus.buildStage) - buildPhaseMetric.GaugeSet(m.prometheus.buildPhase) - buildJobMetric.GaugeSet(m.prometheus.buildJob) - buildTaskMetric.GaugeSet(m.prometheus.buildTask) - } } diff --git a/metrics_deployment.go b/metrics_deployment.go index 36c20bf..4d930f5 100644 --- a/metrics_deployment.go +++ b/metrics_deployment.go @@ -4,14 +4,14 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorDeployment struct { - CollectorProcessorProject + collector.Processor prometheus struct { deployment *prometheus.GaugeVec @@ -19,8 +19,8 @@ type MetricsCollectorDeployment struct { } } -func (m *MetricsCollectorDeployment) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorDeployment) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.deployment = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -44,7 +44,7 @@ func (m *MetricsCollectorDeployment) Setup(collector *CollectorProject) { "approvedBy", }, ) - prometheus.MustRegister(m.prometheus.deployment) + m.Collector.RegisterMetricList("deployment", m.prometheus.deployment, true) m.prometheus.deploymentStatus = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -57,7 +57,7 @@ func (m *MetricsCollectorDeployment) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.deploymentStatus) + m.Collector.RegisterMetricList("deploymentStatus", m.prometheus.deploymentStatus, true) } func (m *MetricsCollectorDeployment) Reset() { @@ -65,18 +65,28 @@ func (m *MetricsCollectorDeployment) Reset() { m.prometheus.deploymentStatus.Reset() } -func (m *MetricsCollectorDeployment) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorDeployment) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() + + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.collectDeployments(ctx, projectLogger, callback, project) + } +} + +func (m *MetricsCollectorDeployment) collectDeployments(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { list, err := AzureDevopsClient.ListReleaseDefinitions(project.Id) if err != nil { logger.Error(err) return } - deploymentMetric := prometheusCommon.NewMetricsList() - deploymentStatusMetric := prometheusCommon.NewMetricsList() + deploymentMetric := m.Collector.GetMetricList("deployment") + deploymentStatusMetric := m.Collector.GetMetricList("deploymentStatus") for _, releaseDefinition := range list.List { - contextLogger := logger.WithField("releaseDefinition", releaseDefinition.Name) + contextLogger := logger.With(zap.String("releaseDefinition", releaseDefinition.Name)) deploymentList, err := AzureDevopsClient.ListReleaseDeployments(project.Id, releaseDefinition.Id) if err != nil { @@ -139,9 +149,4 @@ func (m *MetricsCollectorDeployment) Collect(ctx context.Context, logger *log.En } } } - - callback <- func() { - deploymentMetric.GaugeSet(m.prometheus.deployment) - deploymentStatusMetric.GaugeSet(m.prometheus.deploymentStatus) - } } diff --git a/metrics_general.go b/metrics_general.go deleted file mode 100644 index 59d1448..0000000 --- a/metrics_general.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "context" - - "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" -) - -type MetricsCollectorGeneral struct { - CollectorProcessorGeneral - - prometheus struct { - stats *prometheus.GaugeVec - } -} - -func (m *MetricsCollectorGeneral) Setup(collector *CollectorGeneral) { - m.CollectorReference = collector - - m.prometheus.stats = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "azure_devops_stats", - Help: "Azure DevOps statistics", - }, - []string{ - "name", - "type", - }, - ) - prometheus.MustRegister(m.prometheus.stats) -} - -func (m *MetricsCollectorGeneral) Reset() { - m.prometheus.stats.Reset() -} - -func (m *MetricsCollectorGeneral) Collect(ctx context.Context, logger *log.Entry, callback chan<- func()) { - m.collectCollectorStats(ctx, logger, callback) -} - -func (m *MetricsCollectorGeneral) collectCollectorStats(ctx context.Context, logger *log.Entry, callback chan<- func()) { - statsMetrics := prometheusCommon.NewMetricsList() - - for _, collector := range collectorGeneralList { - if collector.LastScrapeDuration != nil { - statsMetrics.AddDuration(prometheus.Labels{ - "name": collector.Name, - "type": "collectorDuration", - }, *collector.LastScrapeDuration) - } - } - - for _, collector := range collectorAgentPoolList { - if collector.LastScrapeDuration != nil { - statsMetrics.AddDuration(prometheus.Labels{ - "name": collector.Name, - "type": "collectorDuration", - }, *collector.LastScrapeDuration) - } - } - - for _, collector := range collectorProjectList { - if collector.LastScrapeDuration != nil { - statsMetrics.AddDuration(prometheus.Labels{ - "name": collector.Name, - "type": "collectorDuration", - }, *collector.LastScrapeDuration) - } - } - - for _, collector := range collectorQueryList { - if collector.LastScrapeDuration != nil { - statsMetrics.AddDuration(prometheus.Labels{ - "name": collector.Name, - "type": "collectorDuration", - }, *collector.LastScrapeDuration) - } - } - - callback <- func() { - statsMetrics.GaugeSet(m.prometheus.stats) - } -} diff --git a/metrics_latest_build.go b/metrics_latest_build.go index 8963565..d963f4d 100644 --- a/metrics_latest_build.go +++ b/metrics_latest_build.go @@ -4,14 +4,14 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorLatestBuild struct { - CollectorProcessorProject + collector.Processor prometheus struct { build *prometheus.GaugeVec @@ -19,8 +19,8 @@ type MetricsCollectorLatestBuild struct { } } -func (m *MetricsCollectorLatestBuild) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorLatestBuild) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.build = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -43,7 +43,7 @@ func (m *MetricsCollectorLatestBuild) Setup(collector *CollectorProject) { "url", }, ) - prometheus.MustRegister(m.prometheus.build) + m.Collector.RegisterMetricList("build", m.prometheus.build, true) m.prometheus.buildStatus = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -57,23 +57,30 @@ func (m *MetricsCollectorLatestBuild) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.buildStatus) + m.Collector.RegisterMetricList("buildStatus", m.prometheus.buildStatus, true) } -func (m *MetricsCollectorLatestBuild) Reset() { - m.prometheus.build.Reset() - m.prometheus.buildStatus.Reset() +func (m *MetricsCollectorLatestBuild) Reset() {} + +func (m *MetricsCollectorLatestBuild) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() + + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.collectLatestBuilds(ctx, projectLogger, project, callback) + } } -func (m *MetricsCollectorLatestBuild) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorLatestBuild) collectLatestBuilds(ctx context.Context, logger *zap.SugaredLogger, project devopsClient.Project, callback chan<- func()) { list, err := AzureDevopsClient.ListLatestBuilds(project.Id) if err != nil { logger.Error(err) return } - buildMetric := prometheusCommon.NewMetricsList() - buildStatusMetric := prometheusCommon.NewMetricsList() + buildMetric := m.Collector.GetMetricList("build") + buildStatusMetric := m.Collector.GetMetricList("buildStatus") for _, build := range list.List { buildMetric.AddInfo(prometheus.Labels{ @@ -120,9 +127,4 @@ func (m *MetricsCollectorLatestBuild) Collect(ctx context.Context, logger *log.E "type": "jobDuration", }, build.FinishTime.Sub(build.StartTime)) } - - callback <- func() { - buildMetric.GaugeSet(m.prometheus.build) - buildStatusMetric.GaugeSet(m.prometheus.buildStatus) - } } diff --git a/metrics_project.go b/metrics_project.go index b696a64..33aba2f 100644 --- a/metrics_project.go +++ b/metrics_project.go @@ -4,14 +4,14 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorProject struct { - CollectorProcessorProject + collector.Processor prometheus struct { project *prometheus.GaugeVec @@ -19,8 +19,8 @@ type MetricsCollectorProject struct { } } -func (m *MetricsCollectorProject) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorProject) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.project = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -32,26 +32,26 @@ func (m *MetricsCollectorProject) Setup(collector *CollectorProject) { "projectName", }, ) - prometheus.MustRegister(m.prometheus.project) + m.Collector.RegisterMetricList("project", m.prometheus.project, true) } -func (m *MetricsCollectorProject) Reset() { - m.prometheus.project.Reset() -} +func (m *MetricsCollectorProject) Reset() {} + +func (m *MetricsCollectorProject) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() -func (m *MetricsCollectorProject) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - m.collectProject(ctx, logger, callback, project) + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.collectProject(ctx, projectLogger, callback, project) + } } -func (m *MetricsCollectorProject) collectProject(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - projectMetric := prometheusCommon.NewMetricsList() +func (m *MetricsCollectorProject) collectProject(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { + projectMetric := m.Collector.GetMetricList("project") projectMetric.AddInfo(prometheus.Labels{ "projectID": project.Id, "projectName": project.Name, }) - - callback <- func() { - projectMetric.GaugeSet(m.prometheus.project) - } } diff --git a/metrics_pullrequest.go b/metrics_pullrequest.go index 5595816..f818614 100644 --- a/metrics_pullrequest.go +++ b/metrics_pullrequest.go @@ -4,14 +4,15 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "github.com/webdevops/go-common/utils/to" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorPullRequest struct { - CollectorProcessorProject + collector.Processor prometheus struct { pullRequest *prometheus.GaugeVec @@ -20,8 +21,8 @@ type MetricsCollectorPullRequest struct { } } -func (m *MetricsCollectorPullRequest) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorPullRequest) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.pullRequest = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -41,7 +42,7 @@ func (m *MetricsCollectorPullRequest) Setup(collector *CollectorProject) { "creator", }, ) - prometheus.MustRegister(m.prometheus.pullRequest) + m.Collector.RegisterMetricList("pullRequest", m.prometheus.pullRequest, true) m.prometheus.pullRequestStatus = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -55,7 +56,7 @@ func (m *MetricsCollectorPullRequest) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.pullRequestStatus) + m.Collector.RegisterMetricList("pullRequestStatus", m.prometheus.pullRequestStatus, true) m.prometheus.pullRequestLabel = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -70,37 +71,39 @@ func (m *MetricsCollectorPullRequest) Setup(collector *CollectorProject) { "active", }, ) - prometheus.MustRegister(m.prometheus.pullRequestLabel) + m.Collector.RegisterMetricList("pullRequestLabel", m.prometheus.pullRequestLabel, true) } -func (m *MetricsCollectorPullRequest) Reset() { - m.prometheus.pullRequest.Reset() - m.prometheus.pullRequestStatus.Reset() - m.prometheus.pullRequestLabel.Reset() +func (m *MetricsCollectorPullRequest) Reset() {} -} +func (m *MetricsCollectorPullRequest) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() -func (m *MetricsCollectorPullRequest) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - for _, repository := range project.RepositoryList.List { - if repository.Disabled() { - continue - } + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + + for _, repository := range project.RepositoryList.List { + if repository.Disabled() { + continue + } - contextLogger := logger.WithField("repository", repository.Name) - m.collectPullRequests(ctx, contextLogger, callback, project, repository) + repoLogger := projectLogger.With(zap.String("repository", repository.Name)) + m.collectPullRequests(ctx, repoLogger, callback, project, repository) + } } } -func (m *MetricsCollectorPullRequest) collectPullRequests(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project, repository devopsClient.Repository) { +func (m *MetricsCollectorPullRequest) collectPullRequests(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project, repository devopsClient.Repository) { list, err := AzureDevopsClient.ListPullrequest(project.Id, repository.Id) if err != nil { logger.Error(err) return } - pullRequestMetric := prometheusCommon.NewMetricsList() - pullRequestStatusMetric := prometheusCommon.NewMetricsList() - pullRequestLabelMetric := prometheusCommon.NewMetricsList() + pullRequestMetric := m.Collector.GetMetricList("pullRequest") + pullRequestStatusMetric := m.Collector.GetMetricList("pullRequestStatus") + pullRequestLabelMetric := m.Collector.GetMetricList("pullRequestLabel") for _, pullRequest := range list.List { voteSummary := pullRequest.GetVoteSummary() @@ -113,7 +116,7 @@ func (m *MetricsCollectorPullRequest) collectPullRequests(ctx context.Context, l "status": pullRequest.Status, "voteStatus": voteSummary.HumanizeString(), "creator": pullRequest.CreatedBy.DisplayName, - "isDraft": boolToString(pullRequest.IsDraft), + "isDraft": to.BoolString(pullRequest.IsDraft), "sourceBranch": pullRequest.SourceRefName, "targetBranch": pullRequest.TargetRefName, }) @@ -131,14 +134,8 @@ func (m *MetricsCollectorPullRequest) collectPullRequests(ctx context.Context, l "repositoryID": repository.Id, "pullrequestID": int64ToString(pullRequest.Id), "label": label.Name, - "active": boolToString(label.Active), + "active": to.BoolString(label.Active), }) } } - - callback <- func() { - pullRequestMetric.GaugeSet(m.prometheus.pullRequest) - pullRequestStatusMetric.GaugeSet(m.prometheus.pullRequestStatus) - pullRequestLabelMetric.GaugeSet(m.prometheus.pullRequestLabel) - } } diff --git a/metrics_query.go b/metrics_query.go index a926567..376d086 100644 --- a/metrics_query.go +++ b/metrics_query.go @@ -5,12 +5,12 @@ import ( "strings" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" ) type MetricsCollectorQuery struct { - CollectorProcessorQuery + collector.Processor prometheus struct { workItemCount *prometheus.GaugeVec @@ -18,8 +18,8 @@ type MetricsCollectorQuery struct { } } -func (m *MetricsCollectorQuery) Setup(collector *CollectorQuery) { - m.CollectorReference = collector +func (m *MetricsCollectorQuery) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.workItemCount = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -32,7 +32,7 @@ func (m *MetricsCollectorQuery) Setup(collector *CollectorQuery) { "queryPath", }, ) - prometheus.MustRegister(m.prometheus.workItemCount) + m.Collector.RegisterMetricList("workItemCount", m.prometheus.workItemCount, true) m.prometheus.workItemData = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -51,23 +51,28 @@ func (m *MetricsCollectorQuery) Setup(collector *CollectorQuery) { "closedDate", }, ) - prometheus.MustRegister(m.prometheus.workItemData) + m.Collector.RegisterMetricList("workItemData", m.prometheus.workItemData, true) } -func (m *MetricsCollectorQuery) Reset() { - m.prometheus.workItemCount.Reset() -} +func (m *MetricsCollectorQuery) Reset() {} + +func (m *MetricsCollectorQuery) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() + + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) -func (m *MetricsCollectorQuery) Collect(ctx context.Context, logger *log.Entry, callback chan<- func()) { - for _, query := range m.CollectorReference.QueryList { - queryPair := strings.Split(query, "@") - m.collectQueryResults(ctx, logger, callback, queryPair[0], queryPair[1]) + for _, query := range opts.AzureDevops.QueriesWithProjects { + queryPair := strings.Split(query, "@") + m.collectQueryResults(ctx, projectLogger, callback, queryPair[0], queryPair[1]) + } } } -func (m *MetricsCollectorQuery) collectQueryResults(ctx context.Context, logger *log.Entry, callback chan<- func(), queryPath string, projectID string) { - workItemsMetric := prometheusCommon.NewMetricsList() - workItemsDataMetric := prometheusCommon.NewMetricsList() +func (m *MetricsCollectorQuery) collectQueryResults(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), queryPath string, projectID string) { + workItemsMetric := m.Collector.GetMetricList("workItemCount") + workItemsDataMetric := m.Collector.GetMetricList("workItemData") workItemInfoList, err := AzureDevopsClient.QueryWorkItems(queryPath, projectID) if err != nil { @@ -99,9 +104,4 @@ func (m *MetricsCollectorQuery) collectQueryResults(ctx context.Context, logger "closedDate": workItem.Fields.ClosedDate, }) } - - callback <- func() { - workItemsMetric.GaugeSet(m.prometheus.workItemCount) - workItemsDataMetric.GaugeSet(m.prometheus.workItemData) - } } diff --git a/metrics_release.go b/metrics_release.go index 6d97198..c52b00c 100644 --- a/metrics_release.go +++ b/metrics_release.go @@ -5,14 +5,15 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "github.com/webdevops/go-common/utils/to" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorRelease struct { - CollectorProcessorProject + collector.Processor prometheus struct { release *prometheus.GaugeVec @@ -26,8 +27,8 @@ type MetricsCollectorRelease struct { } } -func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorRelease) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.release = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -46,7 +47,7 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "url", }, ) - prometheus.MustRegister(m.prometheus.release) + m.Collector.RegisterMetricList("release", m.prometheus.release, true) m.prometheus.releaseArtifact = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -65,7 +66,7 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "version", }, ) - prometheus.MustRegister(m.prometheus.releaseArtifact) + m.Collector.RegisterMetricList("releaseArtifact", m.prometheus.releaseArtifact, true) m.prometheus.releaseEnvironment = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -83,7 +84,7 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "rank", }, ) - prometheus.MustRegister(m.prometheus.releaseEnvironment) + m.Collector.RegisterMetricList("releaseEnvironment", m.prometheus.releaseEnvironment, true) m.prometheus.releaseEnvironmentStatus = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -98,7 +99,7 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.releaseEnvironmentStatus) + m.Collector.RegisterMetricList("releaseEnvironmentStatus", m.prometheus.releaseEnvironmentStatus, true) m.prometheus.releaseEnvironmentApproval = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -120,7 +121,7 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "approvedBy", }, ) - prometheus.MustRegister(m.prometheus.releaseEnvironmentApproval) + m.Collector.RegisterMetricList("releaseEnvironmentApproval", m.prometheus.releaseEnvironmentApproval, true) m.prometheus.releaseDefinition = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -136,7 +137,7 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "url", }, ) - prometheus.MustRegister(m.prometheus.releaseDefinition) + m.Collector.RegisterMetricList("releaseDefinition", m.prometheus.releaseDefinition, true) m.prometheus.releaseDefinitionEnvironment = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -154,35 +155,36 @@ func (m *MetricsCollectorRelease) Setup(collector *CollectorProject) { "badgeUrl", }, ) - prometheus.MustRegister(m.prometheus.releaseDefinitionEnvironment) + m.Collector.RegisterMetricList("releaseDefinitionEnvironment", m.prometheus.releaseDefinitionEnvironment, true) } -func (m *MetricsCollectorRelease) Reset() { - m.prometheus.release.Reset() - m.prometheus.releaseArtifact.Reset() - m.prometheus.releaseEnvironment.Reset() - m.prometheus.releaseEnvironmentApproval.Reset() - m.prometheus.releaseEnvironmentStatus.Reset() +func (m *MetricsCollectorRelease) Reset() {} - m.prometheus.releaseDefinition.Reset() - m.prometheus.releaseDefinitionEnvironment.Reset() +func (m *MetricsCollectorRelease) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() + + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.collectReleases(ctx, projectLogger, callback, project) + } } -func (m *MetricsCollectorRelease) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorRelease) collectReleases(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { list, err := AzureDevopsClient.ListReleaseDefinitions(project.Id) if err != nil { logger.Error(err) return } - releaseDefinitionMetric := prometheusCommon.NewMetricsList() - releaseDefinitionEnvironmentMetric := prometheusCommon.NewMetricsList() + releaseDefinitionMetric := m.Collector.GetMetricList("releaseDefinition") + releaseDefinitionEnvironmentMetric := m.Collector.GetMetricList("releaseDefinitionEnvironment") - releaseMetric := prometheusCommon.NewMetricsList() - releaseArtifactMetric := prometheusCommon.NewMetricsList() - releaseEnvironmentMetric := prometheusCommon.NewMetricsList() - releaseEnvironmentApprovalMetric := prometheusCommon.NewMetricsList() - releaseEnvironmentStatusMetric := prometheusCommon.NewMetricsList() + releaseMetric := m.Collector.GetMetricList("release") + releaseArtifactMetric := m.Collector.GetMetricList("releaseArtifact") + releaseEnvironmentMetric := m.Collector.GetMetricList("releaseEnvironment") + releaseEnvironmentApprovalMetric := m.Collector.GetMetricList("releaseEnvironmentApproval") + releaseEnvironmentStatusMetric := m.Collector.GetMetricList("releaseEnvironmentStatus") for _, releaseDefinition := range list.List { // -------------------------------------- @@ -229,7 +231,7 @@ func (m *MetricsCollectorRelease) Collect(ctx context.Context, logger *log.Entry "releaseName": release.Name, "status": release.Status, "reason": release.Reason, - "result": boolToString(release.Result), + "result": to.BoolString(release.Result), "url": release.Links.Web.Href, }) @@ -296,7 +298,7 @@ func (m *MetricsCollectorRelease) Collect(ctx context.Context, logger *log.Entry "environmentID": int64ToString(environment.DefinitionEnvironmentId), "approvalType": approval.ApprovalType, "status": approval.Status, - "isAutomated": boolToString(approval.IsAutomated), + "isAutomated": to.BoolString(approval.IsAutomated), "trialNumber": int64ToString(approval.TrialNumber), "attempt": int64ToString(approval.Attempt), "rank": int64ToString(approval.Rank), @@ -318,7 +320,7 @@ func (m *MetricsCollectorRelease) Collect(ctx context.Context, logger *log.Entry "environmentID": int64ToString(environment.DefinitionEnvironmentId), "approvalType": approval.ApprovalType, "status": approval.Status, - "isAutomated": boolToString(approval.IsAutomated), + "isAutomated": to.BoolString(approval.IsAutomated), "trialNumber": int64ToString(approval.TrialNumber), "attempt": int64ToString(approval.Attempt), "rank": int64ToString(approval.Rank), @@ -328,15 +330,4 @@ func (m *MetricsCollectorRelease) Collect(ctx context.Context, logger *log.Entry } } } - - callback <- func() { - releaseDefinitionMetric.GaugeSet(m.prometheus.releaseDefinition) - releaseDefinitionEnvironmentMetric.GaugeSet(m.prometheus.releaseDefinitionEnvironment) - - releaseMetric.GaugeSet(m.prometheus.release) - releaseArtifactMetric.GaugeSet(m.prometheus.releaseArtifact) - releaseEnvironmentMetric.GaugeSet(m.prometheus.releaseEnvironment) - releaseEnvironmentApprovalMetric.GaugeSet(m.prometheus.releaseEnvironmentApproval) - releaseEnvironmentStatusMetric.GaugeSet(m.prometheus.releaseEnvironmentStatus) - } } diff --git a/metrics_repository.go b/metrics_repository.go index 35baac8..e410b6f 100644 --- a/metrics_repository.go +++ b/metrics_repository.go @@ -2,17 +2,18 @@ package main import ( "context" - "sync" + "time" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/remeh/sizedwaitgroup" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorRepository struct { - CollectorProcessorProject + collector.Processor prometheus struct { repository *prometheus.GaugeVec @@ -22,8 +23,8 @@ type MetricsCollectorRepository struct { } } -func (m *MetricsCollectorRepository) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorRepository) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.repository = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -36,7 +37,7 @@ func (m *MetricsCollectorRepository) Setup(collector *CollectorProject) { "repositoryName", }, ) - prometheus.MustRegister(m.prometheus.repository) + m.Collector.RegisterMetricList("repository", m.prometheus.repository, true) m.prometheus.repositoryStats = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -49,7 +50,7 @@ func (m *MetricsCollectorRepository) Setup(collector *CollectorProject) { "type", }, ) - prometheus.MustRegister(m.prometheus.repositoryStats) + m.Collector.RegisterMetricList("repositoryStats", m.prometheus.repositoryStats, true) m.prometheus.repositoryCommits = prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -61,7 +62,7 @@ func (m *MetricsCollectorRepository) Setup(collector *CollectorProject) { "repositoryID", }, ) - prometheus.MustRegister(m.prometheus.repositoryCommits) + m.Collector.RegisterMetricList("repositoryCommits", m.prometheus.repositoryCommits, false) m.prometheus.repositoryPushes = prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -73,40 +74,45 @@ func (m *MetricsCollectorRepository) Setup(collector *CollectorProject) { "repositoryID", }, ) - prometheus.MustRegister(m.prometheus.repositoryPushes) + m.Collector.RegisterMetricList("repositoryPushes", m.prometheus.repositoryPushes, false) } -func (m *MetricsCollectorRepository) Reset() { - m.prometheus.repository.Reset() - m.prometheus.repositoryStats.Reset() -} +func (m *MetricsCollectorRepository) Reset() {} -func (m *MetricsCollectorRepository) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - wg := sync.WaitGroup{} +func (m *MetricsCollectorRepository) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() - for _, repository := range project.RepositoryList.List { - if repository.Disabled() { - continue - } + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) - wg.Add(1) - go func(ctx context.Context, callback chan<- func(), project devopsClient.Project, repository devopsClient.Repository) { - defer wg.Done() - contextLogger := logger.WithField("repository", repository.Name) - m.collectRepository(ctx, contextLogger, callback, project, repository) - }(ctx, callback, project, repository) - } + wg := sizedwaitgroup.New(5) + for _, repository := range project.RepositoryList.List { + if repository.Disabled() { + continue + } - wg.Wait() + wg.Add() + go func(ctx context.Context, callback chan<- func(), project devopsClient.Project, repository devopsClient.Repository) { + defer wg.Done() + repositoryLogger := projectLogger.With(zap.String("repository", repository.Name)) + m.collectRepository(ctx, repositoryLogger, callback, project, repository) + }(ctx, callback, project, repository) + } + wg.Wait() + } } -func (m *MetricsCollectorRepository) collectRepository(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project, repository devopsClient.Repository) { - fromTime := *m.CollectorReference.collectionLastTime +func (m *MetricsCollectorRepository) collectRepository(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project, repository devopsClient.Repository) { + fromTime := time.Now().Add(-*m.Collector.GetScapeTime()) + if val := m.Collector.GetLastScapeTime(); val != nil { + fromTime = *val + } - repositoryMetric := prometheusCommon.NewMetricsList() - repositoryStatsMetric := prometheusCommon.NewMetricsList() - repositoryCommitsMetric := prometheusCommon.NewMetricsList() - repositoryPushesMetric := prometheusCommon.NewMetricsList() + repositoryMetric := m.Collector.GetMetricList("repository") + repositoryStatsMetric := m.Collector.GetMetricList("repositoryStats") + repositoryCommitsMetric := m.Collector.GetMetricList("repositoryCommits") + repositoryPushesMetric := m.Collector.GetMetricList("repositoryPushes") repositoryMetric.AddInfo(prometheus.Labels{ "projectID": project.Id, @@ -143,11 +149,4 @@ func (m *MetricsCollectorRepository) collectRepository(ctx context.Context, logg } else { logger.Error(err) } - - callback <- func() { - repositoryMetric.GaugeSet(m.prometheus.repository) - repositoryStatsMetric.GaugeSet(m.prometheus.repositoryStats) - repositoryCommitsMetric.CounterAdd(m.prometheus.repositoryCommits) - repositoryPushesMetric.CounterAdd(m.prometheus.repositoryPushes) - } } diff --git a/metrics_resourceusage.go b/metrics_resourceusage.go index a083fc1..6ba988e 100644 --- a/metrics_resourceusage.go +++ b/metrics_resourceusage.go @@ -4,12 +4,12 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - prometheusCommon "github.com/webdevops/go-common/prometheus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" ) type MetricsCollectorResourceUsage struct { - CollectorProcessorGeneral + collector.Processor prometheus struct { resourceUsageBuild *prometheus.GaugeVec @@ -17,8 +17,8 @@ type MetricsCollectorResourceUsage struct { } } -func (m *MetricsCollectorResourceUsage) Setup(collector *CollectorGeneral) { - m.CollectorReference = collector +func (m *MetricsCollectorResourceUsage) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) m.prometheus.resourceUsageBuild = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -29,7 +29,7 @@ func (m *MetricsCollectorResourceUsage) Setup(collector *CollectorGeneral) { "name", }, ) - prometheus.MustRegister(m.prometheus.resourceUsageBuild) + m.Collector.RegisterMetricList("resourceUsageBuild", m.prometheus.resourceUsageBuild, true) m.prometheus.resourceUsageLicense = prometheus.NewGaugeVec( prometheus.GaugeOpts{ @@ -40,27 +40,27 @@ func (m *MetricsCollectorResourceUsage) Setup(collector *CollectorGeneral) { "name", }, ) - prometheus.MustRegister(m.prometheus.resourceUsageLicense) + m.Collector.RegisterMetricList("resourceUsageLicense", m.prometheus.resourceUsageLicense, true) } -func (m *MetricsCollectorResourceUsage) Reset() { - m.prometheus.resourceUsageBuild.Reset() - m.prometheus.resourceUsageLicense.Reset() -} +func (m *MetricsCollectorResourceUsage) Reset() {} + +func (m *MetricsCollectorResourceUsage) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() -func (m *MetricsCollectorResourceUsage) Collect(ctx context.Context, logger *log.Entry, callback chan<- func()) { - m.CollectResourceUsageBuild(ctx, logger, callback) - m.CollectResourceUsageAgent(ctx, logger, callback) + m.collectResourceUsageBuild(ctx, logger, callback) + m.collectResourceUsageAgent(ctx, logger, callback) } -func (m *MetricsCollectorResourceUsage) CollectResourceUsageAgent(ctx context.Context, logger *log.Entry, callback chan<- func()) { +func (m *MetricsCollectorResourceUsage) collectResourceUsageAgent(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func()) { resourceUsage, err := AzureDevopsClient.GetResourceUsageAgent() if err != nil { logger.Error(err) return } - resourceUsageMetric := prometheusCommon.NewMetricsList() + resourceUsageMetric := m.Collector.GetMetricList("resourceUsageLicense") licenseDetails := resourceUsage.Data.Provider.TaskHubLicenseDetails @@ -111,20 +111,16 @@ func (m *MetricsCollectorResourceUsage) CollectResourceUsageAgent(ctx context.Co resourceUsageMetric.AddIfNotNil(prometheus.Labels{ "name": "TotalHostedLicenseCount", }, licenseDetails.TotalHostedLicenseCount) - - callback <- func() { - resourceUsageMetric.GaugeSet(m.prometheus.resourceUsageLicense) - } } -func (m *MetricsCollectorResourceUsage) CollectResourceUsageBuild(ctx context.Context, logger *log.Entry, callback chan<- func()) { +func (m *MetricsCollectorResourceUsage) collectResourceUsageBuild(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func()) { resourceUsage, err := AzureDevopsClient.GetResourceUsageBuild() if err != nil { logger.Error(err) return } - resourceUsageMetric := prometheusCommon.NewMetricsList() + resourceUsageMetric := m.Collector.GetMetricList("resourceUsageBuild") if resourceUsage.DistributedTaskAgents != nil { resourceUsageMetric.Add(prometheus.Labels{ @@ -149,9 +145,4 @@ func (m *MetricsCollectorResourceUsage) CollectResourceUsageBuild(ctx context.Co "name": "XamlControllers", }, float64(*resourceUsage.XamlControllers)) } - - callback <- func() { - resourceUsageMetric.GaugeSet(m.prometheus.resourceUsageBuild) - } - } diff --git a/metrics_stats.go b/metrics_stats.go index 9d7baee..b3840e5 100644 --- a/metrics_stats.go +++ b/metrics_stats.go @@ -5,13 +5,14 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" + "github.com/webdevops/go-common/prometheus/collector" + "go.uber.org/zap" devopsClient "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) type MetricsCollectorStats struct { - CollectorProcessorProject + collector.Processor prometheus struct { agentPoolBuildCount *prometheus.CounterVec @@ -27,8 +28,8 @@ type MetricsCollectorStats struct { } } -func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { - m.CollectorReference = collector +func (m *MetricsCollectorStats) Setup(collector *collector.Collector) { + m.Processor.Setup(collector) // ------------------------------------------ // AgentPool @@ -45,7 +46,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "result", }, ) - prometheus.MustRegister(m.prometheus.agentPoolBuildCount) + m.Collector.RegisterMetricList("agentPoolBuildCount", m.prometheus.agentPoolBuildCount, false) m.prometheus.agentPoolBuildWait = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -59,7 +60,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "result", }, ) - prometheus.MustRegister(m.prometheus.agentPoolBuildWait) + m.Collector.RegisterMetricList("agentPoolBuildWait", m.prometheus.agentPoolBuildWait, false) m.prometheus.agentPoolBuildDuration = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -73,7 +74,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "result", }, ) - prometheus.MustRegister(m.prometheus.agentPoolBuildDuration) + m.Collector.RegisterMetricList("agentPoolBuildDuration", m.prometheus.agentPoolBuildDuration, false) // ------------------------------------------ // Project @@ -90,7 +91,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "result", }, ) - prometheus.MustRegister(m.prometheus.projectBuildCount) + m.Collector.RegisterMetricList("projectBuildCount", m.prometheus.projectBuildCount, false) m.prometheus.projectBuildSuccess = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -102,7 +103,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "buildDefinitionID", }, ) - prometheus.MustRegister(m.prometheus.projectBuildSuccess) + m.Collector.RegisterMetricList("projectBuildSuccess", m.prometheus.projectBuildSuccess, false) m.prometheus.projectBuildWait = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -116,7 +117,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "result", }, ) - prometheus.MustRegister(m.prometheus.projectBuildWait) + m.Collector.RegisterMetricList("projectBuildWait", m.prometheus.projectBuildWait, false) m.prometheus.projectBuildDuration = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -130,7 +131,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "result", }, ) - prometheus.MustRegister(m.prometheus.projectBuildDuration) + m.Collector.RegisterMetricList("projectBuildDuration", m.prometheus.projectBuildDuration, false) m.prometheus.projectReleaseDuration = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -145,7 +146,7 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "status", }, ) - prometheus.MustRegister(m.prometheus.projectReleaseDuration) + m.Collector.RegisterMetricList("projectReleaseDuration", m.prometheus.projectReleaseDuration, false) m.prometheus.projectReleaseSuccess = prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -159,19 +160,27 @@ func (m *MetricsCollectorStats) Setup(collector *CollectorProject) { "definitionEnvironmentID", }, ) - prometheus.MustRegister(m.prometheus.projectReleaseSuccess) + m.Collector.RegisterMetricList("projectReleaseSuccess", m.prometheus.projectReleaseSuccess, false) } -func (m *MetricsCollectorStats) Reset() { -} +func (m *MetricsCollectorStats) Reset() {} + +func (m *MetricsCollectorStats) Collect(callback chan<- func()) { + ctx := m.Context() + logger := m.Logger() -func (m *MetricsCollectorStats) Collect(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - m.CollectBuilds(ctx, logger, callback, project) - m.CollectReleases(ctx, logger, callback, project) + for _, project := range AzureDevopsServiceDiscovery.ProjectList() { + projectLogger := logger.With(zap.String("project", project.Name)) + m.CollectBuilds(ctx, projectLogger, callback, project) + m.CollectReleases(ctx, projectLogger, callback, project) + } } -func (m *MetricsCollectorStats) CollectReleases(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { - minTime := *m.CollectorReference.collectionLastTime +func (m *MetricsCollectorStats) CollectReleases(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { + minTime := time.Now().Add(-*m.Collector.GetScapeTime()) + if val := m.Collector.GetLastScapeTime(); val != nil { + minTime = *val + } releaseList, err := AzureDevopsClient.ListReleaseHistory(project.Id, minTime) if err != nil { @@ -209,7 +218,7 @@ func (m *MetricsCollectorStats) CollectReleases(ctx context.Context, logger *log } } -func (m *MetricsCollectorStats) CollectBuilds(ctx context.Context, logger *log.Entry, callback chan<- func(), project devopsClient.Project) { +func (m *MetricsCollectorStats) CollectBuilds(ctx context.Context, logger *zap.SugaredLogger, callback chan<- func(), project devopsClient.Project) { minTime := time.Now().Add(-opts.Limit.BuildHistoryDuration) buildList, err := AzureDevopsClient.ListBuildHistoryWithStatus(project.Id, minTime, "completed") diff --git a/misc.go b/misc.go index d528a86..7fff5e7 100644 --- a/misc.go +++ b/misc.go @@ -5,13 +5,6 @@ import ( "time" ) -func boolToString(b bool) string { - if b { - return "true" - } - return "false" -} - func int64ToString(v int64) string { return strconv.FormatInt(v, 10) } diff --git a/servicediscovery.go b/servicediscovery.go index 82a3f7d..dadc1ab 100644 --- a/servicediscovery.go +++ b/servicediscovery.go @@ -5,7 +5,7 @@ import ( "time" cache "github.com/patrickmn/go-cache" - log "github.com/sirupsen/logrus" + "go.uber.org/zap" AzureDevops "github.com/webdevops/azure-devops-exporter/azure-devops-client" ) @@ -20,7 +20,7 @@ type ( cache *cache.Cache cacheExpiry time.Duration - logger *log.Entry + logger *zap.SugaredLogger lock struct { projectList sync.Mutex @@ -31,11 +31,9 @@ type ( func NewAzureDevopsServiceDiscovery() *azureDevopsServiceDiscovery { sd := &azureDevopsServiceDiscovery{} - sd.cacheExpiry = opts.Cache.Expiry + sd.cacheExpiry = opts.ServiceDiscovery.RefreshDuration sd.cache = cache.New(sd.cacheExpiry, time.Duration(1*time.Minute)) - sd.logger = log.WithFields(log.Fields{ - "component": "servicediscovery", - }) + sd.logger = logger.With(zap.String("component", "servicediscovery")) sd.logger.Infof("init AzureDevops servicediscovery with %v cache", sd.cacheExpiry.String()) return sd