日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Grafana Loki 查詢語言 LogQL 使用

受 PromQL 的啟發(fā),Loki 也有自己的查詢語言,稱為 LogQL,它就像一個(gè)分布式的 grep,可以聚合查看日志。和 PromQL 一樣,LogQL 也是使用標(biāo)簽和運(yùn)算符進(jìn)行過濾的,主要有兩種類型的查詢功能:

在海興等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作定制網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站制作,營銷型網(wǎng)站建設(shè),外貿(mào)營銷網(wǎng)站建設(shè),海興網(wǎng)站建設(shè)費(fèi)用合理。

  • 查詢返回日志行內(nèi)容。
  • 通過過濾規(guī)則在日志流中計(jì)算相關(guān)的度量指標(biāo)。

日志查詢

一個(gè)基本的日志查詢由兩部分組成。

  • log stream selector(日志流選擇器)。
  • log pipeline(日志管道)。

由于 Loki 的設(shè)計(jì),所有 LogQL 查詢必須包含一個(gè)日志流選擇器。一個(gè) Log Stream 代表了具有相同元數(shù)據(jù)(Label 集)的日志條目。

日志流選擇器決定了有多少日志將被搜索到,一個(gè)更細(xì)粒度的日志流選擇器將搜索到流的數(shù)量減少到一個(gè)可管理的數(shù)量,通過精細(xì)的匹配日志流,可以大幅減少查詢期間帶來資源消耗。

而日志流選擇器后面的日志管道是可選的,用于進(jìn)一步處理和過濾日志流信息,它由一組表達(dá)式組成,每個(gè)表達(dá)式都以從左到右的順序?yàn)槊總€(gè)日志行執(zhí)行相關(guān)過濾,每個(gè)表達(dá)式都可以過濾、解析和改變?nèi)罩拘袃?nèi)容以及各自的標(biāo)簽。

下面的例子顯示了一個(gè)完整的日志查詢的操作:

{container="query-frontend",namespace="loki-dev"} |= "metrics.go" | logfmt | duration > 10s and throughput_mb < 500

該查詢語句由以下幾個(gè)部分組成:

  • 一個(gè)日志流選擇器{container="query-frontend",namespace="loki-dev"},用于過濾loki-dev 命名空間下面的query-frontend 容器的日志。
  • 然后后面跟著一個(gè)日志管道|= "metrics.go" | logfmt | duration > 10s and throughput_mb < 500,該管道表示將篩選出包含metrics.go 這個(gè)詞的日志,然后解析每一行日志提取更多的表達(dá)式并進(jìn)行過濾。

為了避免轉(zhuǎn)義特色字符,你可以在引用字符串的時(shí)候使用單引號(hào),而不是雙引號(hào),比如 `\w+1` 與 "\w+" 是相同的。

Log Stream Selector

日志流選擇器決定了哪些日志流應(yīng)該被包含在你的查詢結(jié)果中,選擇器由一個(gè)或多個(gè)鍵值對(duì)組成,其中每個(gè)鍵是一個(gè)日志標(biāo)簽,每個(gè)值是該標(biāo)簽的值。

日志流選擇器是通過將鍵值對(duì)包裹在一對(duì)大括號(hào)中編寫的,比如:

{app="mysql", name="mysql-backup"}

上面這個(gè)示例表示,所有標(biāo)簽為 app 且其值為 mysql 和標(biāo)簽為 name 且其值為 mysql-backup 的日志流將被包括在查詢結(jié)果中。

其中標(biāo)簽名后面的 = 運(yùn)算符是一個(gè)標(biāo)簽匹配運(yùn)算符,LogQL 中一共支持以下幾種標(biāo)簽匹配運(yùn)算符:

  • =: 完全匹配。
  • !=: 不相等。
  • =~: 正則表達(dá)式匹配。
  • !~: 正則表達(dá)式不匹配。

例如:

  • {name=~"mysql.+"}。
  • {name!~"mysql.+"}。
  • {name!~"mysql-\\d+"}。

