Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds OTEL Syslog receiver to Agent v3 #932

Draft
wants to merge 7 commits into
base: v3
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/grpc/mpi/v1/command.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions internal/collector/factories.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor"
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/connector"
"go.opentelemetry.io/collector/exporter"
Expand Down Expand Up @@ -110,6 +111,7 @@ func createReceiverFactories() (map[component.Type]receiver.Factory, error) {
hostmetricsreceiver.NewFactory(),
nginxreceiver.NewFactory(),
nginxplusreceiver.NewFactory(),
syslogreceiver.NewFactory(),
}

return receiver.MakeFactoryMap(receiverList...)
Expand Down
2 changes: 1 addition & 1 deletion internal/collector/factories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestOTelComponentFactories(t *testing.T) {
require.NoError(t, err, "OTelComponentFactories should not return an error")
assert.NotNil(t, factories, "factories should not be nil")

assert.Len(t, factories.Receivers, 4)
assert.Len(t, factories.Receivers, 5)
assert.Len(t, factories.Processors, 20)
assert.Len(t, factories.Exporters, 4)
assert.Len(t, factories.Extensions, 3)
Expand Down
14 changes: 14 additions & 0 deletions internal/collector/otel_collector_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,19 @@ func (oc *Collector) checkForNewNginxReceivers(nginxConfigContext *model.NginxCo
},
)

if nginxConfigContext.Syslog != nil {
oc.config.Collector.Receivers.SyslogReceivers = append(
oc.config.Collector.Receivers.SyslogReceivers,
config.SyslogReceiver{
InstanceID: nginxConfigContext.InstanceID,
Server: nginxConfigContext.Syslog,
Protocol: "rfc3164", // default value, need to get from the agent conf
},
)
}

// slog.Error("hello", oc.config.Collector.Receivers)

