Skip to content

Commit

Permalink
Merge branch 'main' into build_info_internal
Browse files Browse the repository at this point in the history
  • Loading branch information
marctc authored Jul 3, 2024
2 parents 2a1de48 + 84af0d1 commit 9d8108c
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 146 deletions.
69 changes: 37 additions & 32 deletions pkg/internal/export/attributes/attr_defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
// attributes to be reported exclusively for prometheus exporters
var prometheusAttributes = AttrReportGroup{
Disabled: !promEnabled,
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.TargetInstance: true,
attr.ServiceNamespace: true,
},
}
// ServiceName is reported both as resource and metrics attribute, as
// the OTEL definition requires that it is reported as resource attribute
// but Grafana Cloud takes int from the metric
// ServiceName and ServiceNamespace are reported both as resource and metric attributes, as
// the OTEL definition requires that it is reported as resource attribute,
// but Grafana Cloud takes it from the metric
var appAttributes = AttrReportGroup{
SubGroups: []*AttrReportGroup{&prometheusAttributes},
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.ServiceName: true,
attr.ServiceNamespace: true,
},
Expand All @@ -62,7 +62,7 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
// kubernetes metadata is enabled
var networkKubeAttributes = AttrReportGroup{
Disabled: !kubeEnabled,
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.K8sSrcOwnerName: true,
attr.K8sSrcNamespace: true,
attr.K8sDstOwnerName: true,
Expand All @@ -85,7 +85,7 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
// is defined
var networkCIDR = AttrReportGroup{
Disabled: !cidrEnabled,
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.DstCIDR: true,
attr.SrcCIDR: true,
},
Expand All @@ -95,7 +95,7 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
// kubernetes metadata is enabled
var appKubeAttributes = AttrReportGroup{
Disabled: !kubeEnabled,
Attributes: map[attr.Name]Default{
ResourceAttributes: map[attr.Name]Default{
attr.K8sNamespaceName: true,
attr.K8sPodName: true,
attr.K8sDeploymentName: true,
Expand All @@ -111,24 +111,24 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {

var httpRoutes = AttrReportGroup{
Disabled: !groups.Has(GroupHTTPRoutes),
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.HTTPRoute: true,
},
}

var serverInfo = AttrReportGroup{
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.ClientAddr: Default(peerInfoEnabled),
},
}
var httpClientInfo = AttrReportGroup{
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.ServerAddr: Default(peerInfoEnabled),
attr.ServerPort: Default(peerInfoEnabled),
},
}
var grpcClientInfo = AttrReportGroup{
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.ServerAddr: Default(peerInfoEnabled),
},
}
Expand All @@ -138,14 +138,14 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
// via the deprecated BEYLA_METRICS_REPORT_PEER config option
var deprecatedHTTPPath = AttrReportGroup{
Disabled: !groups.Has(GroupTarget),
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.HTTPUrlPath: true,
},
}