適用于 Prometheus 標(biāo)簽選擇器的規(guī)則同樣適用于 Loki 日志流選擇器。

Log Pipeline

日志管道可以附加到日志流選擇器上,以進(jìn)一步處理和過濾日志流。它通常由一個(gè)或多個(gè)表達(dá)式組成,每個(gè)表達(dá)式針對(duì)每個(gè)日志行依次執(zhí)行。如果一個(gè)表達(dá)式過濾掉了日志行,則管道將在此處停止并開始處理下一行。一些表達(dá)式可以改變?nèi)罩緝?nèi)容和各自的標(biāo)簽,然后可用于進(jìn)一步過濾和處理后續(xù)表達(dá)式或指標(biāo)查詢。

一個(gè)日志管道可以由以下部分組成。

  • 日志行過濾表達(dá)式。
  • 解析器表達(dá)式。
  • 標(biāo)簽過濾表達(dá)式。
  • 日志行格式化表達(dá)式。
  • 標(biāo)簽格式化表達(dá)式。
  • Unwrap 表達(dá)式。

其中 unwrap 表達(dá)式是一個(gè)特殊的表達(dá)式,只能在度量查詢中使用。

日志行過濾表達(dá)式

日志行過濾表達(dá)式用于對(duì)匹配日志流中的聚合日志進(jìn)行分布式 grep。

編寫入日志流選擇器后,可以使用一個(gè)搜索表達(dá)式進(jìn)一步過濾得到的日志數(shù)據(jù)集,搜索表達(dá)式可以是文本或正則表達(dá)式,比如:

  • {job="mysql"} |= "error"。
  • {name="kafka"} |~ "tsdb-ops.*io:2003"。
  • {name="cassandra"} |~ "error=\\w+"。
  • {instance=~"kafka-[23]",name="kafka"} != "kafka.server:type=ReplicaManager"。

上面示例中的 |=、|~ 和 != 是過濾運(yùn)算符,支持下面幾種:

  • |=:日志行包含的字符串。
  • !=:日志行不包含的字符串。
  • |~:日志行匹配正則表達(dá)式。
  • !~:日志行與正則表達(dá)式不匹配。

過濾運(yùn)算符可以是鏈?zhǔn)降?,并將按順序過濾表達(dá)式,產(chǎn)生的日志行必須滿足每個(gè)過濾器。當(dāng)使用 |~和 !~ 時(shí),可以使用 Golang 的 RE2 語法的正則表達(dá)式,默認(rèn)情況下,匹配是區(qū)分大小寫的,可以用 (?i) 作為正則表達(dá)式的前綴,切換為不區(qū)分大小寫。

雖然日志行過濾表達(dá)式可以放在管道的任何地方,但最好把它們放在開頭,這樣可以提高查詢的性能,當(dāng)某一行匹配時(shí)才做進(jìn)一步的后續(xù)處理。例如,雖然結(jié)果是一樣的,但下面的查詢 {job="mysql"} |= "error" |json | line_format "{{.err}}" 會(huì)比 {job="mysql"} | json | line_format "{{.message}}" |= "error" 更快,日志行過濾表達(dá)式是繼日志流選擇器之后過濾日志的最快方式。

解析器表達(dá)式

解析器表達(dá)式可以解析和提取日志內(nèi)容中的標(biāo)簽,這些提取的標(biāo)簽可以用于標(biāo)簽過濾表達(dá)式進(jìn)行過濾,或者用于指標(biāo)聚合。

提取的標(biāo)簽鍵將由解析器進(jìn)行自動(dòng)格式化,以遵循 Prometheus 指標(biāo)名稱的約定(它們只能包含 ASCII 字母和數(shù)字,以及下劃線和冒號(hào),不能以數(shù)字開頭)。

例如下面的日志經(jīng)過管道 | json 將產(chǎn)生以下 Map 數(shù)據(jù):

{ "a.b": { "c": "d" }, "e": "f" }

->

{a_b_c="d", e="f"}

在出現(xiàn)錯(cuò)誤的情況下,例如,如果該行不是預(yù)期的格式,該日志行不會(huì)被過濾,而是會(huì)被添加一個(gè)新的 __error__ 標(biāo)簽。

