菜单
开源

LogQL 模板函数

Go 模板语言嵌入在 Loki 查询语言 LogQL 中。用于 | line_format| label_format文本模板格式支持函数的使用。

注意

在下面的示例中,我们使用反引号 (` `) 来引用模板字符串。这是因为某些模板字符串包含双引号,使用反引号可以避免转义双引号。如果您使用不同的引用风格,可能需要对双引号进行转义。

更多信息请参考Go 模板文档

此外,您还可以使用 __line__ 函数访问日志行,并使用 __timestamp__ 函数访问时间戳。

模板 Pipeline 语法

Pipeline 是一个可能链式连接的“命令”序列。命令可以是简单值(参数)、函数或方法调用(可能带多个参数)。Pipeline 可以通过管道符 ' | ' 将命令序列“链式连接”。在链式 Pipeline 中,每个命令的结果作为最后一个参数传递给下一个命令。Pipeline 中最后一个命令的输出即为 Pipeline 的值。

您可以利用Pipeline将多个函数连接起来。

示例

template
`{{ .path | replace " " "_" | trunc 5 | upper }}`

对于返回布尔值的函数,例如 contains, eq, hasPrefixhasSuffix,您可以应用 AND / OR 以及嵌套的 if 逻辑。

示例

template
`{{ if and (contains "he" "hello") (contains "llo" "hello") }} yes {{end}}`
`{{ if or (contains "he" "hello") (contains("llo" "hello") }} yes {{end}}`
`{{ if contains .err "ErrTimeout" }} timeout {{else if contains "he" "hello"}} yes {{else}} no {{end}}`

日志行属性的内置变量

这些变量提供了一种在编写模板表达式时引用日志行中某些内容的方式。

.label_name

日志行中的所有标签都作为变量添加到模板引擎中。它们可以使用标签名前缀 . 进行引用(例如,.label_name)。例如,以下模板将输出 path 标签的值

template
`{{ .path }}`

line

__line__ 函数返回未经任何修改的原始日志行。

签名: line() string

示例

template
`{{ __line__ | lower }}`
`{{ __line__ }}`

timestamp

__timestamp__ 函数返回当前日志行的时间戳。

签名: timestamp() time.Time

template
`{{ __timestamp__ }}`
`{{ __timestamp__ | date "2006-01-02T15:04:05.00Z-07:00" }}`
`{{ __timestamp__ | unixEpoch }}`

更多信息请参考博客在 Go 中解析和格式化日期/时间

日期和时间

在构建 LogQL 查询时,您可以使用以下函数操作日期和时间。

date

根据提供的golang 日期时间布局格式化时间值,并返回文本表示。

签名: date(fmt string, date interface{}) string

示例

template
`{{ date "2006-01-02" now }}`

duration

duration_seconds 的别名

示例

template
`{{ .foo | duration }}`
`{{ duration .foo }}`

duration_seconds

使用 time.ParseDuration 将人性化的时间 duration 转换为秒。

签名: duration_seconds(string) float64

示例

template
`{{ .foo | duration_seconds }}`
`{{ duration_seconds .foo }}`

now

返回 Loki 服务器本地时区的当前时间。

签名: Now() time.Time

示例

template
`{{ now }}`

toDate

解析格式化字符串,并使用运行 Loki 的服务器本地时区返回对应的时间值。

为了在 Loki 安装之间获得更好的一致性,建议使用 toDateInZone

格式字符串必须使用golang 日期时间布局中定义的精确日期。

签名: toDate(fmt, str string) time.Time

示例

template
`{{ toDate "2006-01-02" "2021-11-02" }}`
`{{ .foo | toDate "2006-01-02T15:04:05.999999999Z" }}`

toDateInZone

解析格式化字符串,并在提供的时区中返回对应的时间值。

格式字符串必须使用golang 日期时间布局中定义的精确日期。

时区值可以是 Local, UTC,或任何 IANA 时区数据库值

签名: toDateInZone(fmt, zone, str string) time.Time

示例

template
`{{ toDateInZone "2006-01-02" "UTC" "2021-11-02" }}`
`{{ .foo | toDateInZone "2006-01-02T15:04:05.999999999Z" "UTC" }}`

unixEpoch

返回自 1970 年 1 月 1 日 UTC 起经过的秒数。

签名: unixEpoch(date time.Time) string

示例

template
`{{ unixEpoch now }}`
`{{ .foo | toDateInZone "2006-01-02T15:04:05.999999999Z" "UTC" | unixEpoch }}`

