Skip to content

Commit

Permalink
Add logging labels with GCE instance's managed instance group. (#1849)
Browse files Browse the repository at this point in the history
Co-authored-by: Francisco Valente <1435136+franciscovalentecastro@users.noreply.github.com>
  • Loading branch information
quentinmit and franciscovalentecastro authored Feb 20, 2025
1 parent 6602f6c commit b0665b3
Show file tree
Hide file tree
Showing 3,140 changed files with 92,157 additions and 52,608 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
4 changes: 2 additions & 2 deletions confgenerator/confgenerator.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func (p pipelineInstance) fluentBitComponents(ctx context.Context) (fbSource, er
}
components = append(components, processorComponents...)
}
components = append(components, setLogNameComponents(ctx, tag, p.rID, receiver.Type(), platform.FromContext(ctx).Hostname())...)
components = append(components, setLogNameComponents(ctx, tag, p.rID, receiver.Type())...)

// Logs ingested using the fluent_forward receiver must add the existing_tag
// on the record to the LogName. This is done with a Lua filter.
Expand Down Expand Up @@ -225,7 +225,7 @@ func (p pipelineInstance) otelComponents(ctx context.Context) (map[string]otel.R
if processors, ok := receiverPipeline.Processors["logs"]; ok {
receiverPipeline.Processors["logs"] = append(
processors,
otelSetLogNameComponents(ctx, p.rID, platform.FromContext(ctx).Hostname())...,
otelSetLogNameComponents(ctx, p.rID)...,
)
}

Expand Down
6 changes: 6 additions & 0 deletions confgenerator/confgenerator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"strings"
"testing"

"github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp"
"github.com/GoogleCloudPlatform/ops-agent/apps"
"github.com/GoogleCloudPlatform/ops-agent/confgenerator"
"github.com/GoogleCloudPlatform/ops-agent/confgenerator/resourcedetector"
Expand Down Expand Up @@ -72,6 +73,11 @@ var (
Metadata: map[string]string{"test-key": "test-value", "test-escape": "$foo", "test-escape-parentheses": "${foo:bar}"},
Label: map[string]string{"test-label-key": "test-label-value"},
InterfaceIPv4: map[string]string{"test-interface": "test-interface-ipv4"},
ManagedInstanceGroup: gcp.ManagedInstanceGroup{
Name: "test-mig",
Type: gcp.Zone,
Location: "test-zone",
},
}
linuxTestPlatform = platformConfig{
name: "linux",
Expand Down
68 changes: 39 additions & 29 deletions confgenerator/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,48 @@ import (
const InstrumentationSourceLabel = `labels."logging.googleapis.com/instrumentation_source"`
const HttpRequestKey = "logging.googleapis.com/httpRequest"

// setLogNameComponents generates a series of components that rewrites the tag on log entries tagged `tag` to be `logName`.
func setLogNameComponents(ctx context.Context, tag, logName, receiverType string, hostName string) []fluentbit.Component {
return LoggingProcessorModifyFields{
Fields: map[string]*ModifyField{
"logName": {
DefaultValue: &logName,
},
`labels."compute.googleapis.com/resource_name"`: {
DefaultValue: &hostName,
},
`labels."agent.googleapis.com/log_file_path"`: {
MoveFrom: `jsonPayload."agent.googleapis.com/log_file_path"`,
},
// `labels."agent.googleapis.com/receiver_type"`: {
// StaticValue: &receiverType,
// },
func setLogNameProcessor(ctx context.Context, logName string) LoggingProcessorModifyFields {
p := platform.FromContext(ctx)
hostName := p.Hostname()
fields := map[string]*ModifyField{
"logName": {
DefaultValue: &logName,
},
}.Components(ctx, tag, "setlogname")
`labels."compute.googleapis.com/resource_name"`: {
DefaultValue: &hostName,
},
}
r, err := p.GetResource()
if err == nil {
for k, v := range r.ExtraLogLabels() {
v := v
fields[fmt.Sprintf("labels.%q", k)] = &ModifyField{
DefaultValue: &v,
}
}
}
return LoggingProcessorModifyFields{
Fields: fields,
}
}

func otelSetLogNameComponents(ctx context.Context, logName, hostName string) []otel.Component {
components, err := LoggingProcessorModifyFields{
Fields: map[string]*ModifyField{
// TODO: Prepend `receiver_id.` if it already exists, like the `fluent_forward` receiver?
"logName": {
DefaultValue: &logName,
},
`labels."compute.googleapis.com/resource_name"`: {
DefaultValue: &hostName,
},
},
}.Processors(ctx)
// setLogNameComponents generates a series of components that rewrites the tag on log entries tagged `tag` to be `logName`.
func setLogNameComponents(ctx context.Context, tag, logName, receiverType string) []fluentbit.Component {
p := setLogNameProcessor(ctx, logName)
p.Fields[`labels."agent.googleapis.com/log_file_path"`] = &ModifyField{
MoveFrom: `jsonPayload."agent.googleapis.com/log_file_path"`,
}
// TODO: b/397957994 - Cleanup "receiver_type" logic if no future intended use.
// p.Fields[`labels."agent.googleapis.com/receiver_type"`] = &ModifyField{
// StaticValue: &receiverType,
// }
return p.Components(ctx, tag, "setlogname")
}

func otelSetLogNameComponents(ctx context.Context, logName string) []otel.Component {
// TODO: Prepend `receiver_id.` if it already exists, like the `fluent_forward` receiver?
p := setLogNameProcessor(ctx, logName)
components, err := p.Processors(ctx)
if err != nil {
// We're generating a hard-coded config, so this should never fail.
panic(err)
Expand Down
5 changes: 5 additions & 0 deletions confgenerator/resourcedetector/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Resource interface {
MonitoredResource() *monitoredres.MonitoredResource
OTelResourceAttributes() map[string]string
PrometheusStyleMetadata() map[string]string
ExtraLogLabels() map[string]string
}

type resourceCache struct {
Expand Down Expand Up @@ -81,6 +82,10 @@ func (UnrecognizedPlatformResource) PrometheusStyleMetadata() map[string]string
return nil
}

func (UnrecognizedPlatformResource) ExtraLogLabels() map[string]string {
return nil
}

func GetUnrecognizedPlatformResource() (Resource, error) {
return UnrecognizedPlatformResource{}, nil
}
85 changes: 57 additions & 28 deletions confgenerator/resourcedetector/gce_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"strings"

"github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp"
"github.com/prometheus/prometheus/util/strutil"
"google.golang.org/genproto/googleapis/api/monitoredres"
)
Expand All @@ -41,6 +42,12 @@ const (
defaultScopes
)

const (
ManagedInstanceGroupNameLabel = `compute.googleapis.com/instance_group_manager/name`
ManagedInstanceGroupZoneLabel = `compute.googleapis.com/instance_group_manager/zone`
ManagedInstanceGroupRegionLabel = `compute.googleapis.com/instance_group_manager/region`
)

func GetGCEResource() (Resource, error) {
provider := NewGCEMetadataProvider()
dt := GCEResourceBuilder{provider: provider}
Expand All @@ -65,6 +72,7 @@ type gceDataProvider interface {
getLabels() (map[string]string, error)
getMetadata() (map[string]string, error)
getInterfaceIPv4s() (map[string]string, error)
getMIG() (gcp.ManagedInstanceGroup, error)
}

// List of single-valued attributes (non-nested)
Expand Down Expand Up @@ -95,20 +103,21 @@ var nestedAttributeSpec = map[gceAttribute]func(gceDataProvider) (map[string]str

// GCEResource implements the Resource interface and provide attributes of the VM when on GCE
type GCEResource struct {
Project string
Zone string
Network string
Subnetwork string
PublicIP string
PrivateIP string
InstanceID string
InstanceName string
Tags string
MachineType string
DefaultScopes []string
Metadata map[string]string
Label map[string]string
InterfaceIPv4 map[string]string
Project string
Zone string
Network string
Subnetwork string
PublicIP string
PrivateIP string
InstanceID string
InstanceName string
Tags string
MachineType string
DefaultScopes []string
Metadata map[string]string
Label map[string]string
InterfaceIPv4 map[string]string
ManagedInstanceGroup gcp.ManagedInstanceGroup
}

func (r GCEResource) ProjectName() string {
Expand Down Expand Up @@ -184,6 +193,20 @@ func (r GCEResource) PrometheusStyleMetadata() map[string]string {
return metaLabels
}

func (r GCEResource) ExtraLogLabels() map[string]string {
l := make(map[string]string)
if r.ManagedInstanceGroup.Name != "" {
l[ManagedInstanceGroupNameLabel] = r.ManagedInstanceGroup.Name
}
switch r.ManagedInstanceGroup.Type {
case gcp.Zone:
l[ManagedInstanceGroupZoneLabel] = r.ManagedInstanceGroup.Location
case gcp.Region:
l[ManagedInstanceGroupRegionLabel] = r.ManagedInstanceGroup.Location
}
return l
}

type GCEResourceBuilderInterface interface {
GetResource() (Resource, error)
}
Expand Down Expand Up @@ -220,21 +243,27 @@ func (gd *GCEResourceBuilder) GetResource() (Resource, error) {
nestedAttributes[attrName] = attr
}

mig, err := gd.provider.getMIG()
if err != nil {
return nil, err
}

res := GCEResource{
Project: singleAttributes[project],
Zone: singleAttributes[zone],
Network: singleAttributes[network],
Subnetwork: singleAttributes[subnetwork],
PublicIP: singleAttributes[publicIP],
PrivateIP: singleAttributes[privateIP],
InstanceID: singleAttributes[instanceID],
InstanceName: singleAttributes[instanceName],
Tags: singleAttributes[tags],
MachineType: singleAttributes[machineType],
DefaultScopes: multiAttributes[defaultScopes],
Metadata: nestedAttributes[metadata],
Label: nestedAttributes[label],
InterfaceIPv4: nestedAttributes[interfaceIPv4],
Project: singleAttributes[project],
Zone: singleAttributes[zone],
Network: singleAttributes[network],
Subnetwork: singleAttributes[subnetwork],
PublicIP: singleAttributes[publicIP],
PrivateIP: singleAttributes[privateIP],
InstanceID: singleAttributes[instanceID],
InstanceName: singleAttributes[instanceName],
Tags: singleAttributes[tags],
MachineType: singleAttributes[machineType],
DefaultScopes: multiAttributes[defaultScopes],
Metadata: nestedAttributes[metadata],
Label: nestedAttributes[label],
InterfaceIPv4: nestedAttributes[interfaceIPv4],
ManagedInstanceGroup: mig,
}
return res, nil
}
6 changes: 6 additions & 0 deletions confgenerator/resourcedetector/gce_detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package resourcedetector
import (
"fmt"
"testing"

"github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp"
)

func TestGettingResourceWithoutError(t *testing.T) {
Expand Down Expand Up @@ -140,3 +142,7 @@ func (fp *FakeProvider) getLabels() (map[string]string, error) {
func (fp *FakeProvider) getInterfaceIPv4s() (map[string]string, error) {
return fp.getMap()
}

func (fp *FakeProvider) getMIG() (gcp.ManagedInstanceGroup, error) {
return gcp.ManagedInstanceGroup{}, nil
}
5 changes: 5 additions & 0 deletions confgenerator/resourcedetector/gce_metadata_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"strings"

gcp_metadata "cloud.google.com/go/compute/metadata"
"github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp"
)

const notAvailable = "NOT AVAILABLE"
Expand Down Expand Up @@ -132,3 +133,7 @@ func (gmp *GCEMetadataProvider) getInterfaceIPv4s() (map[string]string, error) {
}
return interfaces, err
}

func (gmp *GCEMetadataProvider) getMIG() (gcp.ManagedInstanceGroup, error) {
return gcp.NewDetector().GCEManagedInstanceGroup()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

function process(tag, timestamp, record)
local __field_0 = (function()
return record["agent.googleapis.com/log_file_path"]
end)();
local __field_1 = (function()
if record["logging.googleapis.com/labels"] == nil
then
return nil
end
return record["logging.googleapis.com/labels"]["compute.googleapis.com/instance_group_manager/name"]
end)();
local __field_2 = (function()
if record["logging.googleapis.com/labels"] == nil
then
return nil
end
return record["logging.googleapis.com/labels"]["compute.googleapis.com/instance_group_manager/zone"]
end)();
local __field_3 = (function()
if record["logging.googleapis.com/labels"] == nil
then
return nil
end
return record["logging.googleapis.com/labels"]["compute.googleapis.com/resource_name"]
end)();
local __field_4 = (function()
return record["logging.googleapis.com/logName"]
end)();
(function(value)
record["agent.googleapis.com/log_file_path"] = value
end)(nil);
local v = __field_0;
(function(value)
if record["logging.googleapis.com/labels"] == nil
then
record["logging.googleapis.com/labels"] = {}
end
record["logging.googleapis.com/labels"]["agent.googleapis.com/log_file_path"] = value
end)(v)
local v = __field_1;
if v == nil then v = "test-mig" end;
(function(value)
if record["logging.googleapis.com/labels"] == nil
then
record["logging.googleapis.com/labels"] = {}
end
record["logging.googleapis.com/labels"]["compute.googleapis.com/instance_group_manager/name"] = value
end)(v)
local v = __field_2;
if v == nil then v = "test-zone" end;
(function(value)
if record["logging.googleapis.com/labels"] == nil
then
record["logging.googleapis.com/labels"] = {}
end
record["logging.googleapis.com/labels"]["compute.googleapis.com/instance_group_manager/zone"] = value
end)(v)
local v = __field_3;
if v == nil then v = "" end;
(function(value)
if record["logging.googleapis.com/labels"] == nil
then
record["logging.googleapis.com/labels"] = {}
end
record["logging.googleapis.com/labels"]["compute.googleapis.com/resource_name"] = value
end)(v)
local v = __field_4;
if v == nil then v = "syslog" end;
(function(value)
record["logging.googleapis.com/logName"] = value
end)(v)
return 2, timestamp, record
end
Loading

0 comments on commit b0665b3

Please sign in to comment.