ottl

package
v0.0.0-...-f77ec2b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 22, 2022 License: Apache-2.0 Imports: 10 Imported by: 0

README

OpenTelemetry Transformation Language

The OpenTelemetry Transformation Language is a query language for transforming open telemetry data based on the OpenTelemetry Collector Processing Exploration.

This package reads in OTTL queries and converts them to invokable Booleans and functions based on the OTTL's grammar.

The OTTL is signal agnostic; it is not aware of the type of telemetry on which it will operate. Instead, the Booleans and functions returned by the package must be passed a TransformContext, which provide access to the signal's telemetry. Telemetry data can be accessed and updated through Getters and Setters.

Grammar

The OTTL grammar includes Invocations, Values and Expressions.

Invocations

Invocations represent a function call. Invocations are made up of 2 parts:

  • a string identifier. The string identifier must start with a letter or an underscore (_).
  • zero or more Values (comma separated) surrounded by parentheses (()).

The OTTL does not define any function implementations. Users must supply a map between string identifiers and the actual function implementation. The OTTL will use this map and reflection to generate Invocations, that can then be invoked by the user.

Example Invocations

  • drop()
  • set(field, 1)
Invocation parameters

The OTTL will use reflection to determine parameter types when parsing an invocation within a statement. When interpreting slice parameter types, the OTTL will attempt to build the slice from all remaining Values in the Invocation's arguments. As a result, function implementations of Invocations may only contain one slice argument and it must be the last argument in the function definition. See function syntax guidelines for more details.

The following types are supported for single parameter values:

  • Setter
  • GetSetter
  • Getter
  • Enum
  • string
  • float64
  • int64
  • bool

For slice parameters, the following types are supported:

  • string
  • float64
  • int64
  • uint8. Slices of bytes will be interpreted as a byte array.
  • Getter
Values

Values are passed as input to an Invocation or are used in an Expression. Values can take the form of:

Invocations as Values allows calling functions as parameters to other functions. See Invocations for details on Invocation syntax.

Paths

A Path Value is a reference to a telemetry field. Paths are made up of lowercase identifiers, dots (.), and square brackets combined with a string key (["key"]). The interpretation of a Path is NOT implemented by the OTTL. Instead, the user must provide a PathExpressionParser that the OTTL can use to interpret paths. As a result, how the Path parts are used is up to the user. However, it is recommended, that the parts be used like so:

  • Identifiers are used to map to a telemetry field.
  • Dots (.) are used to separate nested fields.
  • Square brackets and keys (["key"]) are used to access maps or slices.

Example Paths

  • name
  • value_double
  • resource.name
  • resource.attributes["key"]
Literals

Literals are literal interpretations of the Value into a Go value. Accepted literals are:

  • Strings. Strings are represented as literals by surrounding the string in double quotes ("").
  • Ints. Ints are represented by any digit, optionally prepended by plus (+) or minus (-). Internally the OTTL represents all ints as int64
  • Floats. Floats are represented by digits separated by a dot (.), optionally prepended by plus (+) or minus (-). The leading digit is optional. Internally the OTTL represents all Floats as float64.
  • Bools. Bools are represented by the exact strings true and false.
  • Nil. Nil is represented by the exact string nil.
  • Byte slices. Byte slices are represented via a hex string prefaced with 0x

Example Literals

  • "a string"
  • 1, -1
  • 1.5, -.5
  • true, false
  • nil,
  • 0x0001
Enums

Enums are uppercase identifiers that get interpreted during parsing and converted to an int64. The interpretation of an Enum is NOT implemented by the OTTL. Instead, the user must provide a EnumParser that the OTTL can use to interpret the Enum. The EnumParser returns an int64 instead of a function, which means that the Enum's numeric value is retrieved during parsing instead of during execution.

Within the grammar Enums are always used as int64. As a result, the Enum's symbol can be used as if it is an Int value.

When defining a function that will be used as an Invocation by the OTTL, if the function needs to take an Enum then the function must use the Enum type for that argument, not an int64.

Expressions

Expressions allow a decision to be made about whether an Invocation should be called. Expressions are optional. When used, the parsed query will include a Condition, which can be used to evaluate the result of the query's Expression. Expressions always evaluate to a boolean value (true or false).

Expressions consist of the literal string where followed by one or more Booleans (see below). Booleans can be joined with the literal strings and and or. Note that and expressions have higher precedence than or. Expressions can be grouped with parentheses to override evaluation precedence.

Booleans

Booleans can be either:

  • A literal boolean value (true or false).
  • A Comparison, made up of a left Value, an operator, and a right Value. See Values for details on what a Value can be.

Operators determine how the two Values are compared.

The valid operators are:

  • Equal (==). Tests if the left and right Values are equal (see the Comparison Rules below).
  • Not Equal (!=). Tests if the left and right Values are not equal.
  • Less Than (<). Tests if left is less than right.
  • Greater Than (>). Tests if left is greater than right.
  • Less Than or Equal To (<=). Tests if left is less than or equal to right.
  • Greater Than or Equal to (>=). Tests if left is greater than or equal to right.