过滤创建时间在 1 天前的 Loki 查询器作业的示例查询

logql
{job="loki/querier"} | label_format nowEpoch=`{{(unixEpoch now)}}`,createDateEpoch=`{{unixEpoch (toDate "2006-01-02" .createDate)}}` | label_format dateTimeDiff=`{{sub .nowEpoch .createDateEpoch}}` | dateTimeDiff > 86400

unixEpochMillis

返回自 1970 年 1 月 1 日 UTC 起经过的毫秒数。

签名: unixEpochMillis(date time.Time) string

示例

template
`{{ unixEpochMillis now }}`
`{{ .foo | toDateInZone "2006-01-02T15:04:05.999999999Z" "UTC" | unixEpochMillis }}`

unixEpochNanos

返回自 1970 年 1 月 1 日 UTC 起经过的纳秒数。

签名: unixEpochNanos(date time.Time) string

示例

template
`{{ unixEpochNanos now }}`
`{{ .foo | toDateInZone "2006-01-02T15:04:05.999999999Z" "UTC" | unixEpochNanos }}`

unixToTime

将字符串 epoch 转换为对应的时间值。支持以天、秒、毫秒、微秒和纳秒为单位的 Epoch 时间。

签名: unixToTime(epoch string) time.Time

示例

考虑以下日志行 {"from": "1679577215","to":"1679587215","message":"some message"}。要以人类可读的格式打印 from 字段,请在 LogQL 查询末尾添加以下内容

logql
... | json | line_format `from="{{date "2006-01-02" (unixToTime .from)}}"`

字符串操作

在构建 LogQL 查询时,您可以使用以下模板操作字符串。

alignLeft

使用此函数将字符串格式化为固定宽度,内容左对齐。

签名: alignLeft(count int, src string) string

示例

template
`{{ alignLeft 5 "hello world"}}` // output: "hello"
`{{ alignLeft 5 "hi"}}`          // output: "hi   "

alignRight

使用此函数将字符串格式化为固定宽度,内容右对齐。

签名: alignRight(count int, src string) string

示例

template
`{{ alignRight 5 "hello world"}}` // output: "world"
`{{ alignRight 5 "hi"}}`          // output: "   hi"

b64enc

Base64 编码字符串。

签名: b64enc(string) string

示例

template
`{{ .foo | b64enc }}`
`{{ b64enc  .foo }}`

b64dec

Base64 解码字符串。

签名: b64dec(string) string

示例

template
`{{ .foo | b64dec }}`
`{{ b64dec  .foo }}`

bytes

使用 go-humanize 将人性化的字节字符串转换为字节。 Duration 可以转换为诸如“3 days ago”的字符串,表示大小的数字(如 82854982)可以转换为有用的字符串,如“83 MB”或“79 MiB”

签名: bytes(string) string

示例

template
`{{ .foo | bytes }}`
`{{ bytes .foo }}`

default

如果源字符串为空,则启用输出默认值。如果 'src' 参数不为空,此函数返回 'src' 的值。对于 JSON 中可能缺失的字段很有用,例如日志行中非必需的 HTTP 头,如下例所示

logql
{job="access_log"} | json | line_format `{{.http_request_headers_x_forwarded_for | default "-"}}`

签名: default(d string, src string) string

示例

template
`{{ default "-" "" }}` // output: -
`{{ default "-" "foo" }}` // output: foo

打印 - 的示例查询,如果 http_request_headers_x_forwarded_for 标签为空

logql
{job="access_log"} | json | line_format `{{.http_request_headers_x_forwarded_for | default "-"}}`

fromJson

将 JSON 文档解码为结构体。如果输入无法解码为 JSON,函数将返回空字符串。

签名: fromJson(v string) interface{}

示例

template
`{{fromJson "{\"foo\": 55}"}}`

示例查询,为日志行中存储为 JSON 数组的每个查询打印新行

logql
{job="loki/querier"} |= "finish in prometheus" | logfmt | line_format `{{ range $q := fromJson .queries }} {{ $q.query }} {{ end }}`

lower

使用此函数转换为小写。

签名: lower(string) string

示例

template
`{{ .request_method | lower }}`
`{{ lower  "HELLO"}}`

最后一个示例将返回 hello

indent

indent 函数将给定字符串中的每一行缩进指定的宽度。这在对齐多行字符串时很有用。

签名: indent(spaces int,src string) string

示例

template
`{{ indent 4 .query }}`

这将 .query 中的每一行缩进四个 (4) 空格。

nindent

nindent 函数与 indent 函数相同,但在字符串开头添加新行。

