@@ -558,31 +558,46 @@ func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[str
558
558
func addQueries (content []byte , pgVersion semver.Version , server * Server ) error {
559
559
metricMaps , newQueryOverrides , err := parseUserQueries (content )
560
560
if err != nil {
561
- return nil
561
+ return err
562
562
}
563
563
// Convert the loaded metric map into exporter representation
564
- partialExporterMap := makeDescMap (pgVersion , server .labels , metricMaps )
564
+ labels := make (prometheus.Labels )
565
+ server .labelsMtx .RLock ()
566
+ for key , value := range server .labels {
567
+ labels [key ] = value
568
+ }
569
+ server .labelsMtx .RUnlock ()
570
+
571
+ partialExporterMap := makeDescMap (pgVersion , labels , metricMaps )
565
572
566
573
// Merge the two maps (which are now quite flatteend)
567
574
for k , v := range partialExporterMap {
575
+ server .metricMapMtx .RLock ()
568
576
_ , found := server .metricMap [k ]
577
+ server .metricMapMtx .RUnlock ()
569
578
if found {
570
579
log .Debugln ("Overriding metric" , k , "from user YAML file." )
571
580
} else {
572
581
log .Debugln ("Adding new metric" , k , "from user YAML file." )
573
582
}
583
+ server .metricMapMtx .Lock ()
574
584
server .metricMap [k ] = v
585
+ server .metricMapMtx .Unlock ()
575
586
}
576
587
577
588
// Merge the query override map
578
589
for k , v := range newQueryOverrides {
590
+ server .queryOverridesMtx .RLock ()
579
591
_ , found := server .queryOverrides [k ]
592
+ server .queryOverridesMtx .RUnlock ()
580
593
if found {
581
594
log .Debugln ("Overriding query override" , k , "from user YAML file." )
582
595
} else {
583
596
log .Debugln ("Adding new query override" , k , "from user YAML file." )
584
597
}
598
+ server .queryOverridesMtx .Lock ()
585
599
server .queryOverrides [k ] = v
600
+ server .queryOverridesMtx .Unlock ()
586
601
}
587
602
return nil
588
603
}
@@ -848,21 +863,25 @@ type cachedMetrics struct {
848
863
// Server describes a connection to Postgres.
849
864
// Also it contains metrics map and query overrides.
850
865
type Server struct {
851
- db * sql.DB
852
- labels prometheus.Labels
853
- master bool
866
+ db * sql.DB
867
+ labels prometheus.Labels
868
+ labelsMtx sync.RWMutex
869
+ master bool
870
+ masterMtx sync.RWMutex
854
871
855
872
// Last version used to calculate metric map. If mismatch on scrape,
856
873
// then maps are recalculated.
857
- lastMapVersion semver.Version
874
+ lastMapVersion semver.Version
875
+ lastMapVersionMtx sync.RWMutex
858
876
// Currently active metric map
859
- metricMap map [string ]MetricMapNamespace
877
+ metricMap map [string ]MetricMapNamespace
878
+ metricMapMtx sync.RWMutex
860
879
// Currently active query overrides
861
- queryOverrides map [string ]string
862
- mappingMtx sync.RWMutex
880
+ queryOverrides map [string ]string
881
+ queryOverridesMtx sync.RWMutex
863
882
// Currently cached metrics
864
- metricCache map [string ]cachedMetrics
865
- cacheMtx sync.Mutex
883
+ metricCache map [string ]cachedMetrics
884
+ metricCacheMtx sync.Mutex
866
885
}
867
886
868
887
// ServerOpt configures a server.
@@ -932,12 +951,12 @@ func (s *Server) String() string {
932
951
933
952
// Scrape loads metrics.
934
953
func (s * Server ) Scrape (ch chan <- prometheus.Metric , disableSettingsMetrics bool ) error {
935
- s .mappingMtx .RLock ()
936
- defer s .mappingMtx .RUnlock ()
937
-
938
954
var err error
939
955
940
- if ! disableSettingsMetrics && s .master {
956
+ s .masterMtx .RLock ()
957
+ master := s .master
958
+ s .masterMtx .RUnlock ()
959
+ if ! disableSettingsMetrics && master {
941
960
if err = querySettings (ch , s ); err != nil {
942
961
err = fmt .Errorf ("error retrieving settings: %s" , err )
943
962
}
@@ -968,8 +987,6 @@ func NewServers(opts ...ServerOpt) *Servers {
968
987
969
988
// GetServer returns established connection from a collection.
970
989
func (s * Servers ) GetServer (dsn string ) (* Server , error ) {
971
- s .m .Lock ()
972
- defer s .m .Unlock ()
973
990
var err error
974
991
var ok bool
975
992
errCount := 0 // start at zero because we increment before doing work
@@ -979,17 +996,24 @@ func (s *Servers) GetServer(dsn string) (*Server, error) {
979
996
if errCount ++ ; errCount > retries {
980
997
return nil , err
981
998
}
999
+ s .m .Lock ()
982
1000
server , ok = s .servers [dsn ]
1001
+ s .m .Unlock ()
983
1002
if ! ok {
984
1003
server , err = NewServer (dsn , s .opts ... )
985
1004
if err != nil {
986
1005
time .Sleep (time .Duration (errCount ) * time .Second )
987
1006
continue
988
1007
}
1008
+ s .m .Lock ()
989
1009
s .servers [dsn ] = server
1010
+ s .m .Unlock ()
990
1011
}
1012
+
991
1013
if err = server .Ping (); err != nil {
1014
+ s .m .Lock ()
992
1015
delete (s .servers , dsn )
1016
+ s .m .Unlock ()
993
1017
time .Sleep (time .Duration (errCount ) * time .Second )
994
1018
continue
995
1019
}
@@ -1246,7 +1270,9 @@ func queryDatabases(server *Server) ([]string, error) {
1246
1270
// the scrape fails, and a slice of errors if they were non-fatal.
1247
1271
func queryNamespaceMapping (server * Server , namespace string , mapping MetricMapNamespace ) ([]prometheus.Metric , []error , error ) {
1248
1272
// Check for a query override for this namespace
1273
+ server .queryOverridesMtx .RLock ()
1249
1274
query , found := server .queryOverrides [namespace ]
1275
+ server .queryOverridesMtx .RUnlock ()
1250
1276
1251
1277
// Was this query disabled (i.e. nothing sensible can be queried on cu
1252
1278
// version of PostgreSQL?
@@ -1266,6 +1292,7 @@ func queryNamespaceMapping(server *Server, namespace string, mapping MetricMapNa
1266
1292
} else {
1267
1293
rows , err = server .db .Query (query ) // nolint: safesql
1268
1294
}
1295
+
1269
1296
if err != nil {
1270
1297
return []prometheus.Metric {}, []error {}, fmt .Errorf ("Error running query on database %q: %s %v" , server , namespace , err )
1271
1298
}
@@ -1326,7 +1353,13 @@ func queryNamespaceMapping(server *Server, namespace string, mapping MetricMapNa
1326
1353
} else {
1327
1354
// Unknown metric. Report as untyped if scan to float64 works, else note an error too.
1328
1355
metricLabel := fmt .Sprintf ("%s_%s" , namespace , columnName )
1329
- desc := prometheus .NewDesc (metricLabel , fmt .Sprintf ("Unknown metric from %s" , namespace ), mapping .labels , server .labels )
1356
+ serverLabels := make (prometheus.Labels )
1357
+ server .labelsMtx .RLock ()
1358
+ for key , value := range server .labels {
1359
+ serverLabels [key ] = value
1360
+ }
1361
+ server .labelsMtx .RUnlock ()
1362
+ desc := prometheus .NewDesc (metricLabel , fmt .Sprintf ("Unknown metric from %s" , namespace ), mapping .labels , serverLabels )
1330
1363
1331
1364
// Its not an error to fail here, since the values are
1332
1365
// unexpected anyway.
@@ -1351,19 +1384,24 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
1351
1384
1352
1385
scrapeStart := time .Now ()
1353
1386
1354
- for namespace , mapping := range server .metricMap {
1387
+ server .metricMapMtx .RLock ()
1388
+ metricMap := server .metricMap
1389
+ server .metricMapMtx .RUnlock ()
1390
+ for namespace , mapping := range metricMap {
1355
1391
log .Debugln ("Querying namespace: " , namespace )
1356
1392
1357
- if mapping .master && ! server .master {
1393
+ server .masterMtx .RLock ()
1394
+ master := server .master
1395
+ server .masterMtx .RUnlock ()
1396
+ if mapping .master && ! master {
1358
1397
log .Debugln ("Query skipped..." )
1359
1398
continue
1360
1399
}
1361
-
1362
1400
scrapeMetric := false
1363
1401
// Check if the metric is cached
1364
- server .cacheMtx .Lock ()
1402
+ server .metricCacheMtx .Lock ()
1365
1403
cachedMetric , found := server .metricCache [namespace ]
1366
- server .cacheMtx .Unlock ()
1404
+ server .metricCacheMtx .Unlock ()
1367
1405
// If found, check if needs refresh from cache
1368
1406
if found {
1369
1407
if scrapeStart .Sub (cachedMetric .lastScrape ).Seconds () > float64 (mapping .cacheSeconds ) {
@@ -1402,12 +1440,12 @@ func queryNamespaceMappings(ch chan<- prometheus.Metric, server *Server) map[str
1402
1440
if scrapeMetric {
1403
1441
// Only cache if metric is meaningfully cacheable
1404
1442
if mapping .cacheSeconds > 0 {
1405
- server .cacheMtx .Lock ()
1443
+ server .metricCacheMtx .Lock ()
1406
1444
server .metricCache [namespace ] = cachedMetrics {
1407
1445
metrics : metrics ,
1408
1446
lastScrape : scrapeStart ,
1409
1447
}
1410
- server .cacheMtx .Unlock ()
1448
+ server .metricCacheMtx .Unlock ()
1411
1449
}
1412
1450
}
1413
1451
}
@@ -1432,21 +1470,52 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server)
1432
1470
log .Warnf ("PostgreSQL version is lower on %q then our lowest supported version! Got %s minimum supported is %s." , server , semanticVersion , lowestSupportedVersion )
1433
1471
}
1434
1472
1473
+ metricMap := make (map [string ]MetricMapNamespace )
1474
+ server .metricMapMtx .RLock ()
1475
+ for key , value := range server .metricMap {
1476
+ metricMap [key ] = value
1477
+ }
1478
+ server .metricMapMtx .RUnlock ()
1479
+
1480
+ server .masterMtx .RLock ()
1481
+ master := server .master
1482
+ server .masterMtx .RUnlock ()
1483
+
1484
+ labels := make (prometheus.Labels )
1485
+ server .labelsMtx .RLock ()
1486
+ for key , value := range server .labels {
1487
+ labels [key ] = value
1488
+ }
1489
+ server .labelsMtx .RUnlock ()
1490
+
1435
1491
// Check if semantic version changed and recalculate maps if needed.
1436
- if semanticVersion .NE (server .lastMapVersion ) || server .metricMap == nil {
1492
+ server .lastMapVersionMtx .RLock ()
1493
+ isVersionNotEqual := semanticVersion .NE (server .lastMapVersion )
1494
+ server .lastMapVersionMtx .RUnlock ()
1495
+
1496
+ if isVersionNotEqual || metricMap == nil {
1437
1497
log .Infof ("Semantic Version Changed on %q: %s -> %s" , server , server .lastMapVersion , semanticVersion )
1438
- server .mappingMtx .Lock ()
1439
1498
1440
1499
// Get Default Metrics only for master database
1441
- if ! e .disableDefaultMetrics && server .master {
1442
- server .metricMap = makeDescMap (semanticVersion , server .labels , e .builtinMetricMaps )
1500
+ if ! e .disableDefaultMetrics && master {
1501
+ server .metricMapMtx .Lock ()
1502
+ server .metricMap = makeDescMap (semanticVersion , labels , e .builtinMetricMaps )
1503
+ server .metricMapMtx .Unlock ()
1504
+ server .queryOverridesMtx .Lock ()
1443
1505
server .queryOverrides = makeQueryOverrideMap (semanticVersion , queryOverrides )
1506
+ server .queryOverridesMtx .Unlock ()
1444
1507
} else {
1508
+ server .metricMapMtx .Lock ()
1445
1509
server .metricMap = make (map [string ]MetricMapNamespace )
1510
+ server .metricMapMtx .Unlock ()
1511
+ server .queryOverridesMtx .Lock ()
1446
1512
server .queryOverrides = make (map [string ]string )
1513
+ server .queryOverridesMtx .Unlock ()
1447
1514
}
1448
1515
1516
+ server .lastMapVersionMtx .Lock ()
1449
1517
server .lastMapVersion = semanticVersion
1518
+ server .lastMapVersionMtx .Unlock ()
1450
1519
1451
1520
if e .userQueriesPath [HR ] != "" || e .userQueriesPath [MR ] != "" || e .userQueriesPath [LR ] != "" {
1452
1521
// Clear the metric while a reload is happening
@@ -1458,18 +1527,17 @@ func (e *Exporter) checkMapVersions(ch chan<- prometheus.Metric, server *Server)
1458
1527
e .loadCustomQueries (res , semanticVersion , server )
1459
1528
}
1460
1529
}
1461
-
1462
- server .mappingMtx .Unlock ()
1463
1530
}
1464
1531
1465
1532
// Output the version as a special metric only for master database
1466
1533
versionDesc := prometheus .NewDesc (fmt .Sprintf ("%s_%s" , namespace , staticLabelName ),
1467
- "Version string as reported by postgres" , []string {"version" , "short_version" }, server . labels )
1534
+ "Version string as reported by postgres" , []string {"version" , "short_version" }, labels )
1468
1535
1469
- if ! e .disableDefaultMetrics && server . master {
1536
+ if ! e .disableDefaultMetrics && master {
1470
1537
ch <- prometheus .MustNewConstMetric (versionDesc ,
1471
1538
prometheus .UntypedValue , 1 , versionString , semanticVersion .String ())
1472
1539
}
1540
+
1473
1541
return nil
1474
1542
}
1475
1543
@@ -1574,7 +1642,9 @@ func (e *Exporter) discoverDatabaseDSNs() []string {
1574
1642
}
1575
1643
1576
1644
// If autoDiscoverDatabases is true, set first dsn as master database (Default: false)
1645
+ server .masterMtx .Lock ()
1577
1646
server .master = true
1647
+ server .masterMtx .Unlock ()
1578
1648
1579
1649
databaseNames , err := queryDatabases (server )
1580
1650
if err != nil {
@@ -1609,7 +1679,9 @@ func (e *Exporter) scrapeDSN(ch chan<- prometheus.Metric, dsn string) error {
1609
1679
1610
1680
// Check if autoDiscoverDatabases is false, set dsn as master database (Default: false)
1611
1681
if ! e .autoDiscoverDatabases {
1682
+ server .masterMtx .Lock ()
1612
1683
server .master = true
1684
+ server .masterMtx .Unlock ()
1613
1685
}
1614
1686
1615
1687
// Check if map versions need to be updated
0 commit comments