Skip to content

Commit

Permalink
Merge branch 'main' into goleak_jmxreceiver
Browse files Browse the repository at this point in the history
  • Loading branch information
crobert-1 committed Mar 15, 2024
2 parents 4dca4f0 + 3351c9d commit 8acc25c
Show file tree
Hide file tree
Showing 14 changed files with 607 additions and 46 deletions.
27 changes: 27 additions & 0 deletions .chloggen/dd-feature-gate-removal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: breaking

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: datadogconnector

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Remove feature gate `connector.datadogconnector.performance`

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [31638]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
13 changes: 13 additions & 0 deletions .chloggen/feat_ottl_xml-parse-function.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: "enhancement"

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add `ParseXML` function for parsing XML from a target string.

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [31133]
8 changes: 0 additions & 8 deletions internal/datadog/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/DataDog/datadog-agent/pkg/trace/timing"
"github.com/DataDog/datadog-go/v5/statsd"
"github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/metrics"
"go.opentelemetry.io/collector/featuregate"
"go.opentelemetry.io/collector/pdata/ptrace"
)

Expand All @@ -38,13 +37,6 @@ type TraceAgent struct {
exit chan struct{}
}

var _ = featuregate.GlobalRegistry().MustRegister(
"connector.datadogconnector.performance",
featuregate.StageStable,
featuregate.WithRegisterDescription("Datadog Connector will use optimized code"),
featuregate.WithRegisterToVersion("0.97.0"),
)

