Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
01 May 2024 · 6 mnt baca ·Artikel 119 / 119
Go

05 Implementasi Singleton Logger Logrus Pada Golang

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Pada kali ini kita akan mencoba untuk mengimplementasikan Singleton Design Pattern. Apa itu Singletone? Bisa kamu baca terlebih dahulu artikel disini. Agar lebih paham lagi jadi Singleton adalah desain standar perangkat lunak yang memberikan jaminan keberadaan hanya satu instance kelas, sambil mempertahankan titik akses global ke objeknya. Singleton adalah pola desain yang membatasi instantiation ke suatu objek, kita harus memastikan bahwa ini hanya terjadi sekali.

Ada 2 cara yang akan kita coba implementasikan Logrus diantaranya yaitu dengan langsung menggunakan Singleton Logrus sendiri dan membuat custom sendiri dikarenakan ada beberapa kebutuhan misalkan, set fields tersendiri atau kebutuhan yang lainnya.

Penggunaan Singletone Logrus

Nah pada kali ini kita akan coba membuat inisialisasi object dari Logrus sebagai Logger sehingga kita tidak perlu lagi membuat object logger sendiri. Jika kita menggunakan Singleton maka akan otomatis logger tersebut akan berubah. Secara default Logger singleton yang ada di Logrus itu menggunakan TextFormatter dan Info Level. Cara agar membuat Logger singletone kita akan langsung menggunakan package pada Logrus-nya saja.

Pertama akan buat fungsi unit test seperti dibawah ini.

go
1func TestSingletone(t *testing.T) {
2	// set formatter using JSON
3	logrus.SetFormatter(&logrus.JSONFormatter{})
4	// initiate log rus
5	logrus.Info("info using Logrus singleton")
6	logrus.Warn("warn using Logrus singleton")
7	logrus.Error("error using Logrus singleton")
8}

Maka ketika dijalankan akan tampil seperti dibawah ini.

txt
1{"level":"info","msg":"info using Logrus singleton","time":"2024-04-30T23:40:00+07:00"}
2{"level":"warning","msg":"warn using Logrus singleton","time":"2024-04-30T23:40:00+07:00"}
3{"level":"error","msg":"error using Logrus singleton","time":"2024-04-30T23:40:00+07:00"}

Membuat Custom Singleton untuk inisialisasi Logrus

Kita akan membuat Singleton untuk inisialisasi Logrus yang kita custom agar lebih mudah dan sesuai dengan kebutuhan kita. Pertama kita buat folder pkg/env ini digunakan untuk kebutuhan pengecekan environment yang diguanakn pada sistem kita. Package yang kita buat ini yaitu kebutuhan environment yang digunakan pada sistem kita agar lebih mudah penggunaannya.

Pertama, kita buat file env.go dengan fungsi inisialisasi sebagai berikut.

go
 1type ServiceEnvironment = string
 2
 3const (
 4	DevelopmentEnv  = "development"
 5	StagingEnv      = "staging"
 6	ProductionEnv   = "production"
 7	EnvironmentName = "environment"
 8	GoVersionName   = "go_version"
 9)
10
11var (
12	envName   = "SERVICE_ENV"
13	goVersion string
14)
15
16func Init() error {
17	err := SetFromEnvFile(".env")
18	if err != nil && !os.IsNotExist(err) {
19		log.Printf("failed to set env file: %v\n", err)
20		return err
21	}
22
23	goVersion = runtime.Version()
24	return nil
25}
26
27func SetFromEnvFile(filepath string) error {
28	if _, err := os.Stat(filepath); err != nil {
29		return err
30	}
31
32	f, err := os.Open(filepath)
33	if err != nil {
34		return err
35	}
36	scanner := bufio.NewScanner(f)
37	if err := scanner.Err(); err != nil {
38		return err
39	}
40	for scanner.Scan() {
41		text := scanner.Text()
42		text = strings.TrimSpace(text)
43		vars := strings.SplitN(text, "=", 2)
44		if len(vars) < 2 {
45			return err
46		}
47		if err := os.Setenv(vars[0], vars[1]); err != nil {
48			return err
49		}
50	}
51	return nil
52}

Fungsi initialize ini digunakan saat berjalannya sistem dengan membaca file .env lalu membaca beberapa tag yang ada pada file tersebut kemudian di set ke dalam enrironment sistem di server.

Ada beberapa fungsi tambahan untuk kebutuhan pada sistem diantaranya yaitu kebutuhan untuk mengambil data sesuai environment yang sedang berjalan misalkan development, staging, dan production.

go
 1func ServiceEnv() ServiceEnvironment {
 2	e := os.Getenv(envName)
 3	if e == "" {
 4		e = DevelopmentEnv
 5	}
 6	return e
 7}
 8
 9func GetVersion() string {
10	return goVersion
11}
12
13func IsDevelopment() bool {
14	return ServiceEnv() == DevelopmentEnv
15}
16
17func IsStaging() bool {
18	return ServiceEnv() == StagingEnv
19}
20
21func IsProduction() bool {
22	return ServiceEnv() == ProductionEnv
23}

