Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg/ottl] Change OTTL contexts to handle paths with context #36820

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .chloggen/change-contexts-to-support-path-with-context.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: 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: "Change OTTL contexts to properly handle `ottl.Path` with context"

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

# (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: "The OTTL contexts have a new option `EnablePathContextNames` to enable support for expressing a statement's context via path names in the statement"

# 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: [api]
6 changes: 5 additions & 1 deletion pkg/ottl/contexts/internal/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

const (
MetricContextName = "metric"
)

type MetricContext interface {
GetMetric() pmetric.Metric
}
Expand All @@ -29,7 +33,7 @@ var MetricSymbolTable = map[ottl.EnumSymbol]ottl.Enum{

func MetricPathGetSetter[K MetricContext](path ottl.Path[K]) (ottl.GetSetter[K], error) {
if path == nil {
return nil, FormatDefaultErrorMessage("metric", "metric", "Metric", MetricRef)
return nil, FormatDefaultErrorMessage(MetricContextName, MetricContextName, "Metric", MetricRef)
}
switch path.Name() {
case "name":
Expand Down
6 changes: 5 additions & 1 deletion pkg/ottl/contexts/internal/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

const (
ResourceContextName = "resource"
)

type ResourceContext interface {
GetResource() pcommon.Resource
GetResourceSchemaURLItem() SchemaURLItem
}

func ResourcePathGetSetter[K ResourceContext](path ottl.Path[K]) (ottl.GetSetter[K], error) {
if path == nil {
return nil, FormatDefaultErrorMessage("resource", "resource", "Resource", ResourceContextRef)
return nil, FormatDefaultErrorMessage(ResourceContextName, ResourceContextName, "Resource", ResourceContextRef)
}
switch path.Name() {
case "attributes":
Expand Down
7 changes: 6 additions & 1 deletion pkg/ottl/contexts/internal/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
)

const (
InstrumentationScopeContextName = "instrumentation_scope"
ScopeContextName = "scope"
)

type InstrumentationScopeContext interface {
GetInstrumentationScope() pcommon.InstrumentationScope
GetScopeSchemaURLItem() SchemaURLItem
}

func ScopePathGetSetter[K InstrumentationScopeContext](path ottl.Path[K]) (ottl.GetSetter[K], error) {
if path == nil {
return nil, FormatDefaultErrorMessage("instrumentation_scope", "instrumentation_scope", "Instrumentation Scope", InstrumentationScopeRef)
return nil, FormatDefaultErrorMessage(InstrumentationScopeContextName, InstrumentationScopeContextName, "Instrumentation Scope", InstrumentationScopeRef)
}
switch path.Name() {
case "name":
Expand Down
12 changes: 12 additions & 0 deletions pkg/ottl/contexts/internal/scope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,18 @@ func TestScopePathGetSetter(t *testing.T) {
s.AppendEmpty().SetEmptySlice().AppendEmpty().SetStr("new")
},
},
{
name: "scope with context",
path: &TestPath[*instrumentationScopeContext]{
C: "scope",
N: "name",
},
orig: refIS.Name(),
newVal: "newname",
modified: func(is pcommon.InstrumentationScope) {
is.SetName("newname")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
17 changes: 9 additions & 8 deletions pkg/ottl/contexts/internal/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import (
)

const (
SpanContextName = "Span"
SpanContextName = "span"
SpanContextNameDescription = "Span"
)

type SpanContext interface {
Expand All @@ -39,7 +40,7 @@ var SpanSymbolTable = map[ottl.EnumSymbol]ottl.Enum{

func SpanPathGetSetter[K SpanContext](path ottl.Path[K]) (ottl.GetSetter[K], error) {
if path == nil {
return nil, FormatDefaultErrorMessage("span", "span", SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(SpanContextName, SpanContextName, SpanContextNameDescription, SpanRef)
}
switch path.Name() {
case "trace_id":
Expand All @@ -48,7 +49,7 @@ func SpanPathGetSetter[K SpanContext](path ottl.Path[K]) (ottl.GetSetter[K], err
if nextPath.Name() == "string" {
return accessStringTraceID[K](), nil
}
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextNameDescription, SpanRef)
}
return accessTraceID[K](), nil
case "span_id":
Expand All @@ -57,7 +58,7 @@ func SpanPathGetSetter[K SpanContext](path ottl.Path[K]) (ottl.GetSetter[K], err
if nextPath.Name() == "string" {
return accessStringSpanID[K](), nil
}
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextNameDescription, SpanRef)
}
return accessSpanID[K](), nil
case "trace_state":
Expand All @@ -72,7 +73,7 @@ func SpanPathGetSetter[K SpanContext](path ottl.Path[K]) (ottl.GetSetter[K], err
if nextPath.Name() == "string" {
return accessStringParentSpanID[K](), nil
}
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextNameDescription, SpanRef)
}
return accessParentSpanID[K](), nil
case "name":
Expand All @@ -86,7 +87,7 @@ func SpanPathGetSetter[K SpanContext](path ottl.Path[K]) (ottl.GetSetter[K], err
case "deprecated_string":
return accessDeprecatedStringKind[K](), nil
default:
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextNameDescription, SpanRef)
}
}
return accessKind[K](), nil
Expand Down Expand Up @@ -123,12 +124,12 @@ func SpanPathGetSetter[K SpanContext](path ottl.Path[K]) (ottl.GetSetter[K], err
case "message":
return accessStatusMessage[K](), nil
default:
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), SpanContextNameDescription, SpanRef)
}
}
return accessStatus[K](), nil
default:
return nil, FormatDefaultErrorMessage(path.Name(), path.String(), SpanContextName, SpanRef)
return nil, FormatDefaultErrorMessage(path.Name(), path.String(), SpanContextNameDescription, SpanRef)
}
}

Expand Down
60 changes: 50 additions & 10 deletions pkg/ottl/contexts/ottldatapoint/datapoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
)

const (
contextName = "DataPoint"
// Experimental: *NOTE* this constant is subject to change or removal in the future.
ContextName = "datapoint"
contextNameDescription = "DataPoint"
)

var (
Expand Down Expand Up @@ -124,6 +126,22 @@ func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySet
return p, nil
}

// EnablePathContextNames enables the support to path's context names on statements.
// When this option is configured, all statement's paths must have a valid context prefix,
// otherwise an error is reported.
//
// Experimental: *NOTE* this option is subject to change or removal in the future.
func EnablePathContextNames() Option {
return func(p *ottl.Parser[TransformContext]) {
ottl.WithPathContextNames[TransformContext]([]string{
ContextName,
internal.ResourceContextName,
internal.InstrumentationScopeContextName,
internal.MetricContextName,
})(p)
}
}

type StatementSequenceOption func(*ottl.StatementSequence[TransformContext])

func WithStatementSequenceErrorMode(errorMode ottl.ErrorMode) StatementSequenceOption {
Expand Down Expand Up @@ -185,18 +203,23 @@ func (pep *pathExpressionParser) parsePath(path ottl.Path[TransformContext]) (ot
if path == nil {
return nil, fmt.Errorf("path cannot be nil")
}
// Higher contexts parsing
if path.Context() != "" && path.Context() != ContextName {
return pep.parseHigherContextPath(path.Context(), path)
}
// Backward compatibility with paths without context
if path.Context() == "" && (path.Name() == internal.ResourceContextName ||
path.Name() == internal.InstrumentationScopeContextName ||
path.Name() == internal.MetricContextName) {
return pep.parseHigherContextPath(path.Name(), path.Next())
}

switch path.Name() {
case "cache":
if path.Keys() == nil {
return accessCache(), nil
}
return accessCacheKey(path.Keys()), nil
case "resource":
return internal.ResourcePathGetSetter[TransformContext](path.Next())
case "instrumentation_scope":
return internal.ScopePathGetSetter[TransformContext](path.Next())
case "metric":
return internal.MetricPathGetSetter[TransformContext](path.Next())
case "attributes":
if path.Keys() == nil {
return accessAttributes(), nil
Expand Down Expand Up @@ -239,7 +262,7 @@ func (pep *pathExpressionParser) parsePath(path ottl.Path[TransformContext]) (ot
case "bucket_counts":
return accessPositiveBucketCounts(), nil
default:
return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), path.String(), contextName, internal.DataPointRef)
return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), path.String(), contextNameDescription, internal.DataPointRef)
}
}
return accessPositive(), nil
Expand All @@ -252,14 +275,31 @@ func (pep *pathExpressionParser) parsePath(path ottl.Path[TransformContext]) (ot
case "bucket_counts":
return accessNegativeBucketCounts(), nil
default:
return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), path.String(), contextName, internal.DataPointRef)
return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), path.String(), contextNameDescription, internal.DataPointRef)
}
}
return accessNegative(), nil
case "quantile_values":
return accessQuantileValues(), nil
default:
return nil, internal.FormatDefaultErrorMessage(path.Name(), path.String(), contextName, internal.DataPointRef)
return nil, internal.FormatDefaultErrorMessage(path.Name(), path.String(), contextNameDescription, internal.DataPointRef)
}
}

func (pep *pathExpressionParser) parseHigherContextPath(context string, path ottl.Path[TransformContext]) (ottl.GetSetter[TransformContext], error) {
switch context {
case internal.ResourceContextName:
return internal.ResourcePathGetSetter(path)
case internal.InstrumentationScopeContextName:
return internal.ScopePathGetSetter(path)
case internal.MetricContextName:
return internal.MetricPathGetSetter(path)
default:
var fullPath string
if path != nil {
fullPath = path.String()
}
return nil, internal.FormatDefaultErrorMessage(context, fullPath, contextNameDescription, internal.DataPointRef)
}
}

Expand Down
Loading
Loading