需要注意的是如果一個(gè)提取的標(biāo)簽鍵名已經(jīng)存在于原始日志流中,那么提取的標(biāo)簽鍵將以 _extracted 作為后綴,以區(qū)分兩個(gè)標(biāo)簽,你可以使用一個(gè)標(biāo)簽格式化表達(dá)式來強(qiáng)行覆蓋原始標(biāo)簽,但是如果一個(gè)提取的鍵出現(xiàn)了兩次,那么只有最新的標(biāo)簽值會(huì)被保留。

目前支持 json、logfmt、pattern、regexp 和 unpack 這幾種解析器。

我們應(yīng)該盡可能使用 json 和 logfmt 等預(yù)定義的解析器,這會(huì)更加容易,而當(dāng)日志行結(jié)構(gòu)異常時(shí),可以使用 regexp,可以在同一日志管道中使用多個(gè)解析器,這在你解析復(fù)雜日志時(shí)很有用。

JSON

json 解析器有兩種模式運(yùn)行。

  • 如果日志行是一個(gè)有效的 json 文檔,在你的管道中添加 | json 將提取所有 json 屬性作為標(biāo)簽,嵌套的屬性會(huì)使用 _ 分隔符被平鋪到標(biāo)簽鍵中。

注意:數(shù)組會(huì)被忽略。

  • 例如,使用 json 解析器從以下文件內(nèi)容中提取標(biāo)簽。
{
"protocol": "HTTP/2.0",
"servers": ["129.0.1.1", "10.2.1.3"],
"request": {
"time": "6.032",
"method": "GET",
"host": "foo.grafana.net",
"size": "55",
"headers": {
"Accept": "*/*",
"User-Agent": "curl/7.68.0"
}
},
"response": {
"status": 401,
"size": "228",
"latency_seconds": "6.031"
}
}

可以得到如下所示的標(biāo)簽列表:

"protocol" => "HTTP/2.0"
"request_time" => "6.032"
"request_method" => "GET"
"request_host" => "foo.grafana.net"
"request_size" => "55"
"response_status" => "401"
"response_size" => "228"
"response_latency_seconds" => "6.031"
  1. 沒有參數(shù)。
  • 在你的管道中使用|json label="expression", another="expression" 將只提取指定的 json 字段為標(biāo)簽,你可以用這種方式指定一個(gè)或多個(gè)表達(dá)式,與label_format 相同,所有表達(dá)式必須加引號(hào)。當(dāng)前僅支持字段訪問(my.field,my["field"])和數(shù)組訪問(list[0]),以及任何級(jí)別嵌套中的這些組合(my.list[0]["field"])。例如,|json first_server="servers[0]", ua="request.headers[\"User-Agent\"] 將從以下日志文件中提取標(biāo)簽:
{
"protocol": "HTTP/2.0",
"servers": ["129.0.1.1", "10.2.1.3"],
"request": {
"time": "6.032",
"method": "GET",
"host": "foo.grafana.net",
"size": "55",
"headers": {
"Accept": "*/*",
"User-Agent": "curl/7.68.0"
}
},
"response": {
"status": 401,
"size": "228",
"latency_seconds": "6.031"
}
}

提取的標(biāo)簽列表為:

"first_server" => "129.0.1.1"
"ua" => "curl/7.68.0"

如果表達(dá)式返回一個(gè)數(shù)組或?qū)ο?,它將?json 格式分配給標(biāo)簽。例如,|json server_list="services", headers="request.headers 將提取到如下標(biāo)簽:

"server_list" => `["129.0.1.1","10.2.1.3"]`
"headers" => `{"Accept": "*/*", "User-Agent": "curl/7.68.0"}`
  1. 帶參數(shù)的。

logfmt

logfmt 解析器可以通過使用 | logfmt 來添加,它將從 logfmt 格式的日志行中提前所有的鍵和值。

例如,下面的日志行數(shù)據(jù):