// newAgent creates a new unstarted traceagent using the given context. Call Start to start the traceagent.
// The out channel will receive outoing stats payloads resulting from spans ingested using the Ingest method.
func NewAgent(ctx context.Context, out chan *pb.StatsPayload, metricsClient statsd.ClientInterface, timingReporter timing.Reporter) *TraceAgent {
Expand Down
2 changes: 0 additions & 2 deletions internal/datadog/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ require (
github.com/DataDog/opentelemetry-mapping-go/pkg/otlp/metrics v0.13.4
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/collector/component v0.96.1-0.20240306115632-b2693620eff6
go.opentelemetry.io/collector/featuregate v1.3.1-0.20240306115632-b2693620eff6
go.opentelemetry.io/collector/pdata v1.3.1-0.20240306115632-b2693620eff6
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel/metric v1.24.0
Expand Down Expand Up @@ -46,7 +45,6 @@ require (
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/karrick/godirwalk v1.17.0 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
Expand Down
4 changes: 0 additions & 4 deletions internal/datadog/go.sum

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

37 changes: 18 additions & 19 deletions internal/sqlquery/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/receiver/scraperhelper"
"go.uber.org/multierr"
)

type Config struct {
Expand Down Expand Up @@ -48,36 +47,36 @@ type Query struct {
}

func (q Query) Validate() error {
var errs error
var errs []error
if q.SQL == "" {
errs = multierr.Append(errs, errors.New("'query.sql' cannot be empty"))
errs = append(errs, errors.New("'query.sql' cannot be empty"))
}
if len(q.Logs) == 0 && len(q.Metrics) == 0 {
errs = multierr.Append(errs, errors.New("at least one of 'query.logs' and 'query.metrics' must not be empty"))
errs = append(errs, errors.New("at least one of 'query.logs' and 'query.metrics' must not be empty"))
}
for _, logs := range q.Logs {
if err := logs.Validate(); err != nil {
errs = multierr.Append(errs, err)
errs = append(errs, err)
}
}
for _, metric := range q.Metrics {
if err := metric.Validate(); err != nil {
errs = multierr.Append(errs, err)
errs = append(errs, err)
}
}
return errs
return errors.Join(errs...)
}

type LogsCfg struct {
BodyColumn string `mapstructure:"body_column"`
}

func (config LogsCfg) Validate() error {
var errs error
var errs []error
if config.BodyColumn == "" {
errs = multierr.Append(errs, errors.New("'body_column' must not be empty"))
errs = append(errs, errors.New("'body_column' must not be empty"))
}
return errs
return errors.Join(errs...)
}

type MetricCfg struct {
Expand All @@ -96,29 +95,29 @@ type MetricCfg struct {
}

func (c MetricCfg) Validate() error {
var errs error
var errs []error
if c.MetricName == "" {
errs = multierr.Append(errs, errors.New("'metric_name' cannot be empty"))
errs = append(errs, errors.New("'metric_name' cannot be empty"))
}
if c.ValueColumn == "" {
errs = multierr.Append(errs, errors.New("'value_column' cannot be empty"))
errs = append(errs, errors.New("'value_column' cannot be empty"))
}
if err := c.ValueType.Validate(); err != nil {
errs = multierr.Append(errs, err)
errs = append(errs, err)
}
if err := c.DataType.Validate(); err != nil {
errs = multierr.Append(errs, err)
errs = append(errs, err)
}
if err := c.Aggregation.Validate(); err != nil {
errs = multierr.Append(errs, err)
errs = append(errs, err)
}
if c.DataType == MetricTypeGauge && c.Aggregation != "" {
errs = multierr.Append(errs, fmt.Errorf("aggregation=%s but data_type=%s does not support aggregation", c.Aggregation, c.DataType))
errs = append(errs, fmt.Errorf("aggregation=%s but data_type=%s does not support aggregation", c.Aggregation, c.DataType))
}
if errs != nil && c.MetricName != "" {
errs = multierr.Append(fmt.Errorf("invalid metric config with metric_name '%s'", c.MetricName), errs)
errs = append(errs, fmt.Errorf("invalid metric config with metric_name '%s'", c.MetricName))
}
return errs
return errors.Join(errs...)
}

type MetricType string
Expand Down
8 changes: 4 additions & 4 deletions internal/sqlquery/db_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package sqlquery // import "github.com/open-telemetry/opentelemetry-collector-co

import (
"context"
"errors"

// register Db drivers
_ "github.com/SAP/go-hdb/driver"
Expand All @@ -14,7 +15,6 @@ import (
_ "github.com/microsoft/go-mssqldb/integratedauth/krb5"
_ "github.com/sijms/go-ora/v2"
_ "github.com/snowflakedb/gosnowflake"
"go.uber.org/multierr"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -52,19 +52,19 @@ func (cl DbSQLClient) QueryRows(ctx context.Context, args ...any) ([]StringMap,
return nil, err
}
scanner := newRowScanner(colTypes)
var warnings error
var warnings []error
for sqlRows.Next() {
err = scanner.scan(sqlRows)
if err != nil {
return nil, err
}
sm, scanErr := scanner.toStringMap()
if scanErr != nil {
warnings = multierr.Append(warnings, scanErr)
warnings = append(warnings, scanErr)
}
out = append(out, sm)
}
return out, warnings
return out, errors.Join(warnings...)
}

func (cl DbSQLClient) prepareQueryFields(sql string, args []any) []zap.Field {
Expand Down
14 changes: 9 additions & 5 deletions internal/sqlquery/db_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/multierr"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -90,11 +89,16 @@ func TestDBSQLClient_Nulls_MultiRow(t *testing.T) {
}
rows, err := cl.QueryRows(context.Background())
assert.Error(t, err)
errs := multierr.Errors(err)
for _, err := range errs {
assert.True(t, errors.Is(err, errNullValueWarning))

var e interface{ Unwrap() []error }
if errors.As(err, &e) {
uw := e.Unwrap()
assert.Len(t, uw, 2)

for _, err := range uw {
assert.True(t, errors.Is(err, errNullValueWarning))
}
}
assert.Len(t, errs, 2)
assert.Len(t, rows, 2)
assert.EqualValues(t, map[string]string{
"col_0": "42",
Expand Down
7 changes: 3 additions & 4 deletions internal/sqlquery/scraper.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"go.opentelemetry.io/collector/pdata/pmetric"
"go.opentelemetry.io/collector/receiver/scrapererror"
"go.opentelemetry.io/collector/receiver/scraperhelper"
"go.uber.org/multierr"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -84,17 +83,17 @@ func (s *Scraper) Scrape(ctx context.Context) (pmetric.Metrics, error) {
sms := rm.ScopeMetrics()
sm := sms.AppendEmpty()
ms := sm.Metrics()
var errs error
var errs []error
for _, metricCfg := range s.Query.Metrics {
for i, row := range rows {
if err = rowToMetric(row, metricCfg, ms.AppendEmpty(), s.StartTime, ts, s.ScrapeCfg); err != nil {
err = fmt.Errorf("row %d: %w", i, err)
errs = multierr.Append(errs, err)
errs = append(errs, err)
}
}
}
if errs != nil {
return out, scrapererror.NewPartialScrapeError(errs, len(multierr.Errors(errs)))
return out, scrapererror.NewPartialScrapeError(errors.Join(errs...), len(errs))
}
return out, nil
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/ottl/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,22 @@ func Test_e2e_converters(t *testing.T) {
m.PutStr("k2", "v2__!__v2")
},
},
{
statement: `set(attributes["test"], ParseXML("<Log id=\"1\"><Message>This is a log message!</Message></Log>"))`,
want: func(tCtx ottllog.TransformContext) {
log := tCtx.GetLogRecord().Attributes().PutEmptyMap("test")
log.PutStr("tag", "Log")

attrs := log.PutEmptyMap("attributes")
attrs.PutStr("id", "1")

logChildren := log.PutEmptySlice("children")

message := logChildren.AppendEmpty().SetEmptyMap()
message.PutStr("tag", "Message")
message.PutStr("content", "This is a log message!")
},
},
{
statement: `set(attributes["test"], Seconds(Duration("1m")))`,
want: func(tCtx ottllog.TransformContext) {
Expand Down
73 changes: 73 additions & 0 deletions pkg/ottl/ottlfuncs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ Available Converters:
- [ParseCSV](#parsecsv)
- [ParseJSON](#parsejson)
- [ParseKeyValue](#parsekeyvalue)
- [ParseXML](#parsexml)
- [Seconds](#seconds)
- [SHA1](#sha1)
- [SHA256](#sha256)
Expand Down Expand Up @@ -913,6 +914,78 @@ Examples:
- `ParseKeyValue(attributes["pairs"])`


### ParseXML

`ParseXML(target)`

The `ParseXML` Converter returns a `pcommon.Map` struct that is the result of parsing the target string as an XML document.

`target` is a Getter that returns a string. This string should be in XML format.
If `target` is not a string, nil, or cannot be parsed as XML, `ParseXML` will return an error.

Unmarshalling XML is done using the following rules:
1. All character data for an XML element is trimmed, joined, and placed into the `content` field.
2. The tag for an XML element is trimmed, and placed into the `tag` field.
3. The attributes for an XML element is placed as a `pcommon.Map` into the `attribute` field.
4. Processing instructions, directives, and comments are ignored and not represented in the resultant map.
5. All child elements are parsed as above, and placed in a `pcommon.Slice`, which is then placed into the `children` field.

For example, the following XML document:
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<Log>
<User>
<ID>00001</ID>
<Name type="first">Joe</Name>
<Email>[email protected]</Email>
</User>
<Text>User fired alert A</Text>
</Log>
```

will be parsed as:
```json
{
"tag": "Log",
"children": [
{
"tag": "User",
"children": [
{
"tag": "ID",
"content": "00001"
},
{
"tag": "Name",
"content": "Joe",
"attributes": {
"type": "first"
}
},
{
"tag": "Email",
"content": "[email protected]"
}
]
},
{
"tag": "Text",
"content": "User fired alert A"
}
]
}
```

Examples:

- `ParseXML(body)`

- `ParseXML(attributes["xml"])`

- `ParseXML("<HostInfo hostname=\"example.com\" zone=\"east-1\" cloudprovider=\"aws\" />")`



### Seconds

`Seconds(value)`
Expand Down
Loading

0 comments on commit 8acc25c

Please sign in to comment.