GoFrame 搭配 Grafana 讀取 Loki log
配置 Docker
建立一資料夾(loki)
新增三檔案 loki-config.yml,promtail-local-config.yml,docker-compose.yml
以下為三檔案內容
loki-config.yml
=============================
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration
# analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/
#
# Statistics help us better understand how Loki is used, and they show us performance
# levels for most users. This helps us prioritize features and documentation.
# For more information on what's sent, look at
# https://github.com/grafana/loki/blob/main/pkg/usagestats/stats.go
# Refer to the buildReport method to see what goes into a report.
#
# If you would like to disable reporting, uncomment the following lines:
#analytics:
# reporting_enabled: false
=============================
promtail-local-config.yml
=============================
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*log
=============================
docker-compose.yml
=============================
version: "3"
networks:
loki:
services:
loki:
image: grafana/loki:2.8.0
ports:
- "3100:3100"
volumes:
- ./loki-config.yml:/etc/loki/local-config.yml
command: -config.file=/etc/loki/local-config.yml
networks:
- loki
promtail:
image: grafana/promtail:2.8.0
volumes:
- /var/log:/var/log
- ./promtail-local-config.yml:/etc/promtail/config.yml:ro
command: -config.file=/etc/promtail/config.yml
networks:
- loki
grafana:
environment:
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
entrypoint:
- sh
- -euc
- |
mkdir -p /etc/grafana/provisioning/datasources
cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
orgId: 1
url: http://loki:3100
basicAuth: false
isDefault: true
version: 1
editable: false
EOF
/run.sh
image: grafana/grafana:10.0.3
ports:
- "3000:3000"
networks:
- loki
=============================
啟動 Grafana
開啟 Docker Desktop
執行 docker compose up -d
設定 Grafana admin
瀏覽器開啟 http://localhost:3000/?orgId=1,點擊 Sign in
輸入預設帳/密 admin/admin, 後可以修改密碼
查詢 Loki log
重新登入後,點擊 Toggle Menu,並選擇 Explore
點擊 Label browser, 於畫面中點擊 job(1) 中的 varlogs 後,點擊 Show logs,結束設定,即可以看到結果
利用 postman 新增 log
使用 post,url 為 http://localhost:3100/loki/api/v1/push,使用 json 格式,發送以下內容
{
"streams": [
{
"stream": {
"label": "postman"
},
"values": [
[
"1726476194219686912", //2024-09-16 16:43:14.210 時間戳
"fizzbuzz"
]
]
}
]
}
若回傳結果為 204,即代表成功
查詢 postman 發送的 log
請回到網頁,點擊 code,輸入 {label="postman"},時間區間選 Last 2 days, 即可看到結果
設定 goFrame Hook
目前分兩隻程式,一隻主要loki hook,一隻 main, 用來測試 loki hook
程式內容如下
loki.go
=============================
package loki
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/gogf/gf/v2/os/glog"
)
const (
LOKI_LABEL = "go-demo"
LOKI_APP = "gavin-job"
)
type LokiHook struct {
Logger *glog.Logger
Label string
App string
}
func (w *LokiHook) Write(p []byte) (n int, err error) {
var (
msg = string(p)
)
err = w.PostDataToLoki(msg)
return w.Logger.Write(p)
}
type LokiEntry struct {
Streams []struct {
Stream map[string]string `json:"stream"`
Values [][]string `json:"values"`
} `json:"streams"`
}
func (w *LokiHook) PostDataToLoki(msg string) error {
stream := make(map[string]string, 0)
//可以自由新增 key 值,方便 loki 查詢使用
stream["label"] = w.Label
stream["app"] = w.App //目前設定此來對應專案中 backend/app 中的應用
valueList := make([][]string, 0)
strTime := fmt.Sprintf("%v", time.Now().UnixNano())
newRow := []string{strTime, msg}
valueList = append(valueList, newRow)
data := LokiEntry{
Streams: []struct {
Stream map[string]string `json:"stream"`
Values [][]string `json:"values"`
}{
{
Stream: stream,
Values: valueList,
},
},
}
jsonData, err := json.Marshal(data)
if err != nil {
return err
}
resp, err := http.Post("http://localhost:3100/loki/api/v1/push", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}
=============================
main.go
=============================
package main
import (
"context"
"demo/loki/loki"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
)
func callFun(ctx context.Context, msg string) error {
g.Log().Infof(ctx, "callFun msg:%v", msg)
return nil
}
func main() {
ctx := gctx.New()
g.Log().SetWriter(&loki.LokiHook{
Logger: glog.New(),
Label: loki.LOKI_LABEL,
App: loki.LOKI_APP,
})
g.Log().Infof(ctx, "run callFun")
err := callFun(ctx, "hello, call fun test")
if err != nil {
g.Log().Errorf(ctx, "PostDataToLoki error:%v", err)
} else {
g.Log().Infof(ctx, "PostDataToLoki success")
}
}
=============================
執行 go run main.go
查詢 goFrame 發送 log
點擊 Label browser 用選的,或是輸入 {app="gavin-job"},或是 {label="go-demo"},即可以看到結果
Note
Label browser, 是方便不用輸入可以直接用選的,結果會轉成輸入的值
參考來源
https://blog.yowko.com/docker-compose-grafana-loki/