Pada kali ini kita akan mencoba mempelajari Logrus lebih mendalam yaitu mengenai Field, entry dan Hook. Fitur-fitur yang disediakan oleh Logrus untuk kebutuhan Logger ini sangat bermanfaat sekali bagi kita ketika kita membutuhkan beberapa fitur yang menunjang bisnis kita. Misalkan field
ini digunakan untuk menyisipkan data atau informasi ke dalam log dan beberapa lain yang akan kita bahas secara rinci.
Field pada Logrus
Ketika kita membutuhkan beberapa Field untuk dimunculkan atau disematkan dalam log file kita, maka Field ini bisa kita gunakan untuk menyisipkan sesuatu data atau informasi yang dibutuhkan untuk menunjang kebutuhan bisnis ataupun tracing ketika terjadi permasalahan pada sistem kita.
Sebenarnya bisa kita buat menyisipkan secara manual informasi tersebut di message-nya tetapi Logrus telah menyediakan cara yang lebih baik yaitu dengan menggunakan fitur Field. Dengan fitur ini bisa menambahkan informasi kepada log yang kita kirim sesuai dengan kebutuhannya.
Fungsi yang akan kita gunakan pada Logrus yaitu fungsi
logger.WithField()
// atau
logger.WithFields()
Langsung kita akan mencoba dengan membuat fungsi seperti dibawah ini.
func TestField(t *testing.T) {
logger := logrus.New()
logger.SetFormatter(&logrus.JSONFormatter{})
logger.WithField("user_id", 12345).Info("Hello World")
fields := map[string]interface{}{
"user_id": 12345,
"shop_id": 123,
}
logger.WithFields(fields).Infof("this is information about shop")
}
Maka akan terlihat output pada file seperti dibawah ini.
{"level":"info","msg":"Hello World","time":"2024-04-30T16:57:07+07:00","user_id":12345}
{"level":"info","msg":"this is information about shop","shop_id":123,"time":"2024-04-30T16:57:07+07:00","user_id":12345}
Bisa kita lihat pada output memiliki fields user_id
dan baris yang terakhir terdapat fields user_id
dan shop_id
yang mana sudah kita buat field sendiri.
Entry pada Logrus
Entry ini adalah sebuah struct
yang merepresentasikan dari log agar bisa dikirim oleh Logrus. Setiap log yang kita kirim itu sebenarnya akan dibuat oleh object Entry. Misalkan ketika membuat Formatter sendiri, maka parameter yang digunakan untuk melakukan formatting bukan tipe string melainkan yaitu object dari Entry.
Lebih lengkapnya bisa dibaca di file ini. Ketika kita membuat entry kita bisa menggunakan fungsi
logrus.NewEntry()
Sebenarnya Entry
ini jarang sekali kita pakai tetapi untuk lebih memahami pelajaran log ini kita akan coba membuatnya dengan terlebih dahulu membuat fungsi seperti dibawah ini.
func TestEntry(t *testing.T) {
logger := logrus.New()
logger.SetFormatter(&logrus.JSONFormatter{})
logger.WithField("user_id", 12345).Info("Hello World")
entry := logrus.NewEntry(logger)
entry.WithField("user_id", 1235)
entry.Info("log info using entry")
}
Maka, hasilnya sama seperti halnya kita menambahkan Field karena pada dasarnya saat kita menambahkan field itu sama halnya inisialisasi Entry.
Hook pada Logrus
Hook pada Logrus ini adalah sebuah struct
yang bisa digunakan untuk menambahkan ke dalam Logger sebagai callback ketika melakukan eksekusi log atau terjadi sesuatu pada sistem kita pada level tertentu.
Misalnya, kita akan mengirimkan notifikasi via chat ke Slack Channel ketika ada Log dengan level Error atau yang lainnya. Kita juga bisa menambahkan Hook custom dengan menggunakan fungsi
logger.AddHook()
Agar bisa lebih memahami mekanisme Hook, kita akan coba menggunakannya dengan terlebih dahulu membuat kode seperti dibawah ini.
type SimpleHook struct{}
func (s *SimpleHook) Levels() []logrus.Level {
return []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel}
}
func (s *SimpleHook) Fire(entry *logrus.Entry) error {
fmt.Println("Simple Hook", entry.Level, entry.Message)
return nil
}
Ini adalah contoh simpel ketika kita membuat Hook, sebelum melakukan set ke dalam Hook dari Logrus. Method Levels()
ini digunakan untuk memastikan pada Level tertentu akan menggunakan Hook yang sudah kita inisialisasi.
Dan method Fire()
ini yang nanti akan dieksekusi oleh Logrus sebagai mekanisme Hook setelah dilakukan logger.
Selanjutnya kita buat fungsi unit test untuk memastikan Hook yang kita buat berjalan dengan baik.
func TestHook(t *testing.T) {
logger := logrus.New()
logger.AddHook(&SimpleHook{})
logger.Info("Hello info")
logger.Warn("Hello warn")
logger.Error("Hello error")
logger.Fatal("Hello fatal")
}
Setelah kita eksekusi atau jalankan fungsi unit test tersebut maka akan terlihat seperti dibawah ini.
time="2024-04-30T17:44:58+07:00" level=info msg="Hello info"
time="2024-04-30T17:44:58+07:00" level=warning msg="Hello warn"
Simple Hook error Hello error
time="2024-04-30T17:44:58+07:00" level=error msg="Hello error"
Simple Hook fatal Hello fatal
time="2024-04-30T17:44:58+07:00" level=fatal msg="Hello fatal"
Terlihat pada log file terdapat Simple Hook error Hello error
dan Simple Hook fatal Hello fatal
setelah dilakukan logging, ini menandakan bahwa setelah melakukan log maka akan mengeksekusi Hook selanjutnya berdasarkan level yang sudah kita tentukan. Sedangkan ketika kita log pada level Info
dan Warn
itu tidak tereksekusi Hook yang sudah kita tambahkan.
Baiklah, bisa kita simpulkan bahwa Hook ini sangat bermanfaat buat kita untuk alerting ASAP (as soon as possible) untuk sistem kita jika terjadi masalah agar kita lebih (aware) pada sistem kita dan (acknowledge) lebih cepat.