Skip to content

Commit dc3b14b

Browse files
dehaansakalleep
andauthored
prepare patch v1.8.1 on release branch (#3275)
* Alloy configuration of syslog rfc3164 default year behavior (#3271) (cherry picked from commit 1631806) * fix: Ensure the remoteCfg service doesn't immediately stop if not configured (#3232) * Ensure the remoteCfg service doesn't immediately stop if not configured * Add changelog (cherry picked from commit 5c7c950) * No longer register metrics in isEnabled but do it while holding a write (#3272) (cherry picked from commit 34bfe71) * Add changelog for kalle's fix * fix: panic when using minimal url for `prometheus.postgres.exporter` (#3226) * Handle minimal url * Remove unused function (cherry picked from commit 0858356) --------- Co-authored-by: Karl Persson <[email protected]>
1 parent 03cc885 commit dc3b14b

File tree

8 files changed

+77
-94
lines changed

8 files changed

+77
-94
lines changed

Diff for: CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ This document contains a historical list of changes between releases. Only
77
changes that impact end-user behavior are listed; changes to documentation or
88
internal API changes are not present.
99

10+
v1.8.1
11+
-----------------
12+
13+
### Bugfixes
14+
15+
- `rfc3164_default_to_current_year` argument was not fully added to `loki.source.syslog` (@dehaansa)
16+
17+
- Fix issue with `remoteCfg` service stopping immediately and logging noop error if not configured (@dehaansa)
18+
19+
- Fix potential race condition in `remoteCfg` service metrics registration (@kalleep)
20+
21+
- Fix panic in `prometheus.exporter.postgres` when using minimal url as data source name. (@kalleep)
22+
1023
v1.8.0
1124
-----------------
1225

Diff for: internal/component/loki/source/syslog/types.go

+22-20
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ import (
1313

1414
// ListenerConfig defines a syslog listener.
1515
type ListenerConfig struct {
16-
ListenAddress string `alloy:"address,attr"`
17-
ListenProtocol string `alloy:"protocol,attr,optional"`
18-
IdleTimeout time.Duration `alloy:"idle_timeout,attr,optional"`
19-
LabelStructuredData bool `alloy:"label_structured_data,attr,optional"`
20-
Labels map[string]string `alloy:"labels,attr,optional"`
21-
UseIncomingTimestamp bool `alloy:"use_incoming_timestamp,attr,optional"`
22-
UseRFC5424Message bool `alloy:"use_rfc5424_message,attr,optional"`
23-
MaxMessageLength int `alloy:"max_message_length,attr,optional"`
24-
TLSConfig config.TLSConfig `alloy:"tls_config,block,optional"`
25-
SyslogFormat config.SysLogFormat `alloy:"syslog_format,attr,optional"`
16+
ListenAddress string `alloy:"address,attr"`
17+
ListenProtocol string `alloy:"protocol,attr,optional"`
18+
IdleTimeout time.Duration `alloy:"idle_timeout,attr,optional"`
19+
LabelStructuredData bool `alloy:"label_structured_data,attr,optional"`
20+
Labels map[string]string `alloy:"labels,attr,optional"`
21+
UseIncomingTimestamp bool `alloy:"use_incoming_timestamp,attr,optional"`
22+
UseRFC5424Message bool `alloy:"use_rfc5424_message,attr,optional"`
23+
RFC3164DefaultToCurrentYear bool `alloy:"rfc3164_default_to_current_year,attr,optional"`
24+
MaxMessageLength int `alloy:"max_message_length,attr,optional"`
25+
TLSConfig config.TLSConfig `alloy:"tls_config,block,optional"`
26+
SyslogFormat config.SysLogFormat `alloy:"syslog_format,attr,optional"`
2627
}
2728

2829
// DefaultListenerConfig provides the default arguments for a syslog listener.
@@ -65,16 +66,17 @@ func (sc ListenerConfig) Convert() (*scrapeconfig.SyslogTargetConfig, error) {
6566
}
6667

6768
return &scrapeconfig.SyslogTargetConfig{
68-
ListenAddress: sc.ListenAddress,
69-
ListenProtocol: sc.ListenProtocol,
70-
IdleTimeout: sc.IdleTimeout,
71-
LabelStructuredData: sc.LabelStructuredData,
72-
Labels: lbls,
73-
UseIncomingTimestamp: sc.UseIncomingTimestamp,
74-
UseRFC5424Message: sc.UseRFC5424Message,
75-
MaxMessageLength: sc.MaxMessageLength,
76-
TLSConfig: *sc.TLSConfig.Convert(),
77-
SyslogFormat: syslogFormat,
69+
ListenAddress: sc.ListenAddress,
70+
ListenProtocol: sc.ListenProtocol,
71+
IdleTimeout: sc.IdleTimeout,
72+
LabelStructuredData: sc.LabelStructuredData,
73+
Labels: lbls,
74+
UseIncomingTimestamp: sc.UseIncomingTimestamp,
75+
UseRFC5424Message: sc.UseRFC5424Message,
76+
RFC3164DefaultToCurrentYear: sc.RFC3164DefaultToCurrentYear,
77+
MaxMessageLength: sc.MaxMessageLength,
78+
TLSConfig: *sc.TLSConfig.Convert(),
79+
SyslogFormat: syslogFormat,
7880
}, nil
7981
}
8082

Diff for: internal/component/prometheus/exporter/postgres/postgres.go

-33
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ package postgres
22

33
import (
44
"fmt"
5-
"strings"
65

76
"github.com/grafana/alloy/internal/component"
87
"github.com/grafana/alloy/internal/component/prometheus/exporter"
98
"github.com/grafana/alloy/internal/featuregate"
109
"github.com/grafana/alloy/internal/static/integrations"
1110
"github.com/grafana/alloy/internal/static/integrations/postgres_exporter"
1211
"github.com/grafana/alloy/syntax/alloytypes"
13-
"github.com/lib/pq"
1412
config_util "github.com/prometheus/common/config"
1513
)
1614

@@ -30,37 +28,6 @@ func createExporter(opts component.Options, args component.Arguments, defaultIns
3028
return integrations.NewIntegrationWithInstanceKey(opts.Logger, a.convert(opts.ID), defaultInstanceKey)
3129
}
3230

33-
func parsePostgresURL(url string) (map[string]string, error) {
34-
raw, err := pq.ParseURL(url)
35-
if err != nil {
36-
return nil, err
37-
}
38-
39-
res := map[string]string{}
40-
41-
unescaper := strings.NewReplacer(`\'`, `'`, `\\`, `\`)
42-
43-
for _, keypair := range strings.Split(raw, " ") {
44-
parts := strings.SplitN(keypair, "=", 2)
45-
if len(parts) != 2 {
46-
return nil, fmt.Errorf("unexpected keypair %s from pq", keypair)
47-
}
48-
49-
key := parts[0]
50-
value := parts[1]
51-
52-
// Undo all the transformations ParseURL did: remove wrapping
53-
// quotes and then unescape the escaped characters.
54-
value = strings.TrimPrefix(value, "'")
55-
value = strings.TrimSuffix(value, "'")
56-
value = unescaper.Replace(value)
57-
58-
res[key] = value
59-
}
60-
61-
return res, nil
62-
}
63-
6431
// DefaultArguments holds the default arguments for the prometheus.exporter.postgres
6532
// component.
6633
var DefaultArguments = Arguments{

Diff for: internal/component/prometheus/exporter/postgres/postgres_test.go

-16
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,3 @@ func TestRiverConfigValidate(t *testing.T) {
115115
})
116116
}
117117
}
118-
119-
func TestParsePostgresURL(t *testing.T) {
120-
dsn := "postgresql://linus:42secret@localhost:5432/postgres?sslmode=disable"
121-
expected := map[string]string{
122-
"dbname": "postgres",
123-
"host": "localhost",
124-
"password": "42secret",
125-
"port": "5432",
126-
"sslmode": "disable",
127-
"user": "linus",
128-
}
129-
130-
actual, err := parsePostgresURL(dsn)
131-
require.NoError(t, err)
132-
require.Equal(t, actual, expected)
133-
}

Diff for: internal/service/remotecfg/noop.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ import (
1010

1111
type noopClient struct{}
1212

13+
var errNoopClient = errors.New("noop client")
14+
1315
// GetConfig returns the collector's configuration.
1416
func (c noopClient) GetConfig(context.Context, *connect.Request[collectorv1.GetConfigRequest]) (*connect.Response[collectorv1.GetConfigResponse], error) {
15-
return nil, errors.New("noop client")
17+
return nil, errNoopClient
1618
}
1719

1820
// RegisterCollector checks in the current collector to the API on startup.
1921
func (c noopClient) RegisterCollector(context.Context, *connect.Request[collectorv1.RegisterCollectorRequest]) (*connect.Response[collectorv1.RegisterCollectorResponse], error) {
20-
return nil, errors.New("noop client")
22+
return nil, errNoopClient
2123
}
2224

2325
// UnregisterCollector checks out the current collector to the API on shutdown.
2426
func (c noopClient) UnregisterCollector(context.Context, *connect.Request[collectorv1.UnregisterCollectorRequest]) (*connect.Response[collectorv1.UnregisterCollectorResponse], error) {
25-
return nil, errors.New("noop client")
27+
return nil, errNoopClient
2628
}

Diff for: internal/service/remotecfg/remotecfg.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ func (s *Service) Run(ctx context.Context, host service.Host) error {
282282

283283
s.fetch()
284284
err := s.registerCollector()
285-
if err != nil {
285+
if err != nil && err != errNoopClient {
286286
return err
287287
}
288288

@@ -302,7 +302,7 @@ func (s *Service) Run(ctx context.Context, host service.Host) error {
302302
select {
303303
case <-s.ticker.C:
304304
err := s.fetchRemote()
305-
if err != nil {
305+
if err != nil && err != errNoopClient {
306306
level.Error(s.opts.Logger).Log("msg", "failed to fetch remote configuration from the API", "err", err)
307307
}
308308
case <-s.updateTickerChan:
@@ -354,11 +354,16 @@ func (s *Service) Update(newConfig any) error {
354354
// Update the args as the last step to avoid polluting any comparisons
355355
s.args = newArgs
356356
err = s.registerCollector()
357-
s.mut.Unlock()
358357
if err != nil {
358+
s.mut.Unlock()
359359
return err
360360
}
361361

362+
if s.metrics == nil {
363+
s.registerMetrics()
364+
}
365+
s.mut.Unlock()
366+
362367
// If we've already called Run, then immediately trigger an API call with
363368
// the updated Arguments, and/or fall back to the updated cache location.
364369
if s.ctrl != nil && s.ctrl.Ready() {
@@ -546,11 +551,7 @@ func (s *Service) setLastLoadedCfgHash(h string) {
546551
func (s *Service) isEnabled() bool {
547552
s.mut.RLock()
548553
defer s.mut.RUnlock()
549-
enabled := s.args.URL != "" && s.asClient != nil
550-
if enabled && s.metrics == nil {
551-
s.registerMetrics()
552-
}
553-
return enabled
554+
return s.args.URL != "" && s.asClient != nil
554555
}
555556

556557
func (s *Service) setPollFrequency(t time.Duration) {

Diff for: internal/static/integrations/postgres_exporter/postgres_exporter.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ func (c *Config) InstanceKey(_ string) (string, error) {
8888
}
8989

9090
func parsePostgresURL(url string) (map[string]string, error) {
91+
if url == "postgresql://" || url == "postgres://" {
92+
return map[string]string{}, nil
93+
}
94+
9195
raw, err := pq.ParseURL(url)
9296
if err != nil {
9397
return nil, err
@@ -97,10 +101,10 @@ func parsePostgresURL(url string) (map[string]string, error) {
97101

98102
unescaper := strings.NewReplacer(`\'`, `'`, `\\`, `\`)
99103

100-
for _, keypair := range strings.Split(raw, " ") {
104+
for keypair := range strings.SplitSeq(raw, " ") {
101105
parts := strings.SplitN(keypair, "=", 2)
102106
if len(parts) != 2 {
103-
panic(fmt.Sprintf("unexpected keypair %s from pq", keypair))
107+
return nil, fmt.Errorf("unexpected keypair %s from pq", keypair)
104108
}
105109

106110
key := parts[0]

Diff for: internal/static/integrations/postgres_exporter/postgres_exporter_test.go

+22-12
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,29 @@ import (
88
)
99

1010
func Test_ParsePostgresURL(t *testing.T) {
11-
dsn := "postgresql://linus:42secret@localhost:5432/postgres?sslmode=disable"
12-
expected := map[string]string{
13-
"dbname": "postgres",
14-
"host": "localhost",
15-
"password": "42secret",
16-
"port": "5432",
17-
"sslmode": "disable",
18-
"user": "linus",
19-
}
11+
t.Run("with valid url", func(t *testing.T) {
12+
dsn := "postgresql://linus:42secret@localhost:5432/postgres?sslmode=disable"
13+
expected := map[string]string{
14+
"dbname": "postgres",
15+
"host": "localhost",
16+
"password": "42secret",
17+
"port": "5432",
18+
"sslmode": "disable",
19+
"user": "linus",
20+
}
21+
22+
actual, err := parsePostgresURL(dsn)
23+
require.NoError(t, err)
24+
require.Equal(t, actual, expected)
25+
})
2026

21-
actual, err := parsePostgresURL(dsn)
22-
require.NoError(t, err)
23-
require.Equal(t, actual, expected)
27+
t.Run("with minimal url", func(t *testing.T) {
28+
minimal := "postgres://"
29+
expected := map[string]string{}
30+
actual, err := parsePostgresURL(minimal)
31+
require.NoError(t, err)
32+
require.Equal(t, actual, expected)
33+
})
2434
}
2535

2636
func Test_getDataSourceNames(t *testing.T) {

0 commit comments

Comments
 (0)