at=info method=GET path=/ host=grafana.net fwd="124.133.124.161" service=8ms status=200

將提取得到如下所示的標(biāo)簽:

"at" => "info"
"method" => "GET"
"path" => "/"
"host" => "grafana.net"
"fwd" => "124.133.124.161"
"service" => "8ms"
"status" => "200"

regexp

與 logfmt 和 json(它們隱式提取所有值且不需要參數(shù))不同,regexp 解析器采用單個(gè)參數(shù) | regexp "" 的格式,其參數(shù)是使用 Golang RE2 語法的正則表達(dá)式。

正則表達(dá)式必須包含至少一個(gè)命名的子匹配(例如(?Pre)),每個(gè)子匹配項(xiàng)都會(huì)提取一個(gè)不同的標(biāo)簽。

例如,解析器 | regexp "(?P\\w+) (?P[\\w|/]+) \\((?P\\d+?)\\) (?P.*)" 將從以下行中提取標(biāo)簽:

POST /api/prom/api/v1/query_range (200) 1.5s

提取的標(biāo)簽為:

"method" => "POST"
"path" => "/api/prom/api/v1/query_range"
"status" => "200"
"duration" => "1.5s"

pattern

模式解析器允許通過定義模式表達(dá)式(| pattern "")從日志行中顯式提取字段,該表達(dá)式與日志行的結(jié)構(gòu)相匹配。

比如我們來考慮下面的 NGINX 日志行數(shù)據(jù):

0.191.12.2 - - [10/Jun/2021:09:14:29 +0000] "GET /api/plugins/versioncheck HTTP/1.1" 200 2 "-" "Go-http-client/2.0" "13.76.247.102, 34.120.177.193" "TLSv1.2" "US" ""

該日志行可以用下面的表達(dá)式來解析:

 - - <_> "  <_>"   <_> "" <_>

解析后可以提取出下面的這些屬性:

"ip" => "0.191.12.2"
"method" => "GET"
"uri" => "/api/plugins/versioncheck"
"status" => "200"
"size" => "2"
"agent" => "Go-http-client/2.0"

模式表達(dá)式的捕獲是由 < 和 > 字符分隔的字段名稱,比如  定義了字段名稱為 example,未命名的 capture 顯示為 <_>,未命名的 capture 會(huì)跳過匹配的內(nèi)容。默認(rèn)情況下,模式表達(dá)式錨定在日志行的開頭,可以在表達(dá)式的開頭使用 <_> 將表達(dá)式錨定在開頭。

比如我們查看下面的日志行數(shù)據(jù):

level=debug ts=2021-06-10T09:24:13.472094048Z caller=logging.go:66 traceID=0568b66ad2d9294c msg="POST /loki/api/v1/push (204) 16.652862ms"

我們?nèi)绻幌Mテヅ?nbsp;msg=" 的內(nèi)容,我們可以使用下面的表達(dá)式來進(jìn)行匹配:

<_> msg="  () "

前面大部分日志數(shù)據(jù)我們不需要,只需要使用 <_> 進(jìn)行占位即可,明顯可以看出這種方式比正則表達(dá)式要簡單得多。

unpack

unpack 解析器將解析 json 日志行,并通過打包階段解開所有嵌入的標(biāo)簽,一個(gè)特殊的屬性 _entry 也將被用來替換原來的日志行。

例如,使用 | unpack 解析器,可以得到如下所示的標(biāo)簽:

{
"container": "myapp",
"pod": "pod-3223f",
"_entry": "original log message"
}

允許提取 container 和 pod 標(biāo)簽以及原始日志信息作為新的日志行。

如果原始嵌入的日志行是特定的格式,你可以將 unpack 與 json 解析器(或其他解析器)相結(jié)合使用。

標(biāo)簽過濾表達(dá)式

標(biāo)簽過濾表達(dá)式允許使用其原始和提取的標(biāo)簽來過濾日志行,它可以包含多個(gè)謂詞。

一個(gè)謂詞包含一個(gè)標(biāo)簽標(biāo)識(shí)符、操作符和用于比較標(biāo)簽的值。