var httpCommon = AttrReportGroup{
SubGroups: []*AttrReportGroup{&httpRoutes, &deprecatedHTTPPath},
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.HTTPRequestMethod: true,
attr.HTTPResponseStatusCode: true,
attr.HTTPUrlPath: false,
Expand All @@ -154,14 +154,17 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {

// TODO: populate it with host resource attributes in https://opentelemetry.io/docs/specs/semconv/resource/host/
var hostAttributes = AttrReportGroup{
Attributes: map[attr.Name]Default{
ResourceAttributes: map[attr.Name]Default{
attr.HostName: true,
},
}

var processAttributes = AttrReportGroup{
SubGroups: []*AttrReportGroup{&appKubeAttributes, &hostAttributes},
Attributes: map[attr.Name]Default{
// TODO: attributes below are resource-level, but in App O11y we don't treat processes as resources,
// but applications. Let's first consider how to match processes and Applications before marking this spec
// as stable
MetricAttributes: map[attr.Name]Default{
attr.ProcCommand: true,
attr.ProcCPUState: true,
attr.ProcOwner: true,
Expand All @@ -176,10 +179,18 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
},
}

var messagingAttributes = AttrReportGroup{
SubGroups: []*AttrReportGroup{&appAttributes, &appKubeAttributes},
MetricAttributes: map[attr.Name]Default{
attr.MessagingSystem: true,
attr.MessagingDestination: true,
},
}

return map[Section]AttrReportGroup{
BeylaNetworkFlow.Section: {
SubGroups: []*AttrReportGroup{&networkCIDR, &networkKubeAttributes},
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.BeylaIP: false,
attr.Transport: false,
attr.SrcAddress: false,
Expand All @@ -206,15 +217,15 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
},
RPCClientDuration.Section: {
SubGroups: []*AttrReportGroup{&appAttributes, &appKubeAttributes, &grpcClientInfo},
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.RPCMethod: true,
attr.RPCSystem: true,
attr.RPCGRPCStatusCode: true,
},
},
RPCServerDuration.Section: {
SubGroups: []*AttrReportGroup{&appAttributes, &appKubeAttributes, &serverInfo},
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.RPCMethod: true,
attr.RPCSystem: true,
attr.RPCGRPCStatusCode: true,
Expand All @@ -225,28 +236,20 @@ func getDefinitions(groups AttrGroups) map[Section]AttrReportGroup {
},
DBClientDuration.Section: {
SubGroups: []*AttrReportGroup{&appAttributes, &appKubeAttributes},
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.DBOperation: true,
attr.DBSystem: true,
attr.ErrorType: true,
},
},
MessagingPublishDuration.Section: {
SubGroups: []*AttrReportGroup{&appAttributes, &appKubeAttributes},
Attributes: map[attr.Name]Default{
attr.MessagingSystem: true,
attr.MessagingDestination: true,
},
SubGroups: []*AttrReportGroup{&messagingAttributes},
},
MessagingProcessDuration.Section: {
SubGroups: []*AttrReportGroup{&appAttributes, &appKubeAttributes},
Attributes: map[attr.Name]Default{
attr.MessagingSystem: true,
attr.MessagingDestination: true,
},
SubGroups: []*AttrReportGroup{&messagingAttributes},
},
Traces.Section: {
Attributes: map[attr.Name]Default{
MetricAttributes: map[attr.Name]Default{
attr.DBQueryText: false,
},
},
Expand All @@ -265,7 +268,9 @@ func AllAttributeNames() map[attr.Name]struct{} {
names := map[attr.Name]struct{}{}
// -1 to enable all the metric group flags
for _, section := range getDefinitions(-1) {
maps.Copy(names, section.All())
allNames := section.All()
maps.Copy(names, allNames.Metric)
maps.Copy(names, allNames.Resource)
}
return names
}
19 changes: 14 additions & 5 deletions pkg/internal/export/attributes/attr_getters.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,25 @@ type NamedGetters[T, O any] func(name attr.Name) (Getter[T, O], bool)
// It differentiates two name formats: the exposed name for the attribute (uses _ for word separation, as
// required by Prometheus); and the internal name of the attribute (uses . for word separation, as internally Beyla
// stores the metadata).
func PrometheusGetters[T, O any](getter NamedGetters[T, O], names []attr.Name) []Field[T, O] {
return buildGetterList(getter, names, attr.Name.Prom)
func PrometheusGetters[T, O any](getter NamedGetters[T, O], names Sections[[]attr.Name]) []Field[T, O] {
// at the moment we will still keep prometheus attributes as metric-level
// TODO: move resource-level attributes to target_info metrics
attrNames := make([]attr.Name, 0, len(names.Metric)+len(names.Resource))
attrNames = append(attrNames, names.Metric...)
attrNames = append(attrNames, names.Resource...)
return buildGetterList(getter, attrNames, attr.Name.Prom)
}

// OpenTelemetryGetters builds a list of Getter getters for the names provided by the
// user configuration, ready to be passed to an OpenTelemetry exporter.
func OpenTelemetryGetters[T, O any](getter NamedGetters[T, O], names []attr.Name) []Field[T, O] {
return buildGetterList(getter, names, func(name attr.Name) string {
func OpenTelemetryGetters[T, O any](getter NamedGetters[T, O], names Sections[[]attr.Name]) Sections[[]Field[T, O]] {
otelToStr := func(name attr.Name) string {
return string(name.OTEL())
})
}
return Sections[[]Field[T, O]]{
Resource: buildGetterList(getter, names.Resource, otelToStr),
Metric: buildGetterList(getter, names.Metric, otelToStr),
}
}

func buildGetterList[T, O any](
Expand Down
107 changes: 77 additions & 30 deletions pkg/internal/export/attributes/attr_selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@ type AttrReportGroup struct {
// SubGroups are attribute groups related to this instance. If this instance is
// enabled, they might be also enabled (unless they are explicitly disabled)
SubGroups []*AttrReportGroup
// Attributes map of name: enabled for this group
Attributes map[attr.Name]Default
// MetricAttributes map of name: enabled for this group. It refers to metric-level attributes.
MetricAttributes map[attr.Name]Default
// ResourceAttributes is like MetricAttributes but for resources (OTEL) or target_info (Prometheus)
ResourceAttributes map[attr.Name]Default
}

// Sections classifies some attribute-related groups between Metric and Resource attributes
type Sections[T any] struct {
Metric T
Resource T
}

// AttrSelector returns, for each metric, the attributes that have to be reported
Expand All @@ -44,68 +52,107 @@ func NewAttrSelector(groups AttrGroups, selectorCfg Selection) (*AttrSelector, e
}

// For returns the list of attribute names for a given metric
func (p *AttrSelector) For(metricName Name) []attr.Name {
metricAttributes, ok := p.definition[metricName.Section]
func (p *AttrSelector) For(metricName Name) Sections[[]attr.Name] {
attributeNames, ok := p.definition[metricName.Section]
if !ok {
panic(fmt.Sprintf("BUG! metric not found %+v", metricName))
}
inclusionLists, ok := p.selector[metricName.Section]
if !ok {
attrs := attributeNames.Default()
// if the user did not provide any selector, return the default attributes for that metric
attrs := helpers.SetToSlice(metricAttributes.Default())
slices.Sort(attrs)
return attrs
sas := Sections[[]attr.Name]{
Metric: helpers.SetToSlice(attrs.Metric),
Resource: helpers.SetToSlice(attrs.Resource),
}
slices.Sort(sas.Metric)
slices.Sort(sas.Resource)
return sas
}
var addAttributes map[attr.Name]struct{}
var addAttributes Sections[map[attr.Name]struct{}]
// if the "include" list is empty, we use the default attributes
// as included
if len(inclusionLists.Include) == 0 {
addAttributes = metricAttributes.Default()
addAttributes = attributeNames.Default()
} else {
addAttributes = map[attr.Name]struct{}{}
for attrName := range metricAttributes.All() {
addAttributes = Sections[map[attr.Name]struct{}]{
Metric: map[attr.Name]struct{}{},
Resource: map[attr.Name]struct{}{},
}
allAttributes := attributeNames.All()
for attrName := range allAttributes.Metric {
if inclusionLists.includes(attrName) {
addAttributes[attrName] = struct{}{}
addAttributes.Metric[attrName] = struct{}{}
}
}
for attrName := range allAttributes.Resource {
if inclusionLists.includes(attrName) {
addAttributes.Resource[attrName] = struct{}{}
}
}
}
// now remove any attribute specified in the "exclude" list
maps.DeleteFunc(addAttributes, func(attr attr.Name, _ struct{}) bool {
maps.DeleteFunc(addAttributes.Metric, func(attr attr.Name, _ struct{}) bool {
return inclusionLists.excludes(attr)
})
maps.DeleteFunc(addAttributes.Resource, func(attr attr.Name, _ struct{}) bool {
return inclusionLists.excludes(attr)
})
attrs := helpers.SetToSlice(addAttributes)
slices.Sort(attrs)
return attrs
sas := Sections[[]attr.Name]{
Metric: helpers.SetToSlice(addAttributes.Metric),
Resource: helpers.SetToSlice(addAttributes.Resource),
}
slices.Sort(sas.Metric)
slices.Sort(sas.Resource)
return sas
}

// All te attributes for this group and their subgroups, unless they are disabled.
func (p *AttrReportGroup) All() map[attr.Name]struct{} {
func (p *AttrReportGroup) All() Sections[map[attr.Name]struct{}] {
sas := Sections[map[attr.Name]struct{}]{
Metric: map[attr.Name]struct{}{},
Resource: map[attr.Name]struct{}{},
}
if p.Disabled {
return map[attr.Name]struct{}{}
return sas
}
attrs := map[attr.Name]struct{}{}
for _, parent := range p.SubGroups {
maps.Copy(attrs, parent.All())
psas := parent.All()
maps.Copy(sas.Metric, psas.Metric)
maps.Copy(sas.Resource, psas.Resource)
}
for k := range p.MetricAttributes {
sas.Metric[k] = struct{}{}
}
for k := range p.Attributes {
attrs[k] = struct{}{}
for k := range p.ResourceAttributes {
sas.Resource[k] = struct{}{}
}
return attrs
return sas
}

// Default attributes for this group and their subgroups, unless they are disabled.
func (p *AttrReportGroup) Default() map[attr.Name]struct{} {
func (p *AttrReportGroup) Default() Sections[map[attr.Name]struct{}] {
sas := Sections[map[attr.Name]struct{}]{
Metric: map[attr.Name]struct{}{},
Resource: map[attr.Name]struct{}{},
}
if p.Disabled {
return map[attr.Name]struct{}{}
return sas
}
attrs := map[attr.Name]struct{}{}
for _, parent := range p.SubGroups {
maps.Copy(attrs, parent.Default())
psas := parent.Default()
maps.Copy(sas.Metric, psas.Metric)
maps.Copy(sas.Resource, psas.Resource)
}
for k, def := range p.MetricAttributes {
if def {
sas.Metric[k] = struct{}{}
}
}
for k, def := range p.Attributes {
for k, def := range p.ResourceAttributes {
if def {
attrs[k] = struct{}{}
sas.Resource[k] = struct{}{}
}
}
return attrs
return sas
}
Loading

0 comments on commit 9d8108c

Please sign in to comment.