Kemudian selanjutnya kita membuat file baru pada folder baru juga dengan nama pkg/log/log.go dengan isi seperti dibawah ini.

go
 1package log
 2
 3import (
 4	"errors"
 5	"os"
 6
 7	"github.com/santekno/learn-golang-logging/pkg/env"
 8	"github.com/sirupsen/logrus"
 9)
10
11var (
12	log, _        = NewLogger(&Config{Formatter: &TextFormatter, Level: InfoLevel, LogName: "application.log"})
13	JSONFormatter logrus.JSONFormatter
14	TextFormatter logrus.TextFormatter
15	serviceFields = map[string]interface{}{
16		env.EnvironmentName: env.ServiceEnv(),
17		env.GoVersionName:   env.GetVersion(),
18	}
19)
20
21type (
22	Level  = logrus.Level
23	Logger = *logrus.Logger
24)
25
26const (
27	// override logrus level
28	Paniclevel = logrus.PanicLevel
29	FatalLevel = logrus.FatalLevel
30	ErrorLevel = logrus.ErrorLevel
31	WarnLevel  = logrus.WarnLevel
32	InfoLevel  = logrus.InfoLevel
33	DebugLevel = logrus.DebugLevel
34	TraceLevel = logrus.TraceLevel
35)
36
37type Config struct {
38	logrus.Formatter
39	logrus.Level
40	LogName string
41}
42
43func NewLogger(cfg *Config) (Logger, error) {
44	l := logrus.New()
45	if env.IsDevelopment() {
46		l.SetFormatter(&logrus.TextFormatter{})
47	}
48	l.SetFormatter(cfg.Formatter)
49	l.SetLevel(cfg.Level)
50	return l, nil
51}
52
53func SetConfig(cfg *Config) error {
54	if cfg.LogName == "" {
55		return errors.New("log name is empty")
56	}
57
58	if !env.IsDevelopment() {
59		// initiation create file for logger
60		file, err := os.OpenFile(cfg.LogName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
61		if err != nil {
62			log.Fatal(err)
63		}
64
65		// set output file into logrus
66		log.SetOutput(file)
67	}
68
69	log.SetFormatter(cfg.Formatter)
70	log.SetLevel(cfg.Level)
71	return nil
72}

Pada file tersebut terdapat fungsi NewLogger disini kita akan inisialisasi Logrus dengan kebutuhan yang sudah ditentukan sesuai dengan parameter yang diinginkan pada config. Setelah itu kita juga membuat SetConfig lalu jika ingin membuat logging pada package yg kita buat ini sudah disematkan fields yang dibutuhkan seperti mengeset environment dan versi golang yang digunakan. Maka kita sediakan fungsi yang melakukan set tersebut seperti ini.

go
 1func Debug(args ...interface{}) {
 2	log.WithFields(serviceFields).Debug(args...)
 3}
 4
 5func Info(args ...interface{}) {
 6	log.WithFields(serviceFields).Info(args...)
 7}
 8
 9func Warn(args ...interface{}) {
10	log.WithFields(serviceFields).Warn(args...)
11}
12
13func Error(args ...interface{}) {
14	log.WithFields(serviceFields).Error(args...)
15}
16
17func Fatal(args ...interface{}) {
18	log.WithFields(serviceFields).Fatal(args...)
19}

Terakhir kita buat fungsi main pada file main.go dengan isi seperti dibawah ini.

go
 1func main() {
 2	// initialize environment
 3	err := env.Init()
 4	if err != nil {
 5		log.Fatal(err)
 6	}
 7
 8	// initialize config log
 9	err = log.SetConfig(&log.Config{
10		Formatter: &log.TextFormatter,
11		Level:     log.TraceLevel,
12		LogName:   "application.log",
13	})
14	if err != nil {
15		log.Fatal(err)
16	}
17
18	log.Debug("singleton debug")
19	log.Info("singleton info")
20	log.Warn("singleton warn")
21	log.Error("singleton debug")
22	log.Fatal("singleton fatal")
23}

Pada kode diatas bisa dilihat pertama ada inisialisasi environment untuk memastikan sistem kita berjalan dalam environment yang sesuai. Kemudian dilanjutkan dengan inisialisasi konfigurasi logging pada package yang sudah kita buat dan selanjutnya lakukan Logger seperti biasa.

Maka jika kita jalankan kode main tersebut akan terlihat seperti ini.

bash
1DEBU[0000] singleton debug                               environment=development go_version=go1.21.1
2INFO[0000] singleton info                                environment=development go_version=go1.21.1
3WARN[0000] singleton warn                                environment=development go_version=go1.21.1
4ERRO[0000] singleton debug                               environment=development go_version=go1.21.1
5FATA[0000] singleton fatal                               environment=development go_version=go1.21.1

Dan jika kita pindah dengan enviromnet misalkan untuk kebutuhan di production maka kita bisa tambahkan file environment menjadi ini

env
1SERVICE_ENV=production

Artikel Terkait

💬 Komentar