reloadCollector = true
} else if nginxConfigContext.PlusAPI == "" {
nginxReceiverFound, reloadCollector = oc.updateExistingNginxOSSReceiver(nginxConfigContext)
Expand All @@ -387,6 +400,7 @@ func (oc *Collector) checkForNewNginxReceivers(nginxConfigContext *model.NginxCo
return reloadCollector
}

// Todo: consider update scenario for new syslogreceivers
func (oc *Collector) updateExistingNginxPlusReceiver(
nginxConfigContext *model.NginxConfigContext,
) (nginxReceiverFound, reloadCollector bool) {
Expand Down
12 changes: 12 additions & 0 deletions internal/collector/otel_collector_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ func TestCollector_ProcessNginxConfigUpdateTopic(t *testing.T) {
Network: &config.NetworkScraper{},
},
},
SyslogReceivers: []config.SyslogReceiver{
{
Server: []string{"127.0.0.1:1515"},
InstanceID: "00",
Protocol: "rfc3164"},
},
OtlpReceivers: types.OtlpReceivers(),
NginxPlusReceivers: []config.NginxPlusReceiver{
{
Expand Down Expand Up @@ -157,6 +163,12 @@ func TestCollector_ProcessNginxConfigUpdateTopic(t *testing.T) {
},
},
OtlpReceivers: types.OtlpReceivers(),
SyslogReceivers: []config.SyslogReceiver{
{
Server: []string{"127.0.0.1:1515"},
InstanceID: "00",
Protocol: "rfc3164"},
},
NginxReceivers: []config.NginxReceiver{
{
InstanceID: "123",
Expand Down
27 changes: 27 additions & 0 deletions internal/collector/otelcol.tmpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
receivers:
{{- range $index, $otlpReceiver := .Receivers.SyslogReceivers }}
{{- $instanceID := .InstanceID }}
{{- range $serverIndex, $server := .Server }}
syslog/{{$index}}{{$serverIndex}}:
tcp:
listen_address: "{{ $server }}"
protocol: rfc3164
{{- end }}
{{- end }}
{{- if ne .Receivers.HostMetrics nil }}
hostmetrics:
collection_interval: {{ .Receivers.HostMetrics.CollectionInterval }}
Expand Down Expand Up @@ -233,3 +242,21 @@ service:
{{- if ne .Exporters.Debug nil }}
- debug
{{- end }}
{{- if and (ne .Receivers.SyslogReceivers nil) (ne .Exporters.OtlpExporters nil) }}
logs:
receivers:
{{- range .Receivers.SyslogReceivers }}
- syslog/{{- .InstanceID -}}
{{- end }}
processors:
{{- if ne .Processors.Batch nil }}
- batch
{{- end }}
exporters:
{{- range $index, $otlpExporter := .Exporters.OtlpExporters }}
- otlp/{{$index}}
{{- end }}
{{- if ne .Exporters.Debug nil }}
- debug
{{- end }}
{{- end }}
1 change: 1 addition & 0 deletions internal/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

const (
//Todo: Add default Protocol for nap
DefGracefulShutdownPeriod = 5 * time.Second
DefNginxReloadMonitoringPeriod = 10 * time.Second
DefTreatErrorsAsWarnings = false
Expand Down
7 changes: 7 additions & 0 deletions internal/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ type (
OtlpReceivers []OtlpReceiver `yaml:"-" mapstructure:"otlp_receivers"`
NginxReceivers []NginxReceiver `yaml:"-" mapstructure:"nginx_receivers"`
NginxPlusReceivers []NginxPlusReceiver `yaml:"-" mapstructure:"nginx_plus_receivers"`
SyslogReceivers []SyslogReceiver `yaml:"-" mapstructure:"syslog_receiver"`
}

OtlpReceiver struct {
Expand All @@ -171,6 +172,12 @@ type (
OtlpTLSConfig *OtlpTLSConfig `yaml:"-" mapstructure:"tls"`
}

SyslogReceiver struct {
InstanceID string `yaml:"-" mapstructure:"instance_id"`
Server []string `yaml:"-" mapstructure:"server"`
Protocol string `yaml:"-" mapstructure:"protocol"`
}

NginxReceiver struct {
InstanceID string `yaml:"-" mapstructure:"instance_id"`
StubStatus string `yaml:"-" mapstructure:"stub_status"`
Expand Down
7 changes: 7 additions & 0 deletions internal/model/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type NginxConfigContext struct {
Files []*v1.File
AccessLogs []*AccessLog
ErrorLogs []*ErrorLog
Syslog []string
}

func (ncc *NginxConfigContext) Equal(otherNginxConfigContext *NginxConfigContext) bool {
Expand Down Expand Up @@ -85,6 +86,12 @@ type ErrorLog struct {
Readable bool
}

type NAP struct {
Enable bool
Syslog bool
SyslogServer string
}

type (
WriteStatus int
)
Expand Down
18 changes: 17 additions & 1 deletion internal/watcher/instance/nginx_config_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"slices"
"strconv"
"strings"
Expand All @@ -36,6 +37,7 @@ const (
stubStatusAPIDirective = "stub_status"
apiFormat = "http://%s%s"
locationDirective = "location"
napDirective = "app_protect_security_log"
)

type (
Expand Down Expand Up @@ -98,6 +100,7 @@ func (ncp *NginxConfigParser) createNginxConfigContext(

for _, conf := range payload.Config {
formatMap := make(map[string]string)
syslogMap := make(map[string]bool)
err := ncp.crossplaneConfigTraverse(ctx, &conf,
func(ctx context.Context, parent, directive *crossplane.Directive) error {
switch directive.Directive {
Expand All @@ -120,8 +123,21 @@ func (ncp *NginxConfigParser) createNginxConfigContext(
case "ssl_certificate", "proxy_ssl_certificate", "ssl_client_certificate", "ssl_trusted_certificate":
sslCertFile := ncp.sslCert(ctx, directive.Args[0], rootDir)
nginxConfigContext.Files = append(nginxConfigContext.Files, sslCertFile)
case "app_protect_security_log":
if len(directive.Args) > 1 {
syslogArg := directive.Args[1]
re := regexp.MustCompile(`syslog:server=([\S]+)`)
matches := re.FindStringSubmatch(syslogArg)
if len(matches) > 1 {
syslogServer := matches[1]
if !syslogMap[syslogServer] {
nginxConfigContext.Syslog = append(nginxConfigContext.Syslog, syslogServer)
syslogMap[syslogServer] = true
}
slog.InfoContext(ctx, "Captured syslog server", "syslog_server", syslogServer)
}
}
}

return nil
},
)
Expand Down
4 changes: 4 additions & 0 deletions internal/watcher/instance/nginx_config_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ func TestNginxConfigParser_Parse(t *testing.T) {
tests := []struct {
instance *mpi.Instance
name string
syslog []string
}{
{
name: "Test 1: Valid response",
Expand All @@ -287,6 +288,7 @@ func TestNginxConfigParser_Parse(t *testing.T) {
{
name: "Test 2: Error response",
instance: protos.GetNginxPlusInstance([]string{}),
syslog: []string{"127.0.0.1:1515"},
},
}

Expand All @@ -298,7 +300,9 @@ func TestNginxConfigParser_Parse(t *testing.T) {
ltsvAccessLog.Name(),
errorLog.Name(),
test.instance.GetInstanceMeta().GetInstanceId(),
test.syslog,
)

expectedConfigContext.Files = append(expectedConfigContext.Files, &mpi.File{
FileMeta: fileMeta,
})
Expand Down
12 changes: 12 additions & 0 deletions test/config/collector/test-opentelemetry-collector-agent.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
receivers:
syslog/00:
tcp:
listen_address: "127.0.0.1:1515"
protocol: rfc3164
hostmetrics:
collection_interval: 1m0s
initial_delay: 1s
Expand Down Expand Up @@ -84,3 +88,11 @@ service:
- otlp/0
- prometheus
- debug
logs:
receivers:
- syslog/00
processors:
- batch
exporters:
- otlp/0
- debug
2 changes: 1 addition & 1 deletion test/docker/nginx-plus/deb/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ RUN --mount=type=secret,id=nginx-crt,dst=nginx-repo.crt \
&& echo "Acquire::https::pkgs.nginx.com::Verify-Host \"true\";" >> /etc/apt/apt.conf.d/90nginx \
&& echo "Acquire::https::pkgs.nginx.com::SslCert \"/etc/ssl/nginx/nginx-repo.crt\";" >> /etc/apt/apt.conf.d/90nginx \
&& echo "Acquire::https::pkgs.nginx.com::SslKey \"/etc/ssl/nginx/nginx-repo.key\";" >> /etc/apt/apt.conf.d/90nginx \
&& printf "deb https://pkgs.nginx.com/plus/ubuntu `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
&& printf "deb https://pkgs.nginx.com/plus/R32/ubuntu `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
&& mkdir -p /etc/ssl/nginx \
&& cat nginx-repo.crt > /etc/ssl/nginx/nginx-repo.crt \
&& cat nginx-repo.key > /etc/ssl/nginx/nginx-repo.key \
Expand Down
8 changes: 8 additions & 0 deletions test/mock/collector/otel-collector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ exporters:
resource_to_telemetry_conversion:
enabled: true
add_metric_suffixes: false
debug:
verbosity: detailed
sampling_initial: 5
sampling_thereafter: 200

processors:
batch:
Expand All @@ -28,3 +32,7 @@ service:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
logs:
receivers: [otlp]
processors: [batch]
exporters: [debug]
2 changes: 2 additions & 0 deletions test/model/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func GetConfigContextWithNames(
ltsvAccessLogName,
errorLogName string,
instanceID string,
syslog []string,
) *model.NginxConfigContext {
return &model.NginxConfigContext{
AccessLogs: []*model.AccessLog{
Expand Down Expand Up @@ -52,5 +53,6 @@ func GetConfigContextWithNames(
},
},
InstanceID: instanceID,
Syslog: syslog,
}
}
3 changes: 3 additions & 0 deletions test/protos/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ func GetNginxPlusInstance(expectedModules []string) *v1.Instance {
"stream_proxy_protocol_vendor_module", "stream_realip_module", "stream_ssl_module",
"stream_ssl_preread_module",
},
AppProtectDirectives: []string{
`app_protect_security_log "/etc/app_protect/conf/log_default.json" syslog:server=127.0.0.1:514`,
},
PlusApi: "",
},
},
Expand Down
7 changes: 7 additions & 0 deletions test/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ func AgentConfig() *config.Config {
},
Receivers: config.Receivers{
OtlpReceivers: OtlpReceivers(),
SyslogReceivers: []config.SyslogReceiver{
{
Server: []string{"127.0.0.1:1515"},
InstanceID: "00",
Protocol: "rfc3164",
},
},
HostMetrics: &config.HostMetrics{
CollectionInterval: time.Minute,
InitialDelay: time.Second,
Expand Down