Lambda 驱动的函数进入 OTTL

遥测流水线越来越复杂,需要执行的转换也随之增多:清理敏感数据、规范不一致的模式,以及落实属性约定。虽然 OTTL 已提供丰富的转换函数,但要表达集合操作,以往每遇到一种新用途,就需要专门提供一个行为写死的函数。

OpenTelemetry Collector Contrib v0.157.0 通过为 OTTL 引入 lambda 表达式改变了这一点。Lambda 允许用户把内联逻辑直接传给通用高阶函数,使复杂的集合转换既可以复用,又可以保持简洁。这一版本提供了8个利用该能力的新函数:Filter、MapEach、MapKeys、Any、All、Find、Reduce 和 When。

Lambda 表达式是一个小型匿名函数,直接定义在使用它的位置。它由参数列表和函数体组成;函数体可以是任何有效的 OTTL 表达式:

(key, value) => HasPrefix(key, "http.")
(key, value) => value * 2

下面的示例展示了这些函数可以实现什么。

过滤和转换集合

在这些函数出现之前,要操作切片或映射中的每一个元素,必须依赖行为写死的专用函数。现在可以这样做:

# Keep only attributes whose key starts with "http."
set(span.attributes, Filter(span.attributes, (k, _) => HasPrefix(k, "http.")))

# Stringify all attribute values
set(span.attributes, MapEach(span.attributes, (_, v) => String(v)))

# Normalize all attribute key names to snake_case
set(span.attributes, MapKeys(span.attributes, (k, _) => ToSnakeCase(k)))

# Add a prefix to all resource attribute keys
set(resource.attributes, MapKeys(resource.attributes, (k, _) => Format("app.%s", [k])))

对集合提出条件判断

Any 和 All 允许把切片或映射的内容用作条件,从而实现以前无法表达的过滤规则与 where 子句:

# Drop spans originating from internal networks
filter:
  trace_conditions:
    - Any(span.attributes["http.request.header.x-forwarded-for"],
      (_, v) => IsInCIDR(v, ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]))

# Only process spans where all db.* values are non-empty
transform:
  trace_statements:
    - set(span.attributes["db.complete"], true)
      where All(span.attributes, (k, v) => not HasPrefix(k, "db.") or not IsEmpty(v))

提取单个值

Find 返回第一个满足谓词的元素。还可以提供第二个可选 lambda,在返回结果之前对其进行转换:

# Find the value of the first x- header
set(span.attributes["custom_header"], Find(span.attributes, (k, _) => HasPrefix(k, "x-")))

# Find the key of the first attribute whose value is "error", ignoring the value
set(log.attributes["error_key"], Find(log.attributes, (_, v) => v == "error", (k, _) => k))

聚合集合

Reduce 将切片或映射归约为一个值:

# Total bytes across a list of response sizes
- set(span.attributes["total_bytes"],
  Reduce(span.attributes["response.sizes"], 0, (acc, _,  v) => acc + v))

# Concatenate all error messages into one string
- set(log.attributes["errors"],
  Reduce(log.attributes["error.messages"], "", (acc, _, v) => Format("%s; %s", acc, v)))

内联条件表达式

When 并不以集合为基础,但遵循同样的思路。

# Replace two `set` statements with one
- set(span.attributes["speed_class"], When(() => (span.end_time_unix_nano -
  span.start_time_unix_nano) > 1000000000, "slow", "fast"))

组合函数

这些函数可以组合使用,因此一个函数的输出可以直接作为另一个函数的输入。在下面的示例中,Filter 把映射缩小到看起来像个人身份信息(PII)的属性,MapEach 对这些属性的值做哈希处理,再将结果合并回去:

transform:
  trace_statements:
    - merge_maps(span.attributes,
      MapEach(
       Filter(span.attributes, (k, v) => IsMatch(k, "(?i)(email|phone|ssn|credit_card)")),
       (_, v) => Format("%s (redacted)", [SHA1(String(v))])
      ), "upsert")

将这些函数组合起来,就能覆盖多种转换需求。

试用

--feature-gates=ottl.functions.enableLambda

最后,我们鼓励用户探索这项新功能,并在自己的遥测流水线中利用它带来的便利!

如果你有问题或建议,我们非常愿意听取。欢迎加入 CNCF Slack 工作区的 #otel-collector 频道参与讨论。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容