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