From d8803e84d0c311d6538728e9ccc6081f54ff5c0f Mon Sep 17 00:00:00 2001 From: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> Date: Sun, 7 Jan 2024 19:20:59 -0700 Subject: [PATCH] [pkg/ottl] Add e2e tests (#30152) **Description:** Adds e2e tests for OTTL functionality and all `ottlfuncs` functions. Includes the bug fix from https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/30151 **Link to tracking Issue:** Closes https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/28642 **Testing:** **Documentation:** Updated contributing doc --- pkg/ottl/CONTRIBUTING.md | 2 +- pkg/ottl/e2e/e2e_test.go | 603 +++++++++++++++++++++++++++++++++++ pkg/ottl/go.mod | 3 + pkg/ottl/go.sum | 2 + pkg/ottl/ottlfuncs/README.md | 4 +- 5 files changed, 611 insertions(+), 3 deletions(-) create mode 100644 pkg/ottl/e2e/e2e_test.go diff --git a/pkg/ottl/CONTRIBUTING.md b/pkg/ottl/CONTRIBUTING.md index cb7c9f216121..c644810d2c49 100644 --- a/pkg/ottl/CONTRIBUTING.md +++ b/pkg/ottl/CONTRIBUTING.md @@ -19,7 +19,7 @@ When adding new values to the grammar you must: All new functions must be added via a new file. Function files must start with `func_`. Functions must be placed in `ottlfuncs`. -Unit tests must be added for all new functions. Unit test files must start with `func_` and end in `_test`. Unit tests must be placed in the same directory as the function. Functions that are not specific to a pipeline should be tested independently of any specific pipeline. Functions that are specific to a pipeline should be tests against that pipeline. +Unit tests must be added for all new functions. Unit test files must start with `func_` and end in `_test`. Unit tests must be placed in the same directory as the function. Functions that are not specific to a pipeline should be tested independently of any specific pipeline. Functions that are specific to a pipeline should be tests against that pipeline. End-to-end tests must be added in the `e2e` directory. Function names should follow the [Function Syntax Guidelines](ottlfuncs/README.md#function-syntax) diff --git a/pkg/ottl/e2e/e2e_test.go b/pkg/ottl/e2e/e2e_test.go new file mode 100644 index 000000000000..f7075bdd4d47 --- /dev/null +++ b/pkg/ottl/e2e/e2e_test.go @@ -0,0 +1,603 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package e2e + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" +) + +var ( + TestLogTime = time.Date(2020, 2, 11, 20, 26, 12, 321, time.UTC) + TestLogTimestamp = pcommon.NewTimestampFromTime(TestLogTime) + + TestObservedTime = time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC) + TestObservedTimestamp = pcommon.NewTimestampFromTime(TestObservedTime) + + traceID = [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + spanID = [8]byte{1, 2, 3, 4, 5, 6, 7, 8} +) + +func Test_e2e_editors(t *testing.T) { + tests := []struct { + statement string + want func(tCtx ottllog.TransformContext) + }{ + { + statement: `delete_key(attributes, "http.method")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().Remove("http.method") + }, + }, + { + statement: `delete_matching_keys(attributes, "^http")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().Remove("http.method") + tCtx.GetLogRecord().Attributes().Remove("http.path") + tCtx.GetLogRecord().Attributes().Remove("http.url") + }, + }, + { + statement: `keep_keys(attributes, ["flags", "total.string"])`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().Remove("http.method") + tCtx.GetLogRecord().Attributes().Remove("http.path") + tCtx.GetLogRecord().Attributes().Remove("http.url") + tCtx.GetLogRecord().Attributes().Remove("foo") + }, + }, + { + statement: `limit(attributes, 100, [])`, + want: func(tCtx ottllog.TransformContext) {}, + }, + { + statement: `limit(attributes, 1, ["total.string"])`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().Remove("http.method") + tCtx.GetLogRecord().Attributes().Remove("http.path") + tCtx.GetLogRecord().Attributes().Remove("http.url") + tCtx.GetLogRecord().Attributes().Remove("flags") + tCtx.GetLogRecord().Attributes().Remove("foo") + }, + }, + { + statement: `merge_maps(attributes, attributes["foo"], "insert")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("bar", "pass") + }, + }, + { + statement: `merge_maps(attributes, attributes["foo"], "update")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("flags", "pass") + }, + }, + { + statement: `merge_maps(attributes, attributes["foo"], "upsert")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("bar", "pass") + tCtx.GetLogRecord().Attributes().PutStr("flags", "pass") + }, + }, + { + statement: `replace_all_matches(attributes, "*/*", "test")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("http.path", "test") + tCtx.GetLogRecord().Attributes().PutStr("http.url", "test") + }, + }, + { + statement: `replace_all_patterns(attributes, "key", "^http", "test")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().Remove("http.method") + tCtx.GetLogRecord().Attributes().Remove("http.path") + tCtx.GetLogRecord().Attributes().Remove("http.url") + tCtx.GetLogRecord().Attributes().PutStr("test.method", "get") + tCtx.GetLogRecord().Attributes().PutStr("test.path", "/health") + tCtx.GetLogRecord().Attributes().PutStr("test.url", "http://localhost/health") + }, + }, + { + statement: `replace_all_patterns(attributes, "value", "/", "@")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("http.path", "@health") + tCtx.GetLogRecord().Attributes().PutStr("http.url", "http:@@localhost@health") + }, + }, + { + statement: `replace_match(attributes["http.path"], "*/*", "test")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("http.path", "test") + }, + }, + { + statement: `replace_pattern(attributes["http.path"], "/", "@")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("http.path", "@health") + }, + }, + { + statement: `set(attributes["test"], "pass")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], nil)`, + want: func(tCtx ottllog.TransformContext) {}, + }, + { + statement: `set(attributes["test"], attributes["unknown"])`, + want: func(tCtx ottllog.TransformContext) {}, + }, + { + statement: `set(attributes["foo"]["test"], "pass")`, + want: func(tCtx ottllog.TransformContext) { + v, _ := tCtx.GetLogRecord().Attributes().Get("foo") + v.Map().PutStr("test", "pass") + }, + }, + { + statement: `truncate_all(attributes, 100)`, + want: func(tCtx ottllog.TransformContext) {}, + }, + { + statement: `truncate_all(attributes, 1)`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("http.method", "g") + tCtx.GetLogRecord().Attributes().PutStr("http.path", "/") + tCtx.GetLogRecord().Attributes().PutStr("http.url", "h") + tCtx.GetLogRecord().Attributes().PutStr("flags", "A") + tCtx.GetLogRecord().Attributes().PutStr("total.string", "1") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.statement, func(t *testing.T) { + settings := componenttest.NewNopTelemetrySettings() + logParser, err := ottllog.NewParser(ottlfuncs.StandardFuncs[ottllog.TransformContext](), settings) + assert.NoError(t, err) + logStatements, err := logParser.ParseStatement(tt.statement) + assert.NoError(t, err) + + tCtx := constructLogTransformContext() + _, _, _ = logStatements.Execute(context.Background(), tCtx) + + exTCtx := constructLogTransformContext() + tt.want(exTCtx) + + assert.NoError(t, plogtest.CompareResourceLogs(newResourceLogs(exTCtx), newResourceLogs(tCtx))) + }) + } +} + +func Test_e2e_converters(t *testing.T) { + tests := []struct { + statement string + want func(tCtx ottllog.TransformContext) + }{ + { + statement: `set(attributes["test"], Concat(["A","B"], ":"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "A:B") + }, + }, + { + statement: `set(attributes["test"], ConvertCase(attributes["http.method"], "upper"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "GET") + }, + }, + { + statement: `set(attributes["test"], ConvertCase("PASS", "lower"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], ConvertCase("fooBar", "snake"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "foo_bar") + }, + }, + { + statement: `set(attributes["test"], ConvertCase("foo_bar", "camel"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "FooBar") + }, + }, + { + statement: `set(attributes["test"], Double(1.0))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 1.0) + }, + }, + { + statement: `set(attributes["test"], Double("1"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 1.0) + }, + }, + { + statement: `set(attributes["test"], Double(true))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 1.0) + }, + }, + { + statement: `set(attributes["test"], Double(1))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 1.0) + }, + }, + { + statement: `set(attributes["test"], "pass") where Time("10", "%M") - Time("01", "%M") < Duration("10m")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], ExtractPatterns("aa123bb", "(?P\\d+)"))`, + want: func(tCtx ottllog.TransformContext) { + m := tCtx.GetLogRecord().Attributes().PutEmptyMap("test") + m.PutStr("numbers", "123") + }, + }, + { + statement: `set(attributes["test"], FNV("pass"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 266877920130663416) + }, + }, + { + statement: `set(attributes["test"], Hour(Time("12", "%H")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 12) + }, + }, + { + statement: `set(attributes["test"], Hours(Duration("90m")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 1.5) + }, + }, + { + statement: `set(attributes["test"], Int(1.0))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1) + }, + }, + { + statement: `set(attributes["test"], Int("1"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1) + }, + }, + { + statement: `set(attributes["test"], Int(true))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1) + }, + }, + { + statement: `set(attributes["test"], Int(1))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1) + }, + }, + { + statement: `set(attributes["test"], "pass") where IsBool(false)`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where IsDouble(1.0)`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where IsMap(attributes["foo"])`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where IsMatch("aa123bb", "\\d{3}")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where IsString("")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], Len(attributes["foo"]))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 2) + }, + }, + { + statement: `set(attributes["test"], Log(1))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 0) + }, + }, + { + statement: `set(attributes["test"], Microseconds(Duration("1ms")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1000) + }, + }, + { + statement: `set(attributes["test"], Milliseconds(Duration("1s")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1000) + }, + }, + { + statement: `set(attributes["test"], Minutes(Duration("1h")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 60) + }, + }, + { + statement: `set(attributes["test"], Nanoseconds(Duration("1ms")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutInt("test", 1000000) + }, + }, + { + statement: `set(attributes["test"], "pass") where Now() - Now() < Duration("1h")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], ParseJSON("{\"id\":1}"))`, + want: func(tCtx ottllog.TransformContext) { + m := tCtx.GetLogRecord().Attributes().PutEmptyMap("test") + m.PutDouble("id", 1) + }, + }, + { + statement: `set(attributes["test"], Seconds(Duration("1m")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutDouble("test", 60) + }, + }, + { + statement: `set(attributes["test"], SHA1("pass"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684") + }, + }, + { + statement: `set(attributes["test"], SHA256("pass"))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "d74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1") + }, + }, + { + statement: `set(span_id, SpanID(0x0000000000000000))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().SetSpanID(pcommon.NewSpanIDEmpty()) + }, + }, + { + statement: `set(attributes["test"], Split(attributes["flags"], "|"))`, + want: func(tCtx ottllog.TransformContext) { + s := tCtx.GetLogRecord().Attributes().PutEmptySlice("test") + s.AppendEmpty().SetStr("A") + s.AppendEmpty().SetStr("B") + s.AppendEmpty().SetStr("C") + }, + }, + { + statement: `set(attributes["test"], Substring("pass", 0, 2))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pa") + }, + }, + { + statement: `set(trace_id, TraceID(0x00000000000000000000000000000000))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().SetTraceID(pcommon.NewTraceIDEmpty()) + }, + }, + { + statement: `set(time, TruncateTime(time, Duration("1s")))`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().SetTimestamp(pcommon.NewTimestampFromTime(TestLogTimestamp.AsTime().Truncate(time.Second))) + }, + }, + { + statement: `set(attributes["test"], "pass") where UnixMicro(time) > 0`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where UnixMilli(time) > 0`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where UnixNano(time) > 0`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where UnixSeconds(time) > 0`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + statement: `set(attributes["test"], "pass") where IsString(UUID())`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.statement, func(t *testing.T) { + settings := componenttest.NewNopTelemetrySettings() + logParser, err := ottllog.NewParser(ottlfuncs.StandardFuncs[ottllog.TransformContext](), settings) + assert.NoError(t, err) + logStatements, err := logParser.ParseStatement(tt.statement) + assert.NoError(t, err) + + tCtx := constructLogTransformContext() + _, _, _ = logStatements.Execute(context.Background(), tCtx) + + exTCtx := constructLogTransformContext() + tt.want(exTCtx) + + assert.NoError(t, plogtest.CompareResourceLogs(newResourceLogs(exTCtx), newResourceLogs(tCtx))) + }) + } +} + +func Test_e2e_ottl_features(t *testing.T) { + tests := []struct { + name string + statement string + want func(tCtx ottllog.TransformContext) + }{ + { + name: "where clause", + statement: `set(attributes["test"], "pass") where body == "operationB"`, + want: func(tCtx ottllog.TransformContext) {}, + }, + { + name: "reach upwards", + statement: `set(attributes["test"], "pass") where resource.attributes["host.name"] == "localhost"`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + name: "Using enums", + statement: `set(severity_number, SEVERITY_NUMBER_TRACE2) where severity_number == SEVERITY_NUMBER_TRACE`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().SetSeverityNumber(2) + }, + }, + { + name: "Using hex", + statement: `set(attributes["test"], "pass") where trace_id == TraceID(0x0102030405060708090a0b0c0d0e0f10)`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + name: "where clause without comparator", + statement: `set(attributes["test"], "pass") where IsMatch(body, "operation[AC]")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + name: "where clause with Converter return value", + statement: `set(attributes["test"], "pass") where body == Concat(["operation", "A"], "")`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + name: "composing functions", + statement: `merge_maps(attributes, ParseJSON("{\"json_test\":\"pass\"}"), "insert") where body == "operationA"`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("json_test", "pass") + }, + }, + { + name: "complex indexing found", + statement: `set(attributes["test"], attributes["foo"]["bar"])`, + want: func(tCtx ottllog.TransformContext) { + tCtx.GetLogRecord().Attributes().PutStr("test", "pass") + }, + }, + { + name: "complex indexing not found", + statement: `set(attributes["test"], attributes["metadata"]["uid"])`, + want: func(tCtx ottllog.TransformContext) {}, + }, + } + + for _, tt := range tests { + t.Run(tt.statement, func(t *testing.T) { + settings := componenttest.NewNopTelemetrySettings() + logParser, err := ottllog.NewParser(ottlfuncs.StandardFuncs[ottllog.TransformContext](), settings) + assert.NoError(t, err) + logStatements, err := logParser.ParseStatement(tt.statement) + assert.NoError(t, err) + + tCtx := constructLogTransformContext() + _, _, _ = logStatements.Execute(context.Background(), tCtx) + + exTCtx := constructLogTransformContext() + tt.want(exTCtx) + + assert.NoError(t, plogtest.CompareResourceLogs(newResourceLogs(exTCtx), newResourceLogs(tCtx))) + }) + } +} + +func constructLogTransformContext() ottllog.TransformContext { + resource := pcommon.NewResource() + resource.Attributes().PutStr("host.name", "localhost") + + scope := pcommon.NewInstrumentationScope() + scope.SetName("scope") + + logRecord := plog.NewLogRecord() + logRecord.Body().SetStr("operationA") + logRecord.SetTimestamp(TestLogTimestamp) + logRecord.SetObservedTimestamp(TestObservedTimestamp) + logRecord.SetDroppedAttributesCount(1) + logRecord.SetFlags(plog.DefaultLogRecordFlags.WithIsSampled(true)) + logRecord.SetSeverityNumber(1) + logRecord.SetTraceID(traceID) + logRecord.SetSpanID(spanID) + logRecord.Attributes().PutStr("http.method", "get") + logRecord.Attributes().PutStr("http.path", "/health") + logRecord.Attributes().PutStr("http.url", "http://localhost/health") + logRecord.Attributes().PutStr("flags", "A|B|C") + logRecord.Attributes().PutStr("total.string", "123456789") + m := logRecord.Attributes().PutEmptyMap("foo") + m.PutStr("bar", "pass") + m.PutStr("flags", "pass") + + return ottllog.NewTransformContext(logRecord, scope, resource) +} + +func newResourceLogs(tCtx ottllog.TransformContext) plog.ResourceLogs { + rl := plog.NewResourceLogs() + tCtx.GetResource().CopyTo(rl.Resource()) + sl := rl.ScopeLogs().AppendEmpty() + tCtx.GetInstrumentationScope().CopyTo(sl.Scope()) + l := sl.LogRecords().AppendEmpty() + tCtx.GetLogRecord().CopyTo(l) + return rl +} diff --git a/pkg/ottl/go.mod b/pkg/ottl/go.mod index ae69c1d64d7f..6b5ba9cfc3bb 100644 --- a/pkg/ottl/go.mod +++ b/pkg/ottl/go.mod @@ -9,6 +9,7 @@ require ( github.com/iancoleman/strcase v0.3.0 github.com/json-iterator/go v1.1.12 github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.91.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.91.0 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector/component v0.91.0 go.opentelemetry.io/collector/pdata v1.0.0 @@ -18,6 +19,7 @@ require ( ) require ( + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -30,6 +32,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.91.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.91.0 // indirect go.opentelemetry.io/collector/confmap v0.91.0 // indirect diff --git a/pkg/ottl/go.sum b/pkg/ottl/go.sum index 6c695c405e94..a59f656174ab 100644 --- a/pkg/ottl/go.sum +++ b/pkg/ottl/go.sum @@ -2,6 +2,8 @@ github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVd github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/pkg/ottl/ottlfuncs/README.md b/pkg/ottl/ottlfuncs/README.md index 53b9f46084dd..b22aba970849 100644 --- a/pkg/ottl/ottlfuncs/README.md +++ b/pkg/ottl/ottlfuncs/README.md @@ -5,7 +5,7 @@ interact with OTel data via the Collector's internal data model, [pdata](https:/ This document contains documentation for both types of OTTL functions: -- [Functions](#functions) that transform telemetry. +- [Editors](#editors) that transform telemetry. - [Converters](#converters) that provide utilities for transforming telemetry. ## Design principles @@ -631,7 +631,7 @@ Examples: `Log(value)` -The `Log` Converter returns the logarithm of the `target`. +The `Log` Converter returns a `float64` that is the logarithm of the `target`. `target` is either a path expression to a telemetry field to retrieve or a literal.