Skip to content

Commit

Permalink
[pkg/ottl] Change OTTL contexts to handle paths with context (open-te…
Browse files Browse the repository at this point in the history
…lemetry#36820)

Co-authored-by: Evan Bradley <[email protected]>
  • Loading branch information
edmocosta and evan-bradley authored Dec 20, 2024
1 parent 9959e34 commit 8972570
Show file tree
Hide file tree
Showing 20 changed files with 870 additions and 47 deletions.
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

0 comments on commit 8972570

Please sign in to comment.