签名: nindent(spaces int,src string) string

示例

template
`{{ nindent 4 .query }}`

这将把文本的每一行缩进 4 个空格字符,并在开头添加一个新行。

repeat

使用此函数重复字符串多次。

签名: repeat(c int,value string) string

示例

template
`{{ repeat 3 "hello" }}` // output: hellohellohello

printf

使用此函数以自定义方式格式化字符串。有关语法更多信息,请参考Go 文档

签名: printf(format string, a ...interface{})

示例

template
`{{ printf "The IP address was %s" .remote_addr }}` // output: The IP address was 129.168.1.1

`{{ printf "%-40.40s" .request_uri}} {{printf "%-5.5s" .request_method}}`
// output: 
// /a/509965767/alternative-to-my-mtg.html  GET
// /id/609259548/hpr.html                   GET
template
line_format "\"|\" {{printf \"%15.15s\" .ClientHost}} \"|\""

replace

此函数执行简单的字符串替换。

签名: replace(old string, new string, src string) string

它接受三个参数

  • 要替换的旧字符串
  • 替换成的新字符串
  • 源字符串

示例

template
`{{ .cluster | replace "-cluster" "" }}`
`{{ replace "hello" "world" "hello world" }}`

最后一个示例将返回 world world

substr

从字符串获取子字符串。

签名: substr(start int,end int,value string) string

如果 start < 0,则调用 value[:end]。如果 start >= 0 且 end < 0 或 end 大于 s 的长度,则调用 value[start:]。否则,调用 value[start, end]。

示例

template
`{{ .path | substr 2 5 }}`
`{{ substr 0 5 "hello world"}}`  // output: hello
`{{ substr 6 11 "hello world"}}` // output: world

title

转换为标题大小写。

签名: title(string) string

示例

template
`{{.request_method | title}}`
`{{ title "hello world"}}`

最后一个示例将返回 Hello World

trim

trim 函数移除字符串两侧的空格。

签名: trim(string) string

示例

template
`{{ .ip | trim }}`
`{{ trim "   hello    " }}` // output: hello

trimAll

使用此函数从字符串的开头或结尾移除给定字符。

签名: trimAll(chars string,src string) string

示例

template
`{{ .path | trimAll "/" }}`
`{{ trimAll "$" "$5.00" }}` // output: 5.00

trimPrefix

使用此函数仅移除字符串的前缀。

签名: trimPrefix(prefix string, src string) string

示例

template
`{{  .path | trimPrefix "/" }}`
`{{ trimPrefix "-" "-hello" }}` // output: hello

trimSuffix

使用此函数仅移除字符串的后缀。

签名: trimSuffix(suffix string, src string) string

示例

template
`{{  .path | trimSuffix "/" }}`
`{{ trimSuffix "-" "hello-" }}` // output: hello

trunc

截断字符串且不添加后缀。

签名: trunc(count int,value string) string

示例

template
`{{ .path | trunc 2 }}`
`{{ trunc 5 "hello world"}}`   // output: hello
`{{ trunc -5 "hello world"}}`  // output: world

upper

使用此函数转换为大写。

签名: upper(string) string

示例

template
`{ .request_method | upper }}`
`{{ upper  "hello"}}`

结果为 HELLO

urlencode

使用此函数urlencode字符串。

签名: urlencode(string) string

示例

template
`{{ .request_url | urlencode }}`
`{{ urlencode  .request_url}}`

urldecode

使用此函数urldecode字符串。

签名: urldecode(string) string

示例

template
`{{ .request_url | urldecode }}`
`{{ urldecode  .request_url}}`

逻辑函数

在构建模板表达式时,您可以使用以下逻辑函数比较字符串。

contains

使用此函数测试一个字符串是否包含在另一个字符串中。

签名: contains(s string, src string,) bool

示例

template
`{{ if contains "ErrTimeout" .err }} timeout {{end}}`
`{{ if contains "he" "hello" }} yes {{end}}`

eq

使用此函数测试一个字符串是否与另一个字符串完全匹配。

签名: eq(s string, src string) bool

示例

template
`{{ if eq "ErrTimeout" .err }} timeout {{end}}`
`{{ if eq "hello" "hello" }} yes {{end}}`

hasPrefix 和 hasSuffix

hasPrefixhasSuffix 函数测试字符串是否具有给定的前缀或后缀。

签名

  • hasPrefix(prefix string, src string) bool
  • hasSuffix(suffix string, src string) bool

示例