例如 cluster="namespace" 其中的 cluster 是標(biāo)簽標(biāo)識(shí)符,操作符是 =,值是"namespace"。

LogQL 支持從查詢輸入中自動(dòng)推斷出的多種值類型:

  • String(字符串)?用雙引號(hào)或反引號(hào)引起來,例如"200"或`us-central1`。
  • Duration(時(shí)間)?是一串十進(jìn)制數(shù)字,每個(gè)數(shù)字都有可選的數(shù)和單位后綴,如"300ms"?、"1.5h"? 或"2h45m"?,有效的時(shí)間單位是"ns"?、"us"?(或"μs"?)、"ms"?、"s"?、"m"?、"h"。
  • Number(數(shù)字)是浮點(diǎn)數(shù)(64 位),如 250、89.923。
  • Bytes(字節(jié))?是一串十進(jìn)制數(shù)字,每個(gè)數(shù)字都有可選的數(shù)和單位后綴,如"42MB"?、"1.5Kib"? 或"20b"?,有效的字節(jié)單位是"b"?、"kib"?、"kb"?、"mib"?、"mb"?、"gib"?、"gb"?、"tib"?、"tb"?、"pib"?、"bb"?、"eb"。

字符串類型的工作方式與 Prometheus 標(biāo)簽匹配器在日志流選擇器中使用的方式完全一樣,這意味著你可以使用同樣的操作符(=、!=、=~、!~)。

使用 Duration、Number 和 Bytes 將在比較前轉(zhuǎn)換標(biāo)簽值,并支持以下比較器。

  • ==? 或= 相等比較
  • != 不等于比較
  • >? 和>= 用于大于或大于等于比較

例如 logfmt | duration > 1m and bytes_consumed > 20MB 過濾表達(dá)式。

如果標(biāo)簽值的轉(zhuǎn)換失敗,日志行就不會(huì)被過濾,而會(huì)添加一個(gè) __error__ 標(biāo)簽。你可以使用 and和 or 來連接多個(gè)謂詞,它們分別表示且和或的二進(jìn)制操作,and 可以用逗號(hào)、空格或其他管道來表示,標(biāo)簽過濾器可以放在日志管道的任何地方。

以下所有的表達(dá)式都是等價(jià)的:

| duration >= 20ms or size == 20kb and method!~"2.."
| duration >= 20ms or size == 20kb | method!~"2.."
| duration >= 20ms or size == 20kb,method!~"2.."
| duration >= 20ms or size == 20kb method!~"2.."

默認(rèn)情況下,多個(gè)謂詞的優(yōu)先級(jí)是從右到左,你可以用圓括號(hào)包裝謂詞,強(qiáng)制使用從左到右的不同優(yōu)先級(jí)。

例如,以下內(nèi)容是等價(jià)的:

| duration >= 20ms or method="GET" and size <= 20KB
| ((duration >= 20ms or method="GET") and size <= 20KB)

它將首先評(píng)估 duration>=20ms or method="GET",要首先評(píng)估 method="GET" and size<=20KB,請(qǐng)確保使用適當(dāng)?shù)睦ㄌ?hào),如下所示。

| duration >= 20ms or (method="GET" and size <= 20KB)

日志行格式表達(dá)式

日志行格式化表達(dá)式可以通過使用 Golang 的 text/template 模板格式重寫日志行的內(nèi)容,它需要一個(gè)字符串參數(shù) | line_format "{{.label_name}}" 作為模板格式,所有的標(biāo)簽都是注入模板的變量,可以用 {{.label_name}} 的符號(hào)來使用。

例如,下面的表達(dá)式:

{container="frontend"} | logfmt | line_format "{{.query}} {{.duration}}"

將提取并重寫日志行,只包含 query 和請(qǐng)求的 duration。你可以為模板使用雙引號(hào)字符串或反引號(hào) `{{.label_name}}` 來避免轉(zhuǎn)義特殊字符。

此外 line_format 也支持?jǐn)?shù)學(xué)函數(shù),例如:

