{"id":16894184,"url":"https://github.com/jsuereth/ottl-proposal","last_synced_at":"2026-05-20T03:09:13.614Z","repository":{"id":219352197,"uuid":"747964208","full_name":"jsuereth/ottl-proposal","owner":"jsuereth","description":"A proposal for OTTL improvements along with prototype implementation.","archived":false,"fork":false,"pushed_at":"2024-02-08T01:15:56.000Z","size":79,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-25T10:41:28.189Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jsuereth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-25T01:37:58.000Z","updated_at":"2024-01-26T20:02:58.000Z","dependencies_parsed_at":"2024-01-26T22:23:42.873Z","dependency_job_id":"cadf79fe-56b0-44b7-89ff-528065a99b27","html_url":"https://github.com/jsuereth/ottl-proposal","commit_stats":null,"previous_names":["jsuereth/ottl-proposal"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsuereth%2Fottl-proposal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsuereth%2Fottl-proposal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsuereth%2Fottl-proposal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsuereth%2Fottl-proposal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jsuereth","download_url":"https://codeload.github.com/jsuereth/ottl-proposal/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244591485,"owners_count":20477710,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T17:17:56.130Z","updated_at":"2026-05-20T03:09:08.580Z","avatar_url":"https://github.com/jsuereth.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenTelemetry Transformation Template Language Experimentation\n\nThis repository represents experiments for the OpenTelemetry template language.\n\nSpecifically, we're investigating a few optimisations:\n\n- An extension that simplifies manipulating nested datastructures (like protos),\n  as this is core/critical to transformation of OTLP.\n- A type system for OTTL.\n  - This should help catch errors earlier, and provide better error messages.\n  - This could improve runtime performance via hot-path accessors for datatypes.\n- Possibility of a multi-pass optimiser to reduce necessary components in evaluation.\n\n## Grammar\n\nA hazy definition of the grammar.\n\n```\n\u003cstatement\u003e :=\n  on \u003ccontext-identifier\u003e\n  (\u003cpattern-match\u003e)?\n  \u003cstatement-action\u003e\n\n\u003ccontext-identifier\u003e := 'span' | 'spanevent' | 'metrics' | 'log'\n\n\u003cstatement-action\u003e :=\n  'drop' | \n  'yield' \u003cexpr\u003e\n\n\u003cpattern-match\u003e := 'when' \u003cexpr\u003e 'is' \u003cpattern-extractor\u003e\n\n\u003cpattern-extractor\u003e := \n  \u003cidentifier\u003e |\n  \u003cidentifier\u003e '(' \u003cpattern_extractor\u003e ')'\n\n\u003cexpr\u003e := \n  \u003capplication\u003e |\n  \u003cbinary_expr\u003e |\n  \u003caccessor\u003e |\n  \u003cstructure_constructor\u003e |\n  \u003clist_expr\u003e |\n  \u003cliteral\u003e |\n  \u003cidentifier\u003e\n\n# Calling a function\n\u003capplication\u003e := \u003cexpr\u003e '(' optional_repeated(\u003cexpr\u003e, ',') ')'\n\n# Binary Operations\n\u003cbinary_expr\u003e := \u003cexpr\u003e \u003cbinary_op\u003e \u003cexpr\u003e\n\u003cbinary_op\u003e :=\n   '==' | \"!=\" |             # Boolean operators\n   '+' | '-' | '*' | '/' |   # numeric operators\n   'with' |                  # Structural join\n   'in'                      # contained-in operator.\n\n# Accessing members\n\u003caccessor\u003e := \u003cexpr\u003e '.' \u003cidentifier\u003e\n\n# Defining ad-hoc structure\n\u003cstructure_constructor\u003e :=  '{' optional_repeated(\u003cfield-assignment\u003e, ',') '}'\n\u003cfield-assignment\u003e := \u003cidentifier\u003e ':' \u003cexpr\u003e\n\n# Defining a list of items\n\u003clist_expr\u003e := '[' optional_repeated(\u003cexpr\u003e, ',') ']'\n\n# TODO - specifiy allowed strings for identifiers.\n\u003cidentifier\u003e := ...\n\n# Literals, e.g. true, false, \"Hi\", 1.\n\u003cliteral\u003e :=\n  \"Nil\" |\n  \u003cbool-literal\u003e |\n  \u003cint-literal\u003e |\n  \u003cdouble-literal\u003e |\n  \u003cstring-literal\u003e\n\u003cstring-literal\u003e := ...\n\u003cint-literal\u003e := ...\n\u003cbool-literal\u003e := \"true\" | \"false\"\n\u003cdouble-literal\u003e := ...\n```\n\nWe're using some hackery to have left-recursive grammars in \"nom\".\n\n## Type System.\n\nWe have the following types:\n\n- `AnyValue` - A special type, mostly acting as a union of types allowed in attributes.\n- `Nil` - A bottom type.\n- `Constructor(name, args)` - A named type, with possible type arguments (e.g. Int, List[A])\n- `Structural(fields)` - A structural type consisting of known fields and their types.\n\n\nTODO - Formal specification\n\n- `Nil` is a subtype of all types.\n- `Bool`, `Int`, `Double`, `Bytes`, `ArrayValue`, `KeyValueList` are subtypes of `AnyValue`.\n- A `Structural` type is mergable with a named type IFF the `fields` of the structural type\n  are assignable to fields of the named type.\n\nWe have an ad-hoc type inference system in place.  When inferring the type of a `List`, it is able\nto unify `Nil` =\u003e {special primitive types} =\u003e `AnyValue`.  This means lists are NOT guaranteed to\nbe homogenous.\n\n## Compiler Phases\n\n1. Parser takes raw strings and turns it into an AST.\n2. Typer takes the AST and inferrs/assigned types returning a typed AST.\n3. IR transforms the AST into an intermediate representation on which we can perform our optimisations.\n4. transform has optimisations we execute before outputing our final interpretation nodes.\n   - We remove any mathematical operations that can be calculated at compile time.\n   - We flatten the `with` (Merge) operations to a set of `set(field,value)` operations.\n\nBy the end of the compiler, the only IR nodes left should be:\n\n```\nMultiExpr(exprs) // Evaluate all of these.\nLookup(id)       // Pull a value from context, e.g. span.status.code\nLiteral(value)   // A compile-time constant to use/provide.\nMakeList(exprs)  // Construct a list using the expressions provided.\nFunctionApply(name, exprs) // Execute a function with given set of value.\n```\n\nNote: `MultiExpr` should NOT appear anywhere a single value is expected.\n\n## Built-In Environment\n\n- `span` has type `Span`\n- `metric` has type `Metric`\n- `resource` has type `Resource`\n\n### Built-in Types\n\nWhile this isn't expressible in the OTTL language, we define a symbol table against named\ntypes that looks as follows:\n\n```\nstruct Time {}\nstruct SpanID {}\nstruct TraceID {}\nstruct SpanStatus {\n  code Int,\n  message String,\n}\nstruct Span {\n  name String,\n  kind Int,\n  status SpanStatus,\n  startTime Time,\n  endTime Time,\n  spanID SpanID,\n  traceId TraceID,\n  // TODO - attributes, events, dropped*\n}\n\nstruct Log {\n  spanID SpanID,\n  traceId TraceID,\n  time Time,\n  observed_time Time,\n  severity_number Int,\n  severity_text String,\n  body AnyVal,\n  flags Int,\n  // TODO - attributes\n}\n```\n\nThe rest of the types are unimplemented as this is just a proof-of-concept.\n\n\n### Built-in Symbols / Functions\n\nWe expose the following built-in symbols (note this is pseudo-code not expressable OTTL)\n\n```go\nfunc aSum(metric *Metric) Option[*Sum]\n```\n\n## TODOs\n\n- [X] Flatten structural merging to `Set` calls to showcase existing OTTL.\n- [ ] Implement string literals\n- [ ] Implement comperhensions for lists + key-value lists.\n- [ ] Move off nom-recursive to a more robust solution.\n- [X] Evaluate literal arithmetic operations in compiler.\n- [ ] Allow comments in the language.\n- [ ] Formal Type specification\n- [ ] Enforce requirements after each phase/transform of the tree.\n\n\n## Examples\n\n*Structural literal with compile-time-evaluation*\n\n```\non span\nyield span with {\n    status: {\n        code: 1+2-3\n    },\n    kind: 2\n}\n```\n\nbecomes\n\n```\ncontext: span\nguard: true\nexpr: set(span.kind, 2)\n      set(span.status.code, 0)\n```\n\n*Pattern match with expansion to guard*\n\n```\non metric\nwhen metric is aSum(sum)\nyield metric with { \n    sum: sum \n}\n```\n\n\nbecomes\n\n```\ncontext: metric\nguard: IsSome(aSum(metric))\nexpr: set(metric.sum, OptGet(aSum(metric)))\n```\n\nNote: this assumes:\n- `aSum` built in function of `(*Metric) Option[*Sum]`.\n- `IsSome` built in function of `[k] (*Option[k]) bool`.\n- `OptGet` built-in function of `[k] (*Option[k]) k`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsuereth%2Fottl-proposal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjsuereth%2Fottl-proposal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsuereth%2Fottl-proposal/lists"}