Skip to content

Commit

Permalink
PR review fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ptodev committed Apr 18, 2023
1 parent bfea751 commit 6776869
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 44 deletions.
32 changes: 11 additions & 21 deletions component/otelcol/config_attraction.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,27 +77,17 @@ type AttrActionKeyValue struct {

// Convert converts args into the upstream type.
func (args *AttrActionKeyValue) convert() map[string]interface{} {
res := make(map[string]interface{})

// Mandatory attributes - always set those
res["key"] = args.Key
res["action"] = args.Action

// Optional attributes
if args.Value != "" {
res["value"] = args.Value
}
if args.RegexPattern != "" {
res["pattern"] = args.RegexPattern
}
if args.FromAttribute != "" {
res["from_attribute"] = args.FromAttribute
if args == nil {
return nil
}
if args.FromContext != "" {
res["from_context"] = args.FromContext
}
if args.ConvertedType != "" {
res["converted_type"] = args.ConvertedType

return map[string]interface{}{
"key": args.Key,
"action": args.Action,
"value": args.Value,
"pattern": args.RegexPattern,
"from_attribute": args.FromAttribute,
"from_context": args.FromContext,
"converted_type": args.ConvertedType,
}
return res
}
65 changes: 62 additions & 3 deletions component/otelcol/config_filter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package otelcol

import "strings"
import (
"encoding"
"fmt"
"strings"

"go.opentelemetry.io/collector/pdata/plog"
)

// MatchConfig has two optional MatchProperties:
// 1. 'include': to define what is processed by the processor.
Expand Down Expand Up @@ -204,16 +210,69 @@ func (args InstrumentationLibrary) convert() map[string]interface{} {
type LogSeverityNumberMatchProperties struct {
// Min is the lowest severity that may be matched.
// e.g. if this is plog.SeverityNumberInfo, INFO, WARN, ERROR, and FATAL logs will match.
Min int32 `river:"min,attr"`
Min SeverityLevel `river:"min,attr"`

// MatchUndefined controls whether logs with "undefined" severity matches.
// If this is true, entries with undefined severity will match.
MatchUndefined bool `river:"match_undefined,attr"`
}

func (args LogSeverityNumberMatchProperties) convert() map[string]interface{} {
numVal, exists := severityLevels[args.Min]
if !exists {
panic(fmt.Sprintf("No severity value for %q", args.Min))
}

return map[string]interface{}{
"min": args.Min,
"min": numVal,
"match_undefined": args.MatchUndefined,
}
}

type SeverityLevel string

var (
_ encoding.TextUnmarshaler = (*SeverityLevel)(nil)
)

// The severity levels should be in sync with "opentelemetry-collector/pdata/plog/logs.go"
var severityLevels = map[SeverityLevel]int32{
"TRACE": 1,
"TRACE2": 2,
"TRACE3": 3,
"TRACE4": 4,
"DEBUG": 5,
"DEBUG2": 6,
"DEBUG3": 7,
"DEBUG4": 8,
"INFO": 9,
"INFO2": 10,
"INFO3": 11,
"INFO4": 12,
"WARN": 13,
"WARN2": 14,
"WARN3": 15,
"WARN4": 16,
"ERROR": 17,
"ERROR2": 18,
"ERROR3": 19,
"ERROR4": 20,
"FATAL": 21,
"FATAL2": 22,
"FATAL3": 23,
"FATAL4": 24,
}

// UnmarshalText implements encoding.TextUnmarshaler for SeverityLevel.
func (sl *SeverityLevel) UnmarshalText(text []byte) error {
if numVal, exists := severityLevels[SeverityLevel(text)]; exists {
// Check if this is a valid plog severity number
plogInt := plog.SeverityNumber(numVal)
plogStr := plogInt.String()
if plogStr == "SEVERITY_NUMBER_"+string(text) {
*sl = SeverityLevel(text)
return nil
}
}
return fmt.Errorf("unrecognized severity level %q", string(text))
}
89 changes: 88 additions & 1 deletion component/otelcol/config_filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/grafana/agent/component/otelcol"
"github.com/grafana/agent/pkg/river"
"github.com/stretchr/testify/require"
"k8s.io/utils/pointer"
)
Expand All @@ -20,7 +21,7 @@ func TestConvertMatchProperties(t *testing.T) {
LogBodies: []string{"AUTH.*"},
LogSeverityTexts: []string{"debug.*"},
LogSeverityNumber: &otelcol.LogSeverityNumberMatchProperties{
Min: 2,
Min: "TRACE2",
MatchUndefined: true,
},
MetricNames: []string{"metric1"},
Expand Down Expand Up @@ -169,3 +170,89 @@ func TestConvertMatchProperties(t *testing.T) {
}
}
}

func TestUnmarshalSeverityLevel(t *testing.T) {
for _, tt := range []struct {
name string
cfg string
expectErr bool
}{
{
name: "valid TRACE config",
cfg: `
min = "TRACE"
match_undefined = true
`,
},
{
name: "valid DEBUG config",
cfg: `
min = "DEBUG"
match_undefined = true
`,
},
{
name: "valid INFO config",
cfg: `
min = "INFO"
match_undefined = true
`,
},
{
name: "valid WARN config",
cfg: `
min = "WARN"
match_undefined = true
`,
},
{
name: "valid ERROR config",
cfg: `
min = "ERROR"
match_undefined = true
`,
},
{
name: "valid FATAL config",
cfg: `
min = "FATAL"
match_undefined = true
`,
},
{
name: "valid FATAL4 config",
cfg: `
min = "FATAL4"
match_undefined = true
`,
},
{
name: "invalid lowercase sev level",
cfg: `
min = "trace"
match_undefined = true
`,
expectErr: true,
},
{
name: "non-existent sev level",
cfg: `
min = "foo"
match_undefined = true
`,
expectErr: true,
},
} {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var sl otelcol.LogSeverityNumberMatchProperties
err := river.Unmarshal([]byte(tt.cfg), &sl)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
2 changes: 1 addition & 1 deletion component/otelcol/processor/attributes/attributes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ func TestDecode_Regexp2(t *testing.T) {
include {
match_type = "regexp"
attribute {
key = "env"
key = "db.statement"
value = "SELECT \\* FROM USERS.*"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ Hierarchy | Block | Description | Required
--------- | ----- | ----------- | --------
output | [output][] | Configures where to send received telemetry data. | yes
action | [action][] | Actions to take on the attributes of incoming metrics/logs/traces. | no
include | [include/exclude][] | Filter for data to be included to this processor's actions. | no
include | [include][] | Filter for data to be included to this processor's actions. | no
include > regexp | [regexp][] | Regex cache settings. | no
include > attribute | [attribute][] | A list of attributes to match against. | no
include > resource | [resource][] | A list of items to match the resources against. | no
include > library | [library][] | A list of items to match the implementation library against. | no
include > log_severity_number | [library][] | How to match against a log record's SeverityNumber, if defined. | no
exclude | [include/exclude][] | Filter for data to be excluded from this processor's actions | no
exclude | [exclude][] | Filter for data to be excluded from this processor's actions | no
exclude > regexp | [regexp][] | Regex cache settings. | no
exclude > attribute | [attribute][] | A list of attributes to match against. | no
exclude > resource | [resource][] | A list of items to match the resources against. | no
Expand Down Expand Up @@ -180,45 +180,55 @@ Cache size is unlimited unless `cachemaxnumentries` is also specified.

### attribute block

This block specifies a list of attributes to match against.
Only `match_type = "strict"` is allowed if `attribute` is specified.
This block specifies an attribute to match against:

* More than one `attribute` block can be defined.
* Only `match_type = "strict"` is allowed if `attribute` is specified.
* All `attribute` blocks must match exactly for a match to occur.

The following arguments are supported:

Name | Type | Description | Default | Required
---- | ---- | ----------- | ------- | --------
`key` | `string` | The attribute key. | | yes
`value` | `any` | The value to match against. | | no
`value` | `any` | The attribute value to match against. | | no

If `value` is not set, any value will match.
The type of `value` could be a number, a string or a boolean.

### resource block

This block specifies items to match the resources against.
A match occurs if the input data resources matches at least one `resource` block.
This block specifies items to match the resources against:

* More than one `resource` block can be defined.
* A match occurs if the input data resources matches at least one `resource` block.

The following arguments are supported:

Name | Type | Description | Default | Required
---- | ---- | ----------- | ------- | --------
`key` | `string` | The attribute key. | | yes
`value` | `any` | The value to match against. | | no
`key` | `string` | The resource key. | | yes
`value` | `any` | The resource value to match against. | | no

If `value` is not set, any value will match.
The type of `value` could be a number, a string or a boolean.

### library block

This block specifies items to match the implementation library against.
A match occurs if the span's implementation library matches at least one `library` block.
This block specifies properties to match the implementation library against:

* More than one `library` block can be defined.
* A match occurs if the span's implementation library matches at least one `library` block.

The following arguments are supported:

Name | Type | Description | Default | Required
---- | ---- | ----------- | ------- | --------
`name` | `string` | The attribute key. | | yes
`version` | | The value to match against. | | yes
`version` | `string` | The version to match against. | null | no

If `version` is unset, any version will match. If `version` is set to an empty string, it will only match
a library version which is also an empty string.

### log_severity_number block

Expand All @@ -228,14 +238,43 @@ The following arguments are supported:

Name | Type | Description | Default | Required
---- | ---- | ----------- | ------- | --------
`min` | `int` | The lowest severity that may be matched. | | yes
`match_undefined` | `bool` | Whether logs with "undefined" severity matches. | | yes

For example, if `min` is plog.SeverityNumberInfo,
INFO, WARN, ERROR, and FATAL logs will match.
`min` | `string` | The lowest severity that may be matched. | | yes
`match_undefined` | `bool` | Whether logs with "undefined" severity match. | | yes

If `match_undefined` is true, entries with undefined severity will match.

The severity numbers supported by Otel are listed in the table below.

Log Severity | Severity number
------------ | ---------------
TRACE | 1
TRACE2 | 2
TRACE3 | 3
TRACE4 | 4
DEBUG | 5
DEBUG2 | 6
DEBUG3 | 7
DEBUG4 | 8
INFO | 9
INFO2 | 10
INFO3 | 11
INFO4 | 12
WARN | 13
WARN2 | 14
WARN3 | 15
WARN4 | 16
ERROR | 17
ERROR2 | 18
ERROR3 | 19
ERROR4 | 20
FATAL | 21
FATAL2 | 22
FATAL3 | 23
FATAL4 | 24

For example, if the `min` attribute in the `log_severity_number` block is "INFO", then
INFO, WARN, ERROR, and FATAL logs will match.

### output block

{{< docs/shared lookup="flow/reference/components/output-block.md" source="agent" >}}
Expand Down Expand Up @@ -518,7 +557,7 @@ otelcol.processor.attributes "default" {
// This attribute ('db.statement') must exist in the span and match
// the regex ('SELECT \* FROM USERS.*') for a match.
attribute {
key = "env"
key = "db.statement"
value = "SELECT \* FROM USERS.*"
}
}
Expand Down

0 comments on commit 6776869

Please sign in to comment.