如果我們有以下標(biāo)簽 ip=1.1.1.1, status=200 和 duration=3000(ms), 我們可以用 duration 除以 1000 得到以秒為單位的值:

{container="frontend"} | logfmt | line_format "{{.ip}} {{.status}} {{div .duration 1000}}"

上面的查詢將得到的日志行內(nèi)容為1.1.1.1 200 3。

標(biāo)簽格式表達(dá)式

| label_format 表達(dá)式可以重命名、修改或添加標(biāo)簽,它以逗號(hào)分隔的操作列表作為參數(shù),可以同時(shí)進(jìn)行多個(gè)操作。

當(dāng)兩邊都是標(biāo)簽標(biāo)識(shí)符時(shí),例如 dst=src,該操作將把 src 標(biāo)簽重命名為 dst。

左邊也可以是一個(gè)模板字符串,例如 dst="{{.status}} {{.query}}",在這種情況下,dst 標(biāo)簽值會(huì)被 Golang 模板執(zhí)行結(jié)果所取代,這與 | line_format 表達(dá)式是同一個(gè)模板引擎,這意味著標(biāo)簽可以作為變量使用,也可以使用同樣的函數(shù)列表。

在上面兩種情況下,如果目標(biāo)標(biāo)簽不存在,那么就會(huì)創(chuàng)建一個(gè)新的標(biāo)簽。

重命名形式 dst=src 會(huì)在將 src 標(biāo)簽重新映射到 dst 標(biāo)簽后將其刪除,然而,模板形式將保留引用的標(biāo)簽,例如 dst="{{.src}}" 的結(jié)果是 dst 和 src 都有相同的值。

一個(gè)標(biāo)簽名稱在每個(gè)表達(dá)式中只能出現(xiàn)一次,這意味著 | label_format foo=bar,foo="new" 是不允許的,但你可以使用兩個(gè)表達(dá)式來達(dá)到預(yù)期效果,比如 | label_format foo=bar | label_format foo="new"。

日志度量

LogQL 同樣支持通過函數(shù)方式將日志流進(jìn)行度量,通常我們可以用它來計(jì)算消息的錯(cuò)誤率或者排序一段時(shí)間內(nèi)的應(yīng)用日志輸出 Top N。

區(qū)間向量

LogQL 同樣也支持有限的區(qū)間向量度量語句,使用方式和 PromQL 類似,常用函數(shù)主要是如下 4 個(gè):

  • rate: 計(jì)算每秒的日志條目。
  • count_over_time: 對(duì)指定范圍內(nèi)的每個(gè)日志流的條目進(jìn)行計(jì)數(shù)。
  • bytes_rate: 計(jì)算日志流每秒的字節(jié)數(shù)。
  • bytes_over_time: 對(duì)指定范圍內(nèi)的每個(gè)日志流的使用的字節(jié)數(shù)。

比如計(jì)算 nginx 的 qps:

rate({filename="/var/log/nginx/access.log"}[5m]))

計(jì)算 kernel 過去 5 分鐘發(fā)生 oom 的次數(shù):

count_over_time({filename="/var/log/message"} |~ "oom_kill_process" [5m]))

聚合函數(shù)

LogQL 也支持聚合運(yùn)算,我們可用它來聚合單個(gè)向量內(nèi)的元素,從而產(chǎn)生一個(gè)具有較少元素的新向量,當(dāng)前支持的聚合函數(shù)如下:

  • sum:求和。
  • min:最小值。
  • max:最大值。
  • avg:平均值。
  • stddev:標(biāo)準(zhǔn)差。
  • stdvar:標(biāo)準(zhǔn)方差。
  • count:計(jì)數(shù)。
  • bottomk:最小的 k 個(gè)元素。
  • topk:最大的 k 個(gè)元素。

聚合函數(shù)我們可以用如下表達(dá)式描述:

