Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit 7716bf9

Browse files
bacherflatoulmedashpole
authored andcommitted
[receiver/prometheus] include scrape configs provided via scrape_config_files (open-telemetry#34897)
**Description:** This PR fixes a bug in the prometheus receiver where the scrape configs provided via `scrape_config_files` were not applied. Using `scrape_config_files` instead of providing the scrape configs directly does come with some limitations regarding the use of env vars, as also mentioned in open-telemetry#34786 (comment). **Link to tracking Issue:** open-telemetry#34786 **Testing:** Added unit tests --------- Signed-off-by: Florian Bacher <[email protected]> Co-authored-by: Antoine Toulme <[email protected]> Co-authored-by: David Ashpole <[email protected]>
1 parent 5a2cbc9 commit 7716bf9

File tree

7 files changed

+144
-3
lines changed

7 files changed

+144
-3
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: prometheusreceiver
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Fix the retrieval of scrape configurations by also considering scrape config files
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [34786]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

receiver/prometheusreceiver/config.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,24 @@ type Config struct {
4040

4141
// Validate checks the receiver configuration is valid.
4242
func (cfg *Config) Validate() error {
43-
if (cfg.PrometheusConfig == nil || len(cfg.PrometheusConfig.ScrapeConfigs) == 0) && cfg.TargetAllocator == nil {
43+
if !containsScrapeConfig(cfg) && cfg.TargetAllocator == nil {
4444
return errors.New("no Prometheus scrape_configs or target_allocator set")
4545
}
4646
return nil
4747
}
4848

49+
func containsScrapeConfig(cfg *Config) bool {
50+
if cfg.PrometheusConfig == nil {
51+
return false
52+
}
53+
scrapeConfigs, err := (*promconfig.Config)(cfg.PrometheusConfig).GetScrapeConfigs()
54+
if err != nil {
55+
return false
56+
}
57+
58+
return len(scrapeConfigs) > 0
59+
}
60+
4961
// PromConfig is a redeclaration of promconfig.Config because we need custom unmarshaling
5062
// as prometheus "config" uses `yaml` tags.
5163
type PromConfig promconfig.Config
@@ -87,7 +99,12 @@ func (cfg *PromConfig) Validate() error {
8799
return fmt.Errorf("unsupported features:\n\t%s", strings.Join(unsupportedFeatures, "\n\t"))
88100
}
89101

90-
for _, sc := range cfg.ScrapeConfigs {
102+
scrapeConfigs, err := (*promconfig.Config)(cfg).GetScrapeConfigs()
103+
if err != nil {
104+
return err
105+
}
106+
107+
for _, sc := range scrapeConfigs {
91108
if err := validateHTTPClientConfig(&sc.HTTPClientConfig); err != nil {
92109
return err
93110
}

receiver/prometheusreceiver/config_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,19 @@ func TestLoadTargetAllocatorConfig(t *testing.T) {
106106
assert.Equal(t, promModel.Duration(5*time.Second), r2.PrometheusConfig.ScrapeConfigs[0].ScrapeInterval)
107107
}
108108

109+
func TestValidateConfigWithScrapeConfigFiles(t *testing.T) {
110+
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config_scrape_config_files.yaml"))
111+
require.NoError(t, err)
112+
factory := NewFactory()
113+
cfg := factory.CreateDefaultConfig()
114+
115+
sub, err := cm.Sub(component.NewIDWithName(metadata.Type, "").String())
116+
require.NoError(t, err)
117+
require.NoError(t, sub.Unmarshal(cfg))
118+
119+
require.NoError(t, component.ValidateConfig(cfg))
120+
}
121+
109122
func TestLoadConfigFailsOnUnknownSection(t *testing.T) {
110123
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "invalid-config-section.yaml"))
111124
require.NoError(t, err)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package prometheusreceiver
5+
6+
import (
7+
"fmt"
8+
"os"
9+
"testing"
10+
11+
"github.com/prometheus/prometheus/config"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
"go.opentelemetry.io/collector/pdata/pmetric"
15+
semconv "go.opentelemetry.io/collector/semconv/v1.27.0"
16+
"gopkg.in/yaml.v2"
17+
)
18+
19+
var scrapeFileTargetPage = `
20+
# A simple counter
21+
# TYPE foo counter
22+
foo1 1
23+
`
24+
25+
// TestScrapeConfigFiles validates that scrape configs provided via scrape_config_files are
26+
// also considered and added to the applied configuration
27+
28+
func TestScrapeConfigFiles(t *testing.T) {
29+
setMetricsTimestamp()
30+
targets := []*testData{
31+
{
32+
name: "target1",
33+
pages: []mockPrometheusResponse{
34+
{code: 200, data: scrapeFileTargetPage},
35+
},
36+
validateFunc: verifyScrapeConfigFiles,
37+
},
38+
}
39+
40+
testComponent(t, targets, func(cfg *Config) {
41+
// take the generated scrape config and move it into a file instead
42+
marshalledScrapeConfigs, err := yaml.Marshal(cfg.PrometheusConfig.ScrapeConfigs)
43+
require.NoError(t, err)
44+
tmpDir := t.TempDir()
45+
cfgFileName := fmt.Sprintf("%s/test-scrape-config.yaml", tmpDir)
46+
scrapeConfigFileContent := fmt.Sprintf("scrape_configs:\n%s", string(marshalledScrapeConfigs))
47+
err = os.WriteFile(cfgFileName, []byte(scrapeConfigFileContent), 0400)
48+
require.NoError(t, err)
49+
cfg.PrometheusConfig.ScrapeConfigs = []*config.ScrapeConfig{}
50+
cfg.PrometheusConfig.ScrapeConfigFiles = []string{cfgFileName}
51+
})
52+
}
53+
54+
func verifyScrapeConfigFiles(t *testing.T, _ *testData, result []pmetric.ResourceMetrics) {
55+
require.Len(t, result, 1)
56+
serviceName, ok := result[0].Resource().Attributes().Get(semconv.AttributeServiceName)
57+
assert.True(t, ok)
58+
assert.Equal(t, "target1", serviceName.Str())
59+
assert.Equal(t, 6, result[0].ScopeMetrics().At(0).Metrics().Len())
60+
metricFound := false
61+
62+
for i := 0; i < result[0].ScopeMetrics().At(0).Metrics().Len(); i++ {
63+
if result[0].ScopeMetrics().At(0).Metrics().At(i).Name() == "foo1" {
64+
metricFound = true
65+
break
66+
}
67+
}
68+
assert.True(t, metricFound)
69+
}

receiver/prometheusreceiver/targetallocator/manager.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ func (m *Manager) sync(compareHash uint64, httpClient *http.Client) (uint64, err
158158
}
159159

160160
func (m *Manager) applyCfg() error {
161+
scrapeConfigs, err := m.promCfg.GetScrapeConfigs()
162+
if err != nil {
163+
return fmt.Errorf("could not get scrape configs: %w", err)
164+
}
161165
if !m.enableNativeHistograms {
162166
// Enforce scraping classic histograms to avoid dropping them.
163167
for _, scrapeConfig := range m.promCfg.ScrapeConfigs {
@@ -170,7 +174,7 @@ func (m *Manager) applyCfg() error {
170174
}
171175

172176
discoveryCfg := make(map[string]discovery.Configs)
173-
for _, scrapeConfig := range m.promCfg.ScrapeConfigs {
177+
for _, scrapeConfig := range scrapeConfigs {
174178
discoveryCfg[scrapeConfig.JobName] = scrapeConfig.ServiceDiscoveryConfigs
175179
m.settings.Logger.Info("Scrape job added", zap.String("jobName", scrapeConfig.JobName))
176180
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
prometheus:
2+
trim_metric_suffixes: true
3+
use_start_time_metric: true
4+
start_time_metric_regex: '^(.+_)*process_start_time_seconds$'
5+
report_extra_scrape_metrics: true
6+
config:
7+
scrape_config_files:
8+
- ./testdata/scrape-config.yaml
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
scrape_configs:
2+
- job_name: 'demo'
3+
scrape_interval: 5s

0 commit comments

Comments
 (0)