Skip to content

Commit 0bc90df

Browse files
authored
Embedded OTel Collector Config (#1314)
1 parent 9b8090e commit 0bc90df

File tree

20 files changed

+387
-30
lines changed

20 files changed

+387
-30
lines changed

.codecov.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ coverage:
2222

2323
# Patch-level coverage settings
2424
patch:
25-
2625
default:
27-
28-
target: 80%
26+
informational: true
27+
target: auto
2928
threshold: 0%
3029
only_pulls: false
3130

internal/collector/nginxossreceiver/internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const (
2424
type Config struct {
2525
confighttp.ClientConfig `mapstructure:",squash"`
2626
APIDetails APIDetails `mapstructure:"api_details"`
27+
InstanceID string `mapstructure:"instance_id"`
2728
AccessLogs []AccessLog `mapstructure:"access_logs"`
2829
MetricsBuilderConfig metadata.MetricsBuilderConfig `mapstructure:",squash"`
2930
scraperhelper.ControllerConfig `mapstructure:",squash"`

internal/collector/nginxossreceiver/internal/scraper/accesslog/nginx_log_scraper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func (nls *NginxLogScraper) Scrape(_ context.Context) (pmetric.Metrics, error) {
171171
nls.entries = make([]*entry.Entry, 0)
172172
timeNow := pcommon.NewTimestampFromTime(time.Now())
173173

174-
nls.rb.SetInstanceID(nls.settings.ID.Name())
174+
nls.rb.SetInstanceID(nls.cfg.InstanceID)
175175
nls.rb.SetInstanceType("nginx")
176176
nls.logger.Debug("NGINX OSS access log resource info", zap.Any("resource", nls.rb))
177177

internal/collector/nginxossreceiver/internal/scraper/stubstatus/stub_status_scraper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func (s *NginxStubStatusScraper) Scrape(context.Context) (pmetric.Metrics, error
138138
return pmetric.Metrics{}, err
139139
}
140140

141-
s.rb.SetInstanceID(s.settings.ID.Name())
141+
s.rb.SetInstanceID(s.cfg.InstanceID)
142142
s.rb.SetInstanceType("nginx")
143143
s.settings.Logger.Debug("NGINX OSS stub status resource info", zap.Any("resource", s.rb))
144144

internal/collector/nginxplusreceiver/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const defaultCollectInterval = 10 * time.Second
2121
type Config struct {
2222
confighttp.ClientConfig `mapstructure:",squash"`
2323
APIDetails APIDetails `mapstructure:"api_details"`
24+
InstanceID string `mapstructure:"instance_id"`
2425
MetricsBuilderConfig metadata.MetricsBuilderConfig `mapstructure:",squash"`
2526
scraperhelper.ControllerConfig `mapstructure:",squash"`
2627
}

internal/collector/nginxplusreceiver/scraper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func (nps *NginxPlusScraper) Scrape(ctx context.Context) (pmetric.Metrics, error
127127
return pmetric.Metrics{}, fmt.Errorf("failed to get stats from plus API: %w", err)
128128
}
129129

130-
nps.rb.SetInstanceID(nps.settings.ID.Name())
130+
nps.rb.SetInstanceID(nps.cfg.InstanceID)
131131
nps.rb.SetInstanceType("nginxplus")
132132
nps.logger.Debug("NGINX Plus resource info", zap.Any("resource", nps.rb))
133133

internal/collector/otel_collector_plugin.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//
33
// This source code is licensed under the Apache License, Version 2.0 license found in the
44
// LICENSE file in the root directory of this source tree.
5+
56
package collector
67

78
import (
@@ -16,7 +17,9 @@ import (
1617
"sync"
1718
"time"
1819

20+
"github.com/goccy/go-yaml"
1921
pkgConfig "github.com/nginx/agent/v3/pkg/config"
22+
"go.opentelemetry.io/collector/confmap"
2023

2124
"github.com/nginx/agent/v3/api/grpc/mpi/v1"
2225
"github.com/nginx/agent/v3/internal/backoff"
@@ -43,6 +46,7 @@ const (
4346
`? (let utcTime = ` +
4447
`date(timestamp).UTC(); utcTime.Format("Jan 2 15:04:05")) : date(timestamp).Format("Jan 02 15:04:05"); ` +
4548
`split(body, ">")[0] + ">" + newTimestamp + " " + split(body, " ", 2)[1])'`
49+
debugOTelConfigFile = "/opentelemetry-collector-agent-debug.yaml"
4650
)
4751

4852
type (
@@ -53,6 +57,7 @@ type (
5357
mu *sync.Mutex
5458
cancel context.CancelFunc
5559
previousNAPSysLogServer string
60+
debugOTelConfigPath string
5661
stopped bool
5762
}
5863
)
@@ -88,12 +93,15 @@ func NewCollector(conf *config.Config) (*Collector, error) {
8893
return nil, err
8994
}
9095

96+
debugOTelConfigPath := conf.LibDir + debugOTelConfigFile
97+
9198
return &Collector{
9299
config: conf,
93100
service: oTelCollector,
94101
stopped: true,
95102
mu: &sync.Mutex{},
96103
previousNAPSysLogServer: "",
104+
debugOTelConfigPath: debugOTelConfigPath,
97105
}, nil
98106
}
99107

@@ -384,6 +392,31 @@ func (oc *Collector) updateHeadersSetterExtension(
384392
return headersSetterExtensionUpdated
385393
}
386394

395+
func (oc *Collector) writeRunningConfig(ctx context.Context, settings otelcol.CollectorSettings) error {
396+
slog.DebugContext(ctx, "Writing running OTel collector config", "path",
397+
oc.debugOTelConfigPath)
398+
resolver, err := confmap.NewResolver(settings.ConfigProviderSettings.ResolverSettings)
399+
if err != nil {
400+
return fmt.Errorf("unable to create resolver: %w", err)
401+
}
402+
403+
con, err := resolver.Resolve(ctx)
404+
if err != nil {
405+
return fmt.Errorf("error while resolving config: %w", err)
406+
}
407+
b, err := yaml.Marshal(con.ToStringMap())
408+
if err != nil {
409+
return fmt.Errorf("error while marshaling to YAML: %w", err)
410+
}
411+
412+
writeErr := os.WriteFile(oc.debugOTelConfigPath, b, filePermission)
413+
if writeErr != nil {
414+
return fmt.Errorf("error while writing debug config: %w", writeErr)
415+
}
416+
417+
return nil
418+
}
419+
387420
func (oc *Collector) restartCollector(ctx context.Context) {
388421
err := oc.Close(ctx)
389422
if err != nil {
@@ -392,6 +425,14 @@ func (oc *Collector) restartCollector(ctx context.Context) {
392425
}
393426

394427
settings := OTelCollectorSettings(oc.config)
428+
429+
if strings.ToLower(oc.config.Log.Level) == "debug" {
430+
writeErr := oc.writeRunningConfig(ctx, settings)
431+
if writeErr != nil {
432+
slog.ErrorContext(ctx, "Failed to write debug OTel Collector config", "error", writeErr)
433+
}
434+
}
435+
395436
oTelCollector, err := otelcol.NewCollector(settings)
396437
if err != nil {
397438
slog.ErrorContext(ctx, "Failed to create OTel Collector", "error", err)

internal/collector/otel_collector_plugin_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ import (
1818
"github.com/nginx/agent/v3/test/stub"
1919
"github.com/stretchr/testify/assert"
2020
"github.com/stretchr/testify/require"
21+
"go.opentelemetry.io/collector/confmap"
22+
"go.opentelemetry.io/collector/confmap/provider/envprovider"
23+
"go.opentelemetry.io/collector/confmap/provider/fileprovider"
24+
"go.opentelemetry.io/collector/confmap/provider/httpprovider"
25+
"go.opentelemetry.io/collector/confmap/provider/httpsprovider"
26+
"go.opentelemetry.io/collector/confmap/provider/yamlprovider"
27+
2128
"go.opentelemetry.io/collector/otelcol"
2229

2330
"github.com/nginx/agent/v3/internal/bus"
@@ -994,6 +1001,73 @@ func TestCollector_findAvailableSyslogServers(t *testing.T) {
9941001
}
9951002
}
9961003

1004+
func TestCollector_writeRunningConfig(t *testing.T) {
1005+
tempDir := t.TempDir()
1006+
1007+
tests := []struct {
1008+
name string
1009+
writeConfigErr error
1010+
settings otelcol.CollectorSettings
1011+
}{
1012+
{
1013+
name: "Test 1: Write Config Success",
1014+
settings: otelcol.CollectorSettings{
1015+
ConfigProviderSettings: otelcol.ConfigProviderSettings{
1016+
ResolverSettings: confmap.ResolverSettings{
1017+
URIs: []string{"./testdata/otel_config.yaml", "./testdata/custom_otel_config.yaml"},
1018+
ProviderFactories: []confmap.ProviderFactory{
1019+
envprovider.NewFactory(),
1020+
fileprovider.NewFactory(),
1021+
httpprovider.NewFactory(),
1022+
httpsprovider.NewFactory(),
1023+
yamlprovider.NewFactory(),
1024+
},
1025+
DefaultScheme: "",
1026+
ProviderSettings: confmap.ProviderSettings{},
1027+
ConverterFactories: nil,
1028+
ConverterSettings: confmap.ConverterSettings{},
1029+
},
1030+
},
1031+
},
1032+
writeConfigErr: nil,
1033+
},
1034+
{
1035+
name: "Test 2: Write Config Failed",
1036+
settings: otelcol.CollectorSettings{
1037+
ConfigProviderSettings: otelcol.ConfigProviderSettings{
1038+
ResolverSettings: confmap.ResolverSettings{},
1039+
},
1040+
},
1041+
writeConfigErr: errors.New("unable to create resolver: invalid " +
1042+
"'confmap.ResolverSettings' configuration: no URIs"),
1043+
},
1044+
}
1045+
1046+
for _, tt := range tests {
1047+
t.Run(tt.name, func(t *testing.T) {
1048+
conf := types.OTelConfig(t)
1049+
conf.Collector.Log.Path = filepath.Join(tempDir, "otel-collector-test.log")
1050+
newCollector, err := NewCollector(conf)
1051+
newCollector.debugOTelConfigPath = filepath.Join(tempDir, "otel-collector-debug-config.yaml")
1052+
require.NoError(t, err)
1053+
1054+
writeErr := newCollector.writeRunningConfig(context.Background(), tt.settings)
1055+
1056+
if tt.writeConfigErr == nil {
1057+
actual, readErr := os.ReadFile(newCollector.debugOTelConfigPath)
1058+
require.NoError(t, readErr)
1059+
1060+
expected, expectedFileErr := os.ReadFile("./testdata/merge_config.yaml")
1061+
require.NoError(t, expectedFileErr)
1062+
1063+
assert.Equal(t, string(expected), string(actual))
1064+
} else {
1065+
assert.Equal(t, tt.writeConfigErr.Error(), writeErr.Error())
1066+
}
1067+
})
1068+
}
1069+
}
1070+
9971071
func createFakeCollector() *typesfakes.FakeCollectorInterface {
9981072
fakeCollector := &typesfakes.FakeCollectorInterface{}
9991073
fakeCollector.RunStub = func(ctx context.Context) error { return nil }

internal/collector/otelcol.tmpl

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,12 @@ receivers:
7979
{{- end }}
8080

8181
{{- range .Receivers.NginxReceivers }}
82+
{{- if gt (len $.Receivers.NginxReceivers) 1 }}
8283
nginx/{{- .InstanceID -}}:
84+
{{- else }}
85+
nginx:
86+
{{- end}}
87+
instance_id: "{{- .InstanceID -}}"
8388
api_details:
8489
url: "{{- .StubStatus.URL -}}"
8590
listen: "{{- .StubStatus.Listen -}}"
@@ -98,12 +103,17 @@ receivers:
98103
{{- end }}
99104

100105
{{- range .Receivers.NginxPlusReceivers }}
106+
{{- if gt (len $.Receivers.NginxPlusReceivers) 1 }}
101107
nginxplus/{{- .InstanceID -}}:
108+
{{- else }}
109+
nginxplus:
110+
{{- end}}
111+
instance_id: "{{- .InstanceID -}}"
102112
api_details:
103-
url: "{{- .PlusAPI.URL -}}"
104-
listen: "{{- .PlusAPI.Listen -}}"
105-
location: "{{- .PlusAPI.Location -}}"
106-
ca: "{{- .PlusAPI.Ca -}}"
113+
url: "{{- .PlusAPI.URL -}}"
114+
listen: "{{- .PlusAPI.Listen -}}"
115+
location: "{{- .PlusAPI.Location -}}"
116+
ca: "{{- .PlusAPI.Ca -}}"
107117
{{- if .CollectionInterval }}
108118
collection_interval: {{ .CollectionInterval }}
109119
{{- end }}
@@ -274,10 +284,18 @@ service:
274284
{{- end }}
275285
{{- else if eq $receiver "nginx_metrics" }}
276286
{{- range $.Receivers.NginxReceivers }}
287+
{{- if gt (len $.Receivers.NginxReceivers) 1 }}
277288
- nginx/{{- .InstanceID -}}
289+
{{- else }}
290+
- nginx
291+
{{- end }}
278292
{{- end }}
279293
{{- range $.Receivers.NginxPlusReceivers }}
294+
{{- if gt (len $.Receivers.NginxReceivers) 1 }}
280295
- nginxplus/{{- .InstanceID -}}
296+
{{- else }}
297+
- nginxplus
298+
{{- end }}
281299
{{- end }}
282300
{{- else }}
283301
- {{ $receiver }}

internal/collector/settings.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ func createConverterFactories() []confmap.ConverterFactory {
7171
}
7272

7373
func createURIs(cfg *config.Config) []string {
74-
return []string{cfg.Collector.ConfigPath}
74+
configFiles := []string{cfg.Collector.ConfigPath}
75+
configFiles = slices.Concat(configFiles, cfg.Collector.AdditionalConfigPaths)
76+
slog.Info("Merging additional OTel config files", "config_files", configFiles)
77+
78+
return configFiles
7579
}
7680

7781
func createFile(confPath string) error {

0 commit comments

Comments
 (0)