Skip to content

Commit 8dce99b

Browse files
feat(confgenerator): migrate legacy receivers to OTel and remove Fluent Bit components
1 parent d500e9e commit 8dce99b

20 files changed

Lines changed: 1070 additions & 1614 deletions

File tree

apps/common_logging_processors.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func instrumentationSourceValue(processorType string) *confgenerator.ModifyField
3131
}
3232

3333
// genericAccessLogParser is an internal logging processor that parses access logs.
34-
func genericAccessLogParser(ctx context.Context, processorType string) []confgenerator.InternalLoggingProcessor {
34+
func genericAccessLogParser(ctx context.Context, processorType string) []confgenerator.InternalOTelProcessor {
3535
c := confgenerator.LoggingProcessorParseRegex{
3636
// Documentation:
3737
// https://httpd.apache.org/docs/current/logs.html#accesslog
@@ -85,7 +85,7 @@ func genericAccessLogParser(ctx context.Context, processorType string) []confgen
8585
}
8686
}
8787

88-
return []confgenerator.InternalLoggingProcessor{
88+
return []confgenerator.InternalOTelProcessor{
8989
c,
9090
mf,
9191
}

apps/iis.go

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"fmt"
2020

2121
"github.com/GoogleCloudPlatform/ops-agent/confgenerator"
22-
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/fluentbit"
2322
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/otel"
2423
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/otel/ottl"
2524
"github.com/GoogleCloudPlatform/ops-agent/internal/platform"
@@ -162,39 +161,6 @@ func (LoggingProcessorMacroIisAccess) Type() string {
162161
// IISConcatFields handles field concatenation for IIS logs
163162
type IISConcatFields struct{}
164163

165-
// Components implements the Fluent-bit concatenation using Lua
166-
func (IISConcatFields) Components(ctx context.Context, tag, uid string) []fluentbit.Component {
167-
iisMergeRecordFieldsLuaFunction := `iis_merge_fields`
168-
iisMergeRecordFieldsLuaScriptContents := `
169-
function iis_merge_fields(tag, timestamp, record)
170-
171-
if (record["cs_uri_query"] == "-") then
172-
record["cs_uri_query"] = nil
173-
end
174-
if (record["http_request_referer"] == "-") then
175-
record["http_request_referer"] = nil
176-
end
177-
if (record["user"] == "-") then
178-
record["user"] = nil
179-
end
180-
181-
record["http_request_serverIp"] = table.concat({record["http_request_serverIp"], ":", record["s_port"]})
182-
if (record["cs_uri_query"] == nil or record["cs_uri_query"] == '') then
183-
record["http_request_requestUrl"] = record["cs_uri_stem"]
184-
else
185-
record["http_request_requestUrl"] = table.concat({record["cs_uri_stem"], "?", record["cs_uri_query"]})
186-
end
187-
188-
record["cs_uri_query"] = nil
189-
record["cs_uri_stem"] = nil
190-
record["s_port"] = nil
191-
return 2, timestamp, record
192-
end
193-
`
194-
195-
return fluentbit.LuaFilterComponents(tag, iisMergeRecordFieldsLuaFunction, iisMergeRecordFieldsLuaScriptContents)
196-
}
197-
198164
// Processors implements the OTEL concatenation using ModifyFields + CustomConvertFunc
199165
func (IISConcatFields) Processors(ctx context.Context) ([]otel.Component, error) {
200166
// Required OTTL fields
@@ -259,7 +225,7 @@ func (IISConcatFields) Processors(ctx context.Context) ([]otel.Component, error)
259225
return modifyFields.Processors(ctx)
260226
}
261227

262-
func (p LoggingProcessorMacroIisAccess) Expand(ctx context.Context) []confgenerator.InternalLoggingProcessor {
228+
func (p LoggingProcessorMacroIisAccess) Expand(ctx context.Context) []confgenerator.InternalOTelProcessor {
263229
parseRegex := confgenerator.LoggingProcessorParseRegex{
264230
// Microsoft updated the default format in Feb 2026.
265231
// The new format now has fields sc_bytes and cs_bytes added right before time_taken
@@ -316,7 +282,7 @@ func (p LoggingProcessorMacroIisAccess) Expand(ctx context.Context) []confgenera
316282
Fields: fields,
317283
}
318284

319-
return []confgenerator.InternalLoggingProcessor{
285+
return []confgenerator.InternalOTelProcessor{
320286
parseRegex,
321287
concatFields,
322288
excludeLogs,

confgenerator/confgenerator.go

Lines changed: 0 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,12 @@ package confgenerator
1717

1818
import (
1919
"context"
20-
"crypto/md5"
21-
"encoding/hex"
2220
"fmt"
2321
"log"
2422
"maps"
2523
"path"
26-
"regexp"
27-
"sort"
28-
"strconv"
2924
"strings"
3025

31-
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/fluentbit"
3226
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/otel"
3327
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/resourcedetector"
3428
"github.com/GoogleCloudPlatform/ops-agent/internal/experiments"
@@ -281,114 +275,6 @@ func (uc *UnifiedConfig) GenerateOtelConfig(ctx context.Context, outDir, stateDi
281275
return otelConfig, nil
282276
}
283277

284-
func (p PipelineInstance) simplifiedLoggingComponents(ctx context.Context) (InternalLoggingReceiver, []InternalLoggingProcessor, error) {
285-
receiver, ok := p.Receiver.(InternalLoggingReceiver)
286-
if !ok {
287-
return nil, nil, fmt.Errorf("%q is not a logging receiver", p.RID)
288-
}
289-
// Expand receiver and processors
290-
// TODO: What if they can be recursively expanded?
291-
var processors []InternalLoggingProcessor
292-
if r, ok := p.Receiver.(LoggingReceiverMacro); ok {
293-
receiver, processors = r.Expand(ctx)
294-
}
295-
for _, processorItem := range p.Processors {
296-
processor, ok := processorItem.Component.(InternalLoggingProcessor)
297-
if !ok {
298-
return nil, nil, fmt.Errorf("logging processor %q is incompatible with a receiver of type %q", processorItem.ID, p.Receiver.Type())
299-
}
300-
if p, ok := processor.(LoggingProcessorMacro); ok {
301-
processors = append(processors, p.Expand(ctx)...)
302-
continue
303-
}
304-
processors = append(processors, processor)
305-
}
306-
// Now that receiver and processors are all expanded, try merging them.
307-
for len(processors) > 0 {
308-
// Check if current receiver can merge processors.
309-
// This needs to happen every iteration because the receiver might be different after a previous merge.
310-
mr, ok := receiver.(InternalLoggingProcessorMerger)
311-
if !ok {
312-
return receiver, processors, nil
313-
}
314-
315-
// Attempt processor merge.
316-
receiver, processors[0] = mr.MergeInternalLoggingProcessor(processors[0])
317-
if processors[0] != nil {
318-
break
319-
}
320-
processors = processors[1:]
321-
}
322-
// Now receiver has been merged as much as possible.
323-
return receiver, processors, nil
324-
}
325-
326-
func (p PipelineInstance) FluentBitComponents(ctx context.Context) (fbSource, error) {
327-
tag := fmt.Sprintf("%s.%s", p.PID, p.RID)
328-
329-
// For fluent_forward we create the tag in the following format:
330-
// <hash_string>.<pipeline_id>.<receiver_id>.<existing_tag>
331-
//
332-
// hash_string: Deterministic unique identifier for the pipeline_id + receiver_id.
333-
// This is needed to prevent collisions between receivers in the same
334-
// pipeline when using the glob syntax for matching (using wildcards).
335-
// pipeline_id: User defined pipeline_id but with the "." replaced with "_"
336-
// since the "." character is reserved to be used as a delimiter in the
337-
// Lua script.
338-
// receiver_id: User defined receiver_id but with the "." replaced with "_"
339-
// since the "." character is reserved to be used as a delimiter in the
340-
// Lua script.
341-
// existing_tag: Tag associated with the record prior to ingesting.
342-
//
343-
// For an example testing collisions in receiver_ids, see:
344-
//
345-
// testdata/valid/linux/logging-receiver_forward_multiple_receivers_conflicting_id
346-
if p.Receiver.Type() == "fluent_forward" {
347-
hashString := getMD5Hash(tag)
348-
349-
// Note that we only update the tag for the tag. The LogName will still
350-
// use the user defined receiver_id without this replacement.
351-
pipelineIdCleaned := strings.ReplaceAll(p.PID, ".", "_")
352-
receiverIdCleaned := strings.ReplaceAll(p.RID, ".", "_")
353-
tag = fmt.Sprintf("%s.%s.%s", hashString, pipelineIdCleaned, receiverIdCleaned)
354-
}
355-
receiver, processors, err := p.simplifiedLoggingComponents(ctx)
356-
if err != nil {
357-
return fbSource{}, err
358-
}
359-
var components []fluentbit.Component
360-
receiverComponents := receiver.Components(ctx, tag)
361-
components = append(components, receiverComponents...)
362-
363-
// To match on fluent_forward records, we need to account for the addition
364-
// of the existing tag (unknown during config generation) as the suffix
365-
// of the tag.
366-
globSuffix := ""
367-
regexSuffix := ""
368-
if p.Receiver.Type() == "fluent_forward" {
369-
regexSuffix = `\..*`
370-
globSuffix = `.*`
371-
}
372-
tagRegex := regexp.QuoteMeta(tag) + regexSuffix
373-
tag = tag + globSuffix
374-
375-
for i, processor := range processors {
376-
processorComponents := processor.Components(ctx, tag, strconv.Itoa(i))
377-
components = append(components, processorComponents...)
378-
}
379-
components = append(components, setLogNameComponents(ctx, tag, p.RID, p.Receiver.Type())...)
380-
381-
// Logs ingested using the fluent_forward receiver must add the existing_tag
382-
// on the record to the LogName. This is done with a Lua filter.
383-
if p.Receiver.Type() == "fluent_forward" {
384-
components = append(components, fluentbit.LuaFilterComponents(tag, addLogNameLuaFunction, addLogNameLuaScriptContents)...)
385-
}
386-
return fbSource{
387-
TagRegex: tagRegex,
388-
Components: components,
389-
}, nil
390-
}
391-
392278
func (p PipelineInstance) OTelComponents(ctx context.Context) (map[string]otel.ReceiverPipeline, map[string]otel.Pipeline, error) {
393279
outR := make(map[string]otel.ReceiverPipeline)
394280
outP := make(map[string]otel.Pipeline)
@@ -479,25 +365,6 @@ func (uc *UnifiedConfig) generateOtelPipelines(ctx context.Context) (map[string]
479365
return outR, outP, nil
480366
}
481367

482-
// GenerateFluentBitConfigs generates configuration file(s) for Fluent Bit.
483-
// It returns a map of filenames to file contents.
484-
func (uc *UnifiedConfig) GenerateFluentBitConfigs(ctx context.Context, logsDir string, stateDir string) (map[string]string, error) {
485-
userAgent, _ := platform.FromContext(ctx).UserAgent("Google-Cloud-Ops-Agent-Logging")
486-
components, err := uc.generateFluentbitComponents(ctx, userAgent)
487-
if err != nil {
488-
return nil, err
489-
}
490-
491-
c := fluentbit.ModularConfig{
492-
Variables: map[string]string{
493-
"buffers_dir": path.Join(stateDir, "buffers"),
494-
"logs_dir": logsDir,
495-
},
496-
Components: components,
497-
}
498-
return c.Generate()
499-
}
500-
501368
func contains(s []string, str string) bool {
502369
for _, v := range s {
503370
if v == str {
@@ -554,61 +421,3 @@ func addGceMetadataAttributesProcessor(ctx context.Context) LoggingProcessorModi
554421
}
555422
return p
556423
}
557-
558-
type fbSource struct {
559-
TagRegex string
560-
Components []fluentbit.Component
561-
}
562-
563-
// generateFluentbitComponents generates a slice of fluentbit config sections to represent l.
564-
func (uc *UnifiedConfig) generateFluentbitComponents(ctx context.Context, userAgent string) ([]fluentbit.Component, error) {
565-
l := uc.Logging
566-
var out []fluentbit.Component
567-
if l.Service.LogLevel == "" {
568-
l.Service.LogLevel = "info"
569-
}
570-
service := fluentbit.Service{LogLevel: l.Service.LogLevel}
571-
out = append(out, service.Component())
572-
out = append(out, fluentbit.MetricsInputComponent())
573-
574-
if l != nil && l.Service != nil && (l.Service.OTelLogging == nil || !*l.Service.OTelLogging) {
575-
// Type for sorting.
576-
var sources []fbSource
577-
var tags []string
578-
pipelines, err := uc.Pipelines(ctx)
579-
if err != nil {
580-
return nil, err
581-
}
582-
for _, pipeline := range pipelines {
583-
if pipeline.Backend != BackendFluentBit {
584-
continue
585-
}
586-
source, err := pipeline.FluentBitComponents(ctx)
587-
if err != nil {
588-
return nil, err
589-
}
590-
sources = append(sources, source)
591-
tags = append(tags, source.TagRegex)
592-
}
593-
sort.Slice(sources, func(i, j int) bool { return sources[i].TagRegex < sources[j].TagRegex })
594-
sort.Strings(tags)
595-
596-
for _, s := range sources {
597-
out = append(out, s.Components...)
598-
}
599-
if len(tags) > 0 {
600-
out = append(out, stackdriverOutputComponent(ctx, strings.Join(tags, "|"), userAgent, "2G", l.Service.Compress))
601-
}
602-
out = append(out, addGceMetadataAttributesProcessor(ctx).Components(ctx, "*", "*.default-data-proc.gce_metadata")...)
603-
}
604-
out = append(out, uc.generateSelfLogsComponents(ctx, userAgent)...)
605-
out = append(out, fluentbit.MetricsOutputComponent(int(uc.GetFluentBitMetricsPort())))
606-
607-
return out, nil
608-
}
609-
610-
func getMD5Hash(text string) string {
611-
hasher := md5.New()
612-
hasher.Write([]byte(text))
613-
return hex.EncodeToString(hasher.Sum(nil))
614-
}

confgenerator/confgenerator_test.go

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -300,32 +300,10 @@ func generateConfigs(pc platformConfig, testDir string) (got map[string]string,
300300
}
301301
got[builtinConfigFileName] = confgenerator.BuiltInConfStructs[pc.platform.Name()].String()
302302

303-
pipelines, err := mergedUc.Pipelines(ctx)
303+
_, err = mergedUc.Pipelines(ctx)
304304
if err != nil {
305305
return
306306
}
307-
hasFluentBit := false
308-
for _, p := range pipelines {
309-
if p.Backend == confgenerator.BackendFluentBit {
310-
hasFluentBit = true
311-
break
312-
}
313-
}
314-
315-
if hasFluentBit {
316-
// Fluent Bit configs
317-
var flbGeneratedConfigs map[string]string
318-
flbGeneratedConfigs, err = mergedUc.GenerateFluentBitConfigs(ctx,
319-
pc.defaultLogsDir,
320-
pc.defaultStateDir,
321-
)
322-
for k, v := range flbGeneratedConfigs {
323-
got[k] = v
324-
}
325-
if err != nil {
326-
return
327-
}
328-
}
329307

330308
// Otel configs
331309
otelGeneratedConfig, err := mergedUc.GenerateOtelConfig(ctx, "", "")

0 commit comments

Comments
 (0)