遥测流水线越来越复杂,需要执行的转换也随之增多:清理敏感数据、规范不一致的模式,以及落实属性约定。虽然 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 频道参与讨论。











暂无评论内容