iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Modern Web

Let's Go! 解剖Go server開發到部署的過程系列 第 11

day 11 - log服務想說的話

log是什麼?為什麼要寫log? 寫了有什麼幫助?

寫log就像是在幫服務表達它的各種心情, 一個request從api接口進來之後走過的每個路徑,遇到的每個關卡跟發生的錯誤,都是可以log下來的資訊,至於log要紀錄到多詳盡則是要看api本身的屬性。api input的參數是我會紀錄下來的項目之一,另外像是重要的api執行時間、外部api回應時間跟結果我也會紀錄下來,再來是發生的所有錯誤會依照錯誤的緊急程度區分為NoticeWarningErrorEmergency......等,讓其他人在讀我的log的時候也能清楚明瞭的知道服務發生什麼事和緊急程度為何, log不是只寫給自己看的,它是要讓服務有任何狀況時,大家都可以讀懂log反應出來的資訊。

這邊選擇的是logrus這個套件來記錄log,為了保留之後更換套件的彈性,所以一樣會再把套件包裝一次。大概的包裝方式如下:

log
├── log.go
└── log_test.go
package coconutLog

import (
	"github.com/sirupsen/logrus"
)

type Logger struct {
	Log *logrus.Logger
}

type Entry struct {
	Entry *logrus.Entry
}

func New() *Logger {
	log := logrus.New()
	log.SetFormatter(&logrus.JSONFormatter{})

	return &Logger{
		Log: log,
	}
}

func (l *Logger) Debugf(format string, args ...interface{}) {
	l.Log.Printf(format, args...)
}

func (l *Logger) Errorf(format string, args ...interface{}) {
	l.Log.Errorf(format, args...)
}

func (l *Logger) WithFields(fields map[string]interface{}) (e *Entry) {
	e = &Entry{
		Entry: l.Log.WithFields(fields),
	}

	return e
}

func (l *Logger) WithError(err error) (e *Entry) {
	e = &Entry{
		Entry: l.Log.WithError(err),
	}

	return e
}

func (e *Entry) Debugf(format string, args ...interface{}) {
	e.Entry.Printf(format, args...)
}

func (e *Entry) Errorf(format string, args ...interface{}) {
	e.Entry.Errorf(format, args...)
}

一樣,包裝後寫go test

package coconutLog

import (
	"errors"
	"testing"
)

func TestLog(t *testing.T) {
	logger := New()
	logger.Debugf("前天星期%s", "三")
	logger.WithFields(map[string]interface{}{"昨天": "9/9"}).Debugf("星期%s", "四")
	logger.WithFields(map[string]interface{}{"今天": "9/10"}).Errorf("星期%s", "五")
	logger.WithError(errors.New("後天")).Errorf("星期%s", "六")
	logger.Errorf("最後是 星期%s", "天")
}

logrus提供各種訊息的等級來區分log的緊急程度,另外加上log.SetFormatter(&logrus.JSONFormatter{})之後就可以轉成JSON格式輸出,方便於資料的收集跟輸出格式整理。

-> % go test
{"level":"info","msg":"前天星期三","time":"2021-09-17T11:52:24+08:00"}
{"level":"info","msg":"星期四","time":"2021-09-17T11:52:24+08:00","昨天":"9/9"}
{"level":"error","msg":"星期五","time":"2021-09-17T11:52:24+08:00","今天":"9/10"}
{"error":"後天","level":"error","msg":"星期六","time":"2021-09-17T11:52:24+08:00"}
{"level":"error","msg":"最後是 星期天","time":"2021-09-17T11:52:24+08:00"}
PASS
ok      github.com/evelynocean/coconut/lib/log  0.719s

寫好log是一件很重要的事情, 我會在專案完成近80%的時候開始逐行檢視是否需要補上log, 在服務剛上線的時候log可以協助查看API的狀況, 等到服務運行一陣子之後就可以評估關掉debug跟info等級的log, 減少log的紀錄量, 或是針對常常跳警報的項目增加log, 確實記錄狀況發生當下的資訊來輔助查找問題。另外還要評估log的保存時長, 排程去清理掉舊的log資訊, 避免硬碟被塞爆。


上一篇
day 10 - 千萬不要放過error
下一篇
day 12 - API組裝實作
系列文
Let's Go! 解剖Go server開發到部署的過程30

尚未有邦友留言

立即登入留言