template
`{{ if hasSuffix .err "Timeout" }} timeout {{end}}`
`{{ if hasPrefix "he" "hello" }} yes {{end}}`

数学函数

在编写模板表达式时,您可以使用以下数学函数。

add

求和。支持多个数字

签名: func(i ...interface{}) int64

示例

template
`{{ add 3 2 5 }}` // output: 10

addf

求浮点数和。支持多个数字。

签名: func(i ...interface{}) float64

示例

template
`{{ addf 3.5 2 5 }}` // output: 10.5

ceil

返回大于或等于输入值的最大浮点数

签名: ceil(a interface{}) float64

示例

template
`{{ ceil 123.001 }}` //output 124.0

div

整型相除。

签名: func(a, b interface{}) int64

示例

template
`{{ div 10 2}}` // output: 5

divf

浮点数相除。支持多个数字。

签名: func(a interface{}, v ...interface{}) float64

示例

template
`{{ divf 10 2 4}}` // output: 1.25

float64

将字符串转换为 float64。

签名: toFloat64(v interface{}) float64

示例

template
`{{ "3.5" | float64 }}` //output 3.5

floor

返回小于或等于输入值的最大浮点数。

签名: floor(a interface{}) float64

示例

template
`{{ floor 123.9999 }}` //output 123.0

int

将值转换为整型。

签名: toInt(v interface{}) int

示例

template
`{{ "3" | int }}` //output 3

max

返回一系列整型中的最大值

签名: max(a interface{}, i ...interface{}) int64

示例

template
`{{ max 1 2 3 }}` //output 3

maxf

返回一系列浮点数中的最大值

签名: maxf(a interface{}, i ...interface{}) float64

示例

template
`{{ maxf 1 2.5 3 }}` //output 3

min

返回一系列整型中的最小值。

签名: min(a interface{}, i ...interface{}) int64

示例

template
`{{ min 1 2 3 }}`//output 1

minf

返回一系列浮点数中的最小值。

签名: minf(a interface{}, i ...interface{}) float64

示例

template
`{{ minf 1 2.5 3 }}` //output 1.5

mul

乘法运算。支持多个数字。

签名: mul(a interface{}, v ...interface{}) int64

示例

template
`{{ mul 5 2 3}}` // output: 30

mulf

浮点数乘法运算。支持多个数字

签名: mulf(a interface{}, v ...interface{}) float64

示例

template
`{{ mulf 5.5 2 2.5 }}` // output: 27.5

mod

返回数字 'a' 除以数字 'b' 的余数。

签名: mod(a, b interface{}) int64

示例

template
`{{ mod 10 3}}` // output: 1

round

返回一个浮点数,其余数四舍五入到小数点后给定位数。

签名: round(a interface{}, p int, rOpt ...float64) float64

示例

template
`{{ round 123.555555 3 }}` //output 123.556

我们也可以提供一个 roundOn 数字作为第三个参数

示例

template
`{{ round 123.88571428571 5 .2 }}` //output 123.88572

使用默认 roundOn 值为 .5,以上值将是 123.88571

sub

一个数减去另一个数。

签名: func(a, b interface{}) int64

示例

template
`{{ sub 5 2 }}` // output: 3

subf

浮点数相减。支持多个数字。

签名: func(a interface{}, v ...interface{}) float64

示例

template
`{{ subf  5.5 2 1.5 }}` // output: 2

正则表达式函数

您可以在模板表达式中使用以下函数执行正则表达式操作。

count

计算 regex (regex) 在 (src) 的出现次数。

签名: count(regex string, src string) int

示例

template
`{{ count "a|b" "abab" }}` // output: 4
`{{ count "o" "foo" }}`    // output: 2

打印 XYZ 在一行中出现多少次的示例查询

logql
{job="xyzlog"} | line_format `{{ __line__ | count "XYZ"}}`

regexReplaceAll 和 regexReplaceAllLiteral

regexReplaceAll 返回输入字符串的副本,用替换字符串 replacement 替换 Regexp 的匹配项。在字符串替换中,$ 符号的解释方式与 Expand 中相同,例如 $1 代表第一个子匹配的文本。请参见 golangRegexp.replaceAll 文档获取更多示例。

签名: regexReplaceAll(regex string, src string, replacement string) (source)

示例

template
`{{ regexReplaceAll "(a*)bc" .some_label "${1}a" }}`

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

签名: regexReplaceAllLiteral(regex string, src string, replacement string)

示例

template
`{{ regexReplaceAllLiteral "(ts=)" .timestamp "timestamp=" }}`