([parameter,] ) [without|by (

對(duì)于需要對(duì)標(biāo)簽進(jìn)行分組時(shí),我們可以用 without 或者 by 來區(qū)分。比如計(jì)算 nginx 的 qps,并按照 pod 來分組:

sum(rate({filename="/var/log/nginx/access.log"}[5m])) by (pod)

只有在使用 bottomk 和 topk 函數(shù)時(shí),我們可以對(duì)函數(shù)輸入相關(guān)的參數(shù)。比如計(jì)算 nginx 的 qps 最大的前 5 個(gè),并按照 pod 來分組:

topk(5,sum(rate({filename="/var/log/nginx/access.log"}[5m])) by (pod)))

二元運(yùn)算

數(shù)學(xué)計(jì)算

Loki 存的是日志,都是文本,怎么計(jì)算呢?顯然 LogQL 中的數(shù)學(xué)運(yùn)算是面向區(qū)間向量操作的,LogQL 中的支持的二進(jìn)制運(yùn)算符如下:

  • +:加法。
  • -:減法。
  • *:乘法。
  • /:除法。
  • %:求模。
  • ^:求冪。

比如我們要找到某個(gè)業(yè)務(wù)日志里面的錯(cuò)誤率,就可以按照如下方式計(jì)算:

sum(rate({app="foo", level="error"}[1m])) / sum(rate({app="foo"}[1m]))

邏輯運(yùn)算

集合運(yùn)算僅在區(qū)間向量范圍內(nèi)有效,當(dāng)前支持

  • and:并且。
  • or:或者。
  • unless:排除。

比如:

rate({app=~"foo|bar"}[1m]) and rate({app="bar"}[1m])

比較運(yùn)算

LogQL 支持的比較運(yùn)算符和 PromQL 一樣,包括:

  • ==:等于。
  • !=:不等于。
  • >:大于。
  • >=: 大于或等于。
  • <:小于。
  • <=: 小于或等于。

通常我們使用區(qū)間向量計(jì)算后會(huì)做一個(gè)閾值的比較,這對(duì)應(yīng)告警是非常有用的,比如統(tǒng)計(jì) 5 分鐘內(nèi) error 級(jí)別日志條目大于 10 的情況:

count_over_time({app="foo", level="error"}[5m]) > 10

我們也可以通過布爾計(jì)算來表達(dá),比如統(tǒng)計(jì) 5 分鐘內(nèi) error 級(jí)別日志條目大于 10 為真,反正則為假:

count_over_time({app="foo", level="error"}[5m]) > bool 10

注釋

LogQL 查詢可以使用 # 字符進(jìn)行注釋,例如:

{app="foo"} # anything that comes after will not be interpreted in your query

對(duì)于多行 LogQL 查詢,可以使用 # 排除整個(gè)或部分行:

{app="foo"}
| json
# this line will be ignored
| bar="baz" # this checks if bar = "baz"

查詢示例

這里我們部署一個(gè)示例應(yīng)用,該應(yīng)用程序是一個(gè)偽造的記錄器,它的日志具有 debug、info 和 warning 輸出到 stdout。error 級(jí)別的日志將被寫入 stderr,實(shí)際的日志消息以 JSON 格式生成,每 500 毫秒將創(chuàng)建一條新的日志消息。日志消息格式如下所示:

{
"app":"The fanciest app of mankind",
"executable":"fake-logger",
"is_even": true,
"level":"debug",
"msg":"This is a debug message. Hope you'll catch the bug",
"time":"2022-04-04T13:41:50+02:00",
"version":"1.0.0"
}

使用下面的命令來創(chuàng)建示例應(yīng)用:

cat <apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: fake-logger
environment: development
name: fake-logger
spec:
selector:
matchLabels:
app: fake-logger
environment: development
template:
metadata:
labels:
app: fake-logger
environment: development
spec:
containers:
- image: thorstenhans/fake-logger:0.0.2
name: fake-logger
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 10m
memory: 32Mi
EOF

我們可以使用 {app="fake-logger"} 在 Grafana 中查詢到該應(yīng)用的日志流數(shù)據(jù)。

由于我們?cè)撌纠龖?yīng)用的日志是 JSON 形式的,我們可以采用 JSON 解析器來解析日志,表達(dá)式為 {app="fake-logger"} | json,如下所示。