Comparison Rules

The table below describes what happens when two Values are compared. Value types are provided by the user of OTTL. All of the value types supported by OTTL are listed in this table.

If numeric values are of different types, they are compared as float64.

For numeric values and strings, the comparison rules are those implemented by Go. Numeric values are done with signed comparisons. For binary values, false is considered to be less than true.

For values that are not one of the basic primitive types, the only valid comparisons are Equal and Not Equal, which are implemented using Go's standard == and != operators.

A not equal notation in the table below means that the "!=" operator returns true, but any other operator returns false. Note that a nil byte array is considered equivalent to nil.

base type bool int64 float64 string Bytes nil
bool normal, T>F not equal not equal not equal not equal not equal
int64 not equal compared as largest compared as float64 not equal not equal not equal
float64 not equal compared as float64 compared as largest not equal not equal not equal
string not equal not equal not equal normal (compared as Go strings) not equal not equal
Bytes not equal not equal not equal not equal byte-for-byte comparison []byte(nil) == nil
nil not equal not equal not equal not equal []byte(nil) == nil true for equality only

Accessing signal telemetry

Access to signal telemetry is provided to OTTL functions through a TransformContext that is created by the user and passed during statement evaluation. To allow functions to operate on the TransformContext, the OTTL provides Getter, Setter, and GetSetter interfaces.

Getters and Setters

Getters allow for reading the following types of data. See the respective section of each Value type for how they are interpreted.

It is possible to update the Value in a telemetry field using a Setter. For read and write access, the GetSetter interface extends both interfaces.

Logging inside a OTTL function

To emit logs inside a OTTL function, add a parameter of type component.TelemetrySettings to the function signature. The OTTL will then inject the TelemetrySettings that were passed to NewParser into the function. TelemetrySettings can be used to emit logs.

Examples

These examples contain a SQL-like declarative language. Applied statements interact with only one signal, but statements can be declared across multiple signals. Functions used in examples are indicative of what could be useful, but are not implemented by the OTTL itself.

Remove a forbidden attribute
traces:
  delete(attributes["http.request.header.authorization"])
metrics:
  delete(attributes["http.request.header.authorization"])
logs:
  delete(attributes["http.request.header.authorization"])
Remove all attributes except for some
traces:
  keep_keys(attributes, "http.method", "http.status_code")
metrics:
  keep_keys(attributes, "http.method", "http.status_code")
logs:
  keep_keys(attributes, "http.method", "http.status_code")
Reduce cardinality of an attribute
traces:
  replace_match(attributes["http.target"], "/user/*/list/*", "/user/{userId}/list/{listId}")
Reduce cardinality of a span name
traces:
  replace_match(name, "GET /user/*/list/*", "GET /user/{userId}/list/{listId}")
Reduce cardinality of any matching attribute
traces:
  replace_all_matches(attributes, "/user/*/list/*", "/user/{userId}/list/{listId}")
Decrease the size of the telemetry payload
traces:
  delete(resource.attributes["process.command_line"])
metrics:
  delete(resource.attributes["process.command_line"])
logs:
  delete(resource.attributes["process.command_line"])
Drop specific telemetry
metrics:
  drop() where attributes["http.target"] == "/health"
Attach information from resource into telemetry
metrics:
  set(attributes["k8s_pod"], resource.attributes["k8s.pod.name"])
Decorate error spans with additional information
traces:
  set(attributes["whose_fault"], "theirs") where attributes["http.status"] == 400 or attributes["http.status"] == 404
  set(attributes["whose_fault"], "ours") where attributes["http.status"] == 500
Group spans by trace ID
traces:
  group_by(trace_id, 2m)
Update a spans ID
logs:
  set(span_id, SpanID(0x0000000000000000))
traces:
  set(span_id, SpanID(0x0000000000000000))
