菜单
开源

template

注意

Promtail 已被弃用,并在长期支持 (LTS) 期间持续到 2026 年 2 月 28 日。Promtail 将于 2026 年 3 月 2 日达到生命周期结束 (EOL)。您可以在此处找到迁移资源。

template 阶段是一个转换阶段,允许您使用Go 模板语法来操作提取映射中的值。

template 阶段主要用于在将数据设置为标签之前操作来自其他阶段的数据,例如将空格替换为下划线或将大写字符串转换为小写字符串。template 也可用于构建包含多个键的消息。

template 阶段还可以创建提取映射中的新键。

Schema

yaml
template:
  # Name from extracted data to parse. If key in extract data doesn't exist, an
  # entry for it will be created.
  source: <string>

  # Go template string to use. In additional to normal template
  # functions, ToLower, ToUpper, Replace, Trim, TrimLeft, TrimRight,
  # TrimPrefix, TrimSuffix, and TrimSpace are available as functions.
  template: <string>

示例

yaml
- template:
    source: new_key
    template: 'hello world!'

假设提取映射中尚未添加任何数据,此阶段将首先在提取映射中添加一个值为`new_key`的空白键。然后其值将被设置为`hello world!`。

yaml
- template:
    source: app
    template: '{{ .Value }}_some_suffix'

此流水线获取现有提取映射中 `app` 键的值,并在其值后追加 `_some_suffix`。例如,如果提取映射有一个键为 `app` 且值为 `loki`,此阶段会将值从 `loki` 修改为 `loki_some_suffix`。

yaml
- template:
    source: app
    template: '{{ ToLower .Value }}'

此流水线获取提取映射中 `app` 的当前值,并将其值转换为全小写。例如,如果提取映射中包含 `app` 且值为 `LOKI`,此流水线会将其值更改为 `loki`。

yaml
- template:
    source: output_msg
    template: '{{ .level }} for app {{ ToUpper .app }}'

此流水线获取提取映射中 `level` 和 `app` 的当前值,并将在提取映射中添加一个新键 `output_msg`,其值为经过评估的模板。

例如,如果提取映射中包含 `app` 且值为 `loki`,此流水线会将其值更改为 `LOKI`。假设 `level` 的值为 `warn`。新的键 `output_msg` 将被添加到提取映射中,其值为 `warn for app LOKI`。

任何先前提取的键都可以在 `template` 中使用。所有提取的键都可用于 `template` 展开。

yaml
- template:
    source: app
    template: '{{ .level }} for app {{ ToUpper .Value }} in module {{.module}}'

此流水线获取提取映射中 `level`、`app` 和 `module` 的当前值,并将 `app` 的值转换为经过评估的模板。

例如,如果提取映射中包含 `app` 且值为 `loki`,此流水线会将其值更改为 `LOKI`。假设 `level` 的值为 `warn`,`module` 的值为 `test`。流水线会将 `app` 的值更改为 `warn for app LOKI in module test`。

任何先前提取的键都可以在 `template` 中使用。所有提取的键都可用于 `template` 展开。此外,如果 source 可用,可以在 `template` 中引用为 `.Value`。在这里,`app` 被提供为 `source`。因此,可以在 `template` 中引用为 `.Value`。

yaml
- template:
    source: app
    template: '{{ Replace .Value "loki" "blokey" 1 }}'

这里的模板使用 Go 的string.Replace 函数。当模板执行时,提取映射中 `app` 键的全部内容中最多 `1` 个 `loki` 实例将被更改为 `blokey`。

可以使用名为 `Entry` 的特殊键来引用当前行,当您需要向日志行前/后追加内容时,这非常有用。

yaml
- template:
    source: message
    template: '{{.app }}: {{ .Entry }}'
- output:
    source: message

例如,上面的代码片段将在日志行前追加应用程序名称。

