新聞中心
受 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ǎ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)站制作,營(yíng)銷型網(wǎng)站建設(shè),外貿(mào)營(yíng)銷網(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"
- 沒有參數(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"}`
- 帶參數(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 "
正則表達(dá)式必須包含至少一個(gè)命名的子匹配(例如(?P
例如,解析器 | regexp "(?P
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 "
比如我們來考慮下面的 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á)式的捕獲是由 < 和 > 字符分隔的字段名稱,比如
比如我們查看下面的日志行數(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á)式要簡(jiǎn)單得多。
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è)向量?jī)?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ī)則去替換面板中的查詢語句。
建議
- 盡量使用靜態(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)境、版本等。
- 謹(jǐn)慎使用動(dòng)態(tài)標(biāo)簽。過多的標(biāo)簽組合會(huì)造成大量的流,它會(huì)讓 Loki 存儲(chǔ)大量的索引和小塊的對(duì)象文件。這些都會(huì)顯著消耗 Loki 的查詢性能。為避免這些問題,在你知道需要之前不要添加標(biāo)簽。Loki 的優(yōu)勢(shì)在于并行查詢,使用過濾器表達(dá)式(label="text", |~ "regex", ...)來查詢?nèi)罩緯?huì)更有效,并且速度也很快。
- 有界的標(biāo)簽值范圍,作為 Loki 的用戶或操作員,我們的目標(biāo)應(yīng)該是使用盡可能少的標(biāo)簽來存儲(chǔ)你的日志。這意味著,更少的標(biāo)簽帶來更小的索引,從而導(dǎo)致更好的性能,所以我們?cè)谔砑訕?biāo)簽之前一定要三思而行。
- 配置緩存,Loki 可以為多個(gè)組件配置緩存, 可以選擇 redis 或者 memcached,這可以顯著提高性能。
- 合理使用 LogQL 語法,可大幅提高查詢效率。Label matchers(標(biāo)簽匹配器)是你的第一道防線,是大幅減少你搜索的日志數(shù)量(例如,從100TB到1TB)的最好方法。當(dāng)然,這意味著你需要在日志采集端上有良好的標(biāo)簽定義規(guī)范。
標(biāo)題名稱:Grafana Loki 查詢語言 LogQL 使用
鏈接URL:http://m.fisionsoft.com.cn/article/ccdpgdj.html


咨詢
建站咨詢