使用 JSON 解析器解析日志后可以看到 Grafana 提供的面板會(huì)根據(jù) level 的值使用不同的顏色進(jìn)行區(qū)分,而且現(xiàn)在我們?nèi)罩镜膶傩砸脖惶砑拥搅?Log 的標(biāo)簽中去了。

現(xiàn)在 JSON 中的數(shù)據(jù)變成了日志標(biāo)簽我們自然就可以使用這些標(biāo)簽來過濾日志數(shù)據(jù)了,比如我們要過濾 level=error 的日志,只使用表達(dá)式 {app="fake-logger"} | json | level="error" 即可實(shí)現(xiàn)。

此外我們還可以根據(jù)我們的需求去格式化輸出日志,使用 line_format 即可實(shí)現(xiàn),比如我們這里使用查詢語句 {app="fake-logger"} | json |is_even="true" | line_format "在 {{.time}} 于 {{.level}}@{{.pod}} Pod中產(chǎn)生了日志 {{.msg}}" 來格式化日志輸出。

監(jiān)控大盤

這里我們以監(jiān)控 Kubernetes 的事件為例進(jìn)行說明。首先需要安裝 [kubernetes-event-exporter],地址  https://github.com/opsgenie/kubernetes-event-exporter/tree/master/deploy,kubernetes-event-exporter 日志會(huì)打印到 stdout,然后我們的 promtail 會(huì)將日志上傳到 Loki。

然后導(dǎo)入 https://grafana.com/grafana/dashboards/14003 這個(gè) Dashboard 即可,不過需要注意修改每個(gè)圖表中的過濾標(biāo)簽為 job="monitoring/event-exporter"。

修改后正常就可以在 Dashboard 中看到集群中的相關(guān)事件信息了,不過建議用記錄規(guī)則去替換面板中的查詢語句。

建議

  1. 盡量使用靜態(tài)標(biāo)簽,開銷更小,通常日志在發(fā)送到 Loki 之前注入 label,推薦的靜態(tài)標(biāo)簽包含:
  • 宿主機(jī):kubernetes/hosts。
  • 應(yīng)用名:kubernetes/labels/app_kubernetes_io/name。
  • 組件名:kubernetes/labels/name。
  • 命名空間:kubernetes/namespace。
  • 其他靜態(tài)標(biāo)簽,如環(huán)境、版本等。
  1. 謹(jǐn)慎使用動(dòng)態(tài)標(biāo)簽。過多的標(biāo)簽組合會(huì)造成大量的流,它會(huì)讓 Loki 存儲(chǔ)大量的索引和小塊的對(duì)象文件。這些都會(huì)顯著消耗 Loki 的查詢性能。為避免這些問題,在你知道需要之前不要添加標(biāo)簽。Loki 的優(yōu)勢在于并行查詢,使用過濾器表達(dá)式(label="text", |~ "regex", ...)來查詢?nèi)罩緯?huì)更有效,并且速度也很快。

  1. 有界的標(biāo)簽值范圍,作為 Loki 的用戶或操作員,我們的目標(biāo)應(yīng)該是使用盡可能少的標(biāo)簽來存儲(chǔ)你的日志。這意味著,更少的標(biāo)簽帶來更小的索引,從而導(dǎo)致更好的性能,所以我們?cè)谔砑訕?biāo)簽之前一定要三思而行。
  2. 配置緩存,Loki 可以為多個(gè)組件配置緩存, 可以選擇 redis 或者 memcached,這可以顯著提高性能。
  3. 合理使用 LogQL 語法,可大幅提高查詢效率。Label matchers(標(biāo)簽匹配器)是你的第一道防線,是大幅減少你搜索的日志數(shù)量(例如,從100TB到1TB)的最好方法。當(dāng)然,這意味著你需要在日志采集端上有良好的標(biāo)簽定義規(guī)范。

分享題目:Grafana Loki 查詢語言 LogQL 使用
文章鏈接:http://m.5511xx.com/article/ccdpgdj.html