yaml
- template:
    source: time
    template: "\
      {{ .date_local | substr 6 10 }}-{{ .date_local | substr 0 2 }}-{{ .date_local | substr 3 5 }}T\
      {{ if eq (.time_local | substr 0 2) \"12\" }}\
          {{ if eq .hour_period \"AM\" }}00{{ else }}12{{ end }}{{ .time_local | substr 2 10}}Z\
      {{ else }}\
          {{ if eq .hour_period \"AM\" }}\
              {{ if or (eq (.time_local | substr 0 2) \"11\") (eq (.time_local | substr 0 2) \"10\") }}{{ .time_local }}Z\
                  {{ else }}0{{ .time_local }}Z\
              {{ end }}\
          {{ else }}\
              {{ if eq (.time_local | substr 0 2) \"11\" }}23{{ .time_local | substr 2 10 }}Z{{ end }}\
              {{ if eq (.time_local | substr 0 2) \"10\" }}22{{ .time_local | substr 2 10 }}Z{{ end }}\
              {{ if eq (.time_local | substr 0 2) \"9:\" }}21{{ .time_local | substr 1 10 }}Z{{ end }}\
              {{ if eq (.time_local | substr 0 2) \"8:\" }}20{{ .time_local | substr 1 10 }}Z{{ end }}\
              {{ if and (le (.time_local | substr 0 1) \"7\") (eq (.time_local | substr 1 2) \":\") }}1{{ add (.time_local | substr 0 1) 2 }}{{ .time_local | substr 1 10 }}Z{{ end }}\
          {{ end }}\
      {{ end }}"
  - timestamp:
      source: time
      format: RFC3339      

上面的代码片段是一个没有空格的多行模板示例。从日志中使用正则表达式提取的数据将用于将 `11/08/2022, 12:53:24 PM` 转换为 `RFC3339` 时间格式。它还使用了 `eq`、`substr` 等函数,并展示了如何在 Go 模板中使用带 `and`、`or` 的 `if`。

支持的函数

所有sprig 函数已在 Loki 2.3 中添加到 template 阶段(以及下面描述的函数)。

ToLower 和 ToUpper

ToLower 和 ToUpper 分别将整个字符串转换为小写和大写。

示例

yaml
- template:
    source: out
    template: '{{ ToLower .app }}'
yaml
- template:
    source: out
    template: '{{ .app | ToUpper }}'

Replace

Replace 返回字符串 s 的副本,其中第一次出现的 n 个不重叠的 old 实例被 new 替换。如果 old 为空,则在字符串的开头以及每个 UTF-8 序列之后匹配,对于 k 个符文的字符串,最多产生 k+1 个替换。如果 n < 0,则对替换次数没有限制。

下面的示例将把前两个单词 `loki` 替换为 `Loki`。

yaml
- template:
    source: output
    template: '{{ Replace .Value "loki" "Loki" 2 }}'

Trim

Trim 返回字符串 s 的切片,其中所有前导和尾随的 Unicode 码点(包含在 cutset 中)已被移除。

TrimLeftTrimRightTrim 相同,但它们分别只修剪前导和尾随字符。

yaml
- template:
    source: output
    template: '{{ Trim .Value ",. " }}'

TrimSpace TrimSpace 返回字符串 s 的切片,其中所有前导和尾随空白字符(由 Unicode 定义)已被移除。

yaml
- template:
    source: output
    template: '{{ TrimSpace .Value }}'

TrimPrefixTrimSuffix 分别修剪提供的前缀或后缀。

yaml
- template:
    source: output
    template: '{{ TrimPrefix .Value "--" }}'

Regex

regexReplaceAll 返回输入字符串的副本,将 Regexp 的匹配项替换为替换字符串 replacement。在字符串 replacement 内部,$ 符号的解释与 Expand 中相同,例如 $1 表示第一个子匹配的文本

yaml
- template:
    source: output
    template: '{{ regexReplaceAll "(a*)bc" .Value "${1}a" }}'

regexReplaceAllLiteral 返回输入字符串的副本,将 Regexp 的匹配项替换为替换字符串 replacement。替换字符串被直接替换,不使用 Expand。

yaml
- template:
    source: output
    template: '{{ regexReplaceAllLiteral "(ts=)" .Value "timestamp=" }}'

Hash 和 Sha2Hash

Hash 返回字符串的 Sha3_256 哈希值,表示为 64 位数字的十六进制数。您可以使用它来混淆日志中的敏感数据/PII。它需要一个(固定的)盐值,以增加低输入域(例如所有可能的社会安全号码)的复杂性。

yaml
- template:
    source: output
    template: '{{ Hash .Value "salt" }}'

或者,您可以使用 Sha2Hash 计算字符串的 Sha2_256。Sha2_256 比 Sha3_256 更快且需要的 CPU 更少,但安全性较低。

我们建议使用 Hash,因为它具有更强的哈希算法,我们计划随着时间的推移保持其强度,而无需客户端更改配置。

yaml
- template:
    source: output
    template: '{{ Sha2Hash .Value "salt" }}'