Create utilization metric from base metrics.
metrics:
  create_gauge("pod.cpu.utilized", read_gauge("pod.cpu.usage") / read_gauge("node.cpu.limit")

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Boolean

type Boolean bool

Boolean Type for capturing booleans, see: https://github.com/alecthomas/participle#capturing-boolean-value

func (*Boolean) Capture

func (b *Boolean) Capture(values []string) error

type BooleanExpression

type BooleanExpression struct {
	Left  *Term       `parser:"@@"`
	Right []*OpOrTerm `parser:"@@*"`
}

BooleanExpression represents a true/false decision expressed as an arbitrary number of terms separated by OR.

type BooleanValue

type BooleanValue struct {
	Comparison *Comparison        `parser:"( @@"`
	ConstExpr  *Boolean           `parser:"| @Boolean"`
	SubExpr    *BooleanExpression `parser:"| '(' @@ ')' )"`
}

BooleanValue represents something that evaluates to a boolean -- either an equality or inequality, explicit true or false, or a parenthesized subexpression.

type Bytes

type Bytes []byte

Bytes type for capturing byte arrays

func (*Bytes) Capture

func (b *Bytes) Capture(values []string) error

type CompareOp

type CompareOp int

CompareOp is the type of a comparison operator.

const (
	EQ CompareOp = iota
	NE
	LT
	LTE
	GTE
	GT
)

These are the allowed values of a CompareOp

func (*CompareOp) Capture

func (c *CompareOp) Capture(values []string) error

Capture is how the parser converts an operator string to a CompareOp.

func (CompareOp) String

func (c CompareOp) String() string

String() for CompareOp gives us more legible test results and error messages.

type Comparison

type Comparison struct {
	Left  Value     `parser:"@@"`
	Op    CompareOp `parser:"@OpComparison"`
	Right Value     `parser:"@@"`
}

Comparison represents an optional boolean condition.

type Enum

type Enum int64

type EnumParser

type EnumParser func(*EnumSymbol) (*Enum, error)

type EnumSymbol

type EnumSymbol string

type ExprFunc

type ExprFunc func(ctx TransformContext) interface{}

type Field

type Field struct {
	Name   string  `parser:"@Lowercase"`
	MapKey *string `parser:"( '[' @String ']' )?"`
}

Field is an item within a Path.

type GetSetter

type GetSetter interface {
	Getter
	Setter
}

type Getter

type Getter interface {
	Get(ctx TransformContext) interface{}
}

type Invocation

type Invocation struct {
	Function  string  `parser:"@(Uppercase | Lowercase)+"`
	Arguments []Value `parser:"'(' ( @@ ( ',' @@ )* )? ')'"`
}

Invocation represents a function call.

type IsNil

type IsNil bool

func (*IsNil) Capture

func (n *IsNil) Capture(_ []string) error

type OpAndBooleanValue

type OpAndBooleanValue struct {
	Operator string        `parser:"@OpAnd"`
	Value    *BooleanValue `parser:"@@"`
}

OpAndBooleanValue represents the right side of an AND boolean expression.

type OpOrTerm

type OpOrTerm struct {
	Operator string `parser:"@OpOr"`
	Term     *Term  `parser:"@@"`
}

OpOrTerm represents the right side of an OR boolean expression.

type ParsedQuery

type ParsedQuery struct {
	Invocation  Invocation         `parser:"@@"`
	WhereClause *BooleanExpression `parser:"( 'where' @@ )?"`
}

ParsedQuery represents a parsed query. It is the entry point into the query DSL.

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

func NewParser

func NewParser(functions map[string]interface{}, pathParser PathExpressionParser, enumParser EnumParser, telemetrySettings component.TelemetrySettings) Parser

func (*Parser) ParseQueries

func (p *Parser) ParseQueries(statements []string) ([]Query, error)

type Path

type Path struct {
	Fields []Field `parser:"@@ ( '.' @@ )*"`
}

Path represents a telemetry path expression.

type PathExpressionParser

type PathExpressionParser func(*Path) (GetSetter, error)

type Query

type Query struct {
	Function  ExprFunc
	Condition boolExpressionEvaluator
}

Query holds a top level Query for processing telemetry data. A Query is a combination of a function invocation and the expression to match telemetry for invoking the function.

type Setter

type Setter interface {
	Set(ctx TransformContext, val interface{})
}

type StandardGetSetter

type StandardGetSetter struct {
	Getter func(ctx TransformContext) interface{}
	Setter func(ctx TransformContext, val interface{})
}

func (StandardGetSetter) Get

func (path StandardGetSetter) Get(ctx TransformContext) interface{}

func (StandardGetSetter) Set

func (path StandardGetSetter) Set(ctx TransformContext, val interface{})

type Term

type Term struct {
	Left  *BooleanValue        `parser:"@@"`
	Right []*OpAndBooleanValue `parser:"@@*"`
}

Term represents an arbitrary number of boolean values joined by AND.

type TransformContext

type TransformContext interface {
	GetItem() interface{}
	GetInstrumentationScope() pcommon.InstrumentationScope
	GetResource() pcommon.Resource
}

type Value

type Value struct {
	Invocation *Invocation `parser:"( @@"`
	Bytes      *Bytes      `parser:"| @Bytes"`
	String     *string     `parser:"| @String"`
	Float      *float64    `parser:"| @Float"`
	Int        *int64      `parser:"| @Int"`
	Bool       *Boolean    `parser:"| @Boolean"`
	IsNil      *IsNil      `parser:"| @'nil'"`
	Enum       *EnumSymbol `parser:"| @Uppercase"`
	Path       *Path       `parser:"| @@ )"`
}

Value represents a part of a parsed query which is resolved to a value of some sort. This can be a telemetry path expression, function call, or literal.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL