Skip to content

NimTechnology

Trình bày các công nghệ CLOUD một cách dễ hiểu.

  • Kubernetes & Container
    • Docker
    • Kubernetes
      • Ingress
      • Pod
    • Helm Chart
    • OAuth2 Proxy
    • Isito-EnvoyFilter
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Vault
    • Longhorn – Storage
    • VictoriaMetrics
    • MetalLB
    • Kong Gateway
  • CI/CD
    • ArgoCD
    • ArgoWorkflows
    • Argo Events
    • Spinnaker
    • Jenkins
    • Harbor
    • TeamCity
    • Git
      • Bitbucket
  • Coding
    • DevSecOps
    • Terraform
      • GCP – Google Cloud
      • AWS – Amazon Web Service
      • Azure Cloud
    • Golang
    • Laravel
    • Python
    • Jquery & JavaScript
    • Selenium
  • Log, Monitor & Tracing
    • DataDog
    • Prometheus
    • Grafana
    • ELK
      • Kibana
      • Logstash
  • BareMetal
    • NextCloud
  • Toggle search form

[Golang] Lưu log trên server với golang

Posted on February 6, 2022October 27, 2023 By nim No Comments on [Golang] Lưu log trên server với golang

Với lập trình thì log rất là quan trọng:
– Nhờ log mà chúng ta dễ đang bug app bị lỗi ở đâu.
– Nhờ log chúng ta sẽ hiểu được app của chúng ta hoạt động ntn?

mình được dạy sử dụng các package sau:
https://github.com/sirupsen/logrus
Logrus thì hỗ trợ rất nhiều tag log [“INFO”, “WARN”, “FATA”, ….]

Colored
Ở hàm runtime.Caller mình sẽ lấy được tên file và line
rất hữu ích cho việc lấy log.

https://github.com/rifflock/lfshook
chúng ta có thêm 1 thư việc nữa để lưu các file log lại.

https://github.com/lestrrat-go/file-rotatelogs
thư viện này để chúng ta quản lý log, như là file được sinh ra theo ngày…
THIS PROJECT HAS BEEN ARCHIVED
Nhưng chắc chả sao âu anh em hihi

Chúng ta sẽ tạo file log trong thư mục log

https://github.com/thanhniencung/backend-github-trending/blob/master/log/log.go

Hoặc sài file của mình bắt trước của anh trên.

package log

import (
	"encoding/json"
  rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/labstack/gommon/log"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
)

// Log global
var Log *logrus.Logger
var singletonLogger = &MyLogger{}

/*func init() {
	InitLogger(false)
}*/

// MyLogger extend logrus.MyLogger
type MyLogger struct {
	*logrus.Logger
}

// Logger returns singletonLogger
// NOTE: Must run InitLogger() before
func Logger() *MyLogger {
	return singletonLogger
}

// InitLogger return singleton logger
func InitLogger(forTest bool) *MyLogger {
	if Log != nil {
		singletonLogger = &MyLogger{
			Logger: Log,
		}
		return singletonLogger
	}

	var logPath string
	if runtime.GOOS == "windows" {
		logPath = "./log_files/"
	} else {
		logPath = "../../log_files/"
	}

	Log = logrus.New()

	if !forTest {
		writerInfo, err := rotatelogs.New(
			logPath+"info/"+os.Getenv("APP_NAME")+"_%Y%m%d_info.log",
			rotatelogs.WithMaxAge(30*24*time.Hour),
			rotatelogs.WithRotationTime(24*time.Hour),
		)
		if err != nil {
			log.Printf("Failed to create rotatelogs: %s", err)
			return nil
		}

		writerError, err := rotatelogs.New(
			logPath+"error/"+os.Getenv("APP_NAME")+"_%Y%m%d_error.log",
			rotatelogs.WithMaxAge(30*24*time.Hour),
			rotatelogs.WithRotationTime(24*time.Hour),
		)
		if err != nil {
			log.Printf("Failed to create rotatelogs: %s", err)
			return nil
		}

		Log.Hooks.Add(lfshook.NewHook(
			lfshook.WriterMap{
				logrus.ErrorLevel: writerError,
				logrus.WarnLevel:  writerInfo,
				logrus.InfoLevel:  writerInfo,
			},
			&logrus.TextFormatter{
				TimestampFormat:  time.RFC3339Nano,
				QuoteEmptyFields: true,
			},
		))
	}

	singletonLogger = &MyLogger{
		Logger: Log,
	}
	return singletonLogger
}

// LoggerHandler middleware logs the information about each HTTP request.
func LoggerHandler(next echo.HandlerFunc) echo.HandlerFunc {
	return func(ctx echo.Context) error {
		req := ctx.Request()
		if !strings.Contains(req.RequestURI, "healthcheck") {
			// add some default fields to the logger ~ on all messages
			logger := Log.WithFields(logrus.Fields{
				"id":          req.Header.Get(echo.HeaderXRequestID),
				"method":      req.Method,
				"ip":          ctx.RealIP(),
				"request_uri": req.RequestURI,
			})
			ctx.Set("logger", logger)
			startTime := time.Now()

			defer func() {
				rsp := ctx.Response()
				// at the end we will want to log a few more interesting fields
				logger.WithFields(logrus.Fields{
					"status_code":  rsp.Status,
					"runtime_nano": time.Since(startTime).Nanoseconds(),
				}).Info("Finished request")
			}()

			// now we will log out that we have actually started the request
			logger.WithFields(logrus.Fields{
				"id":             req.Header.Get(echo.HeaderXRequestID),
				"user_agent":     req.UserAgent(),
				"content_length": req.ContentLength,
			}).Info("Starting request")
		}

		err := next(ctx)
		if err != nil {
			ctx.Error(err)
		}
		return err
	}
}

// -----------------------------------
// Logger uses for trace
// -----------------------------------

// Args output message of print level
func Args(mess string, args ...interface{}) {
	a, _ := json.Marshal(args)
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"args": string(a),
		"file": file,
		"line": line,
	}).Info(mess)
}

// Print output message of print level
func Print(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Print(i...)
}

// Printf output format message of print level
func Printf(format string, i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Printf(format, i...)
}

// Debug output message of debug level
func Debug(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Debug(i...)
}

// Debugf output format message of debug level
func Debugf(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Debugf(format, args...)
}

// Info output message of info level
func Info(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Info(i...)
}

// Infof output format message of info level
func Infof(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Infof(format, args...)
}

// Warn output message of warn level
func Warn(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Warn(i...)
}

// Warnf output format message of warn level
func Warnf(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Warnf(format, args...)
}

// Error output message of error level
func Error(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Error(i...)
}

// Errorf output format message of error level
func Errorf(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Errorf(format, args...)
}

// Fatal output message of fatal level
func Fatal(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Fatal(i...)
}

// Fatalf output format message of fatal level
func Fatalf(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Fatalf(format, args...)
}

// Panic output message of panic level
func Panic(i ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Panic(i...)
}

// Panicf output format message of panic level
func Panicf(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)
	singletonLogger.WithFields(logrus.Fields{
		"file": file,
		"line": line,
	}).Panicf(format, args...)
}

// To logrus.Level
func toLogrusLevel(level log.Lvl) logrus.Level {
	switch level {
	case log.DEBUG:
		return logrus.DebugLevel
	case log.INFO:
		return logrus.InfoLevel
	case log.WARN:
		return logrus.WarnLevel
	case log.ERROR:
		return logrus.ErrorLevel
	}

	return logrus.InfoLevel
}

// To Echo.log.lvl
func toEchoLevel(level logrus.Level) log.Lvl {
	switch level {
	case logrus.DebugLevel:
		return log.DEBUG
	case logrus.InfoLevel:
		return log.INFO
	case logrus.WarnLevel:
		return log.WARN
	case logrus.ErrorLevel:
		return log.ERROR
	}

	return log.OFF
}

// Output return logger io.Writer
func (l *MyLogger) Output() io.Writer {
	return l.Out
}

// SetOutput logger io.Writer
func (l *MyLogger) SetOutput(w io.Writer) {
	l.Out = w
}

// Level return logger level
func (l *MyLogger) Level() log.Lvl {
	return toEchoLevel(l.Logger.Level)
}

// SetLevel logger level
func (l *MyLogger) SetLevel(v log.Lvl) {
	l.Logger.Level = toLogrusLevel(v)
}

// Formatter return logger formatter
func (l *MyLogger) Formatter() logrus.Formatter {
	return l.Logger.Formatter
}

// SetFormatter logger formatter
// Only support logrus formatter
func (l *MyLogger) SetFormatter(formatter logrus.Formatter) {
	l.Logger.Formatter = formatter
}

// Prefix return logger prefix
// This function do nothing
func (l *MyLogger) Prefix() string {
	return ""
}

// SetPrefix logger prefix
// This function do nothing
func (l *MyLogger) SetPrefix(p string) {
	// do nothing
}

// -----------------------------------
// Logger uses for Echo
// -----------------------------------

// Print output message of print level
func (l *MyLogger) Print(i ...interface{}) {
	l.Logger.Print(i...)
}

// Printf output format message of print level
func (l *MyLogger) Printf(format string, args ...interface{}) {
	l.Logger.Printf(format, args...)
}

// Printj output json of print level
func (l *MyLogger) Printj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Println(string(b))
}

// Debug output message of debug level
func (l *MyLogger) Debug(i ...interface{}) {
	l.Logger.Info(i...)
}

// Debugf output format message of debug level
func (l *MyLogger) Debugf(format string, args ...interface{}) {
	l.Logger.Debugf(format, args...)
}

// Debugj output message of debug level
func (l *MyLogger) Debugj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Debugln(string(b))
}

// Info output message of info level
func (l *MyLogger) Info(i ...interface{}) {
	l.Logger.Info(i...)
}

// Infof output format message of info level
func (l *MyLogger) Infof(format string, args ...interface{}) {
	l.Logger.Infof(format, args...)
}

// Infoj output json of info level
func (l *MyLogger) Infoj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Infoln(string(b))
}

// Warn output message of warn level
func (l *MyLogger) Warn(i ...interface{}) {
	l.Logger.Warn(i...)
}

// Warnf output format message of warn level
func (l *MyLogger) Warnf(format string, args ...interface{}) {
	l.Logger.Warnf(format, args...)
}

// Warnj output json of warn level
func (l *MyLogger) Warnj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Warnln(string(b))
}

// Error output message of error level
func (l *MyLogger) Error(i ...interface{}) {
	l.Logger.Error(i...)
}

// Errorf output format message of error level
func (l *MyLogger) Errorf(format string, args ...interface{}) {
	l.Logger.Errorf(format, args...)
}

// Errorj output json of error level
func (l *MyLogger) Errorj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Errorln(string(b))
}

// Fatal output message of fatal level
func (l *MyLogger) Fatal(i ...interface{}) {
	l.Logger.Fatal(i...)
}

// Fatalf output format message of fatal level
func (l *MyLogger) Fatalf(format string, args ...interface{}) {
	l.Logger.Fatalf(format, args...)
}

// Fatalj output json of fatal level
func (l *MyLogger) Fatalj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Fatalln(string(b))
}

// Panic output message of panic level
func (l *MyLogger) Panic(i ...interface{}) {
	l.Logger.Panic(i...)
}

// Panicf output format message of panic level
func (l *MyLogger) Panicf(format string, args ...interface{}) {
	l.Logger.Panicf(format, args...)
}

// Panicj output json of panic level
func (l *MyLogger) Panicj(j log.JSON) {
	b, err := json.Marshal(j)
	if err != nil {
		panic(err)
	}
	l.Logger.Panicln(string(b))
}

func (l *MyLogger) SetHeader(h string) {
	l.Logger.Info("Not implement yet")
}

và cuối cùng trong hàm main.go bạn cần khai báo init logger

Enable log Debug.

Thường chúng ta sẽ thiết kế như sau:
Usually, Chúng ta sẽ in log info => để biết là app đang hoạt động và log này rất ít.
log error => là khi application bị lỗi.
Khi cần debug: chúng ta sẽ set 1 biến hày 1 flag nào đó thì log debug sẽ hiện ra:

package main

import (
    "github.com/labstack/echo/v4"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "jougan/handler"
    "jougan/helper/monitor/monitor_impl"
    "jougan/log"
    "jougan/router"
    "os"
    "time"
)

func init() {
    os.Setenv("APP_NAME", "jougan-inspects-disk")
    logger := log.InitLogger(false)
    logger.SetLevel(1)
    os.Setenv("TZ", "Asia/Ho_Chi_Minh")
}

func main() {
...
...
}

Nếu bạn muốn hiện thị log debug thì set logger.SetLevel(1)
1 = debug

Ngoài ra chúng ta có tham kháo zap log.
https://github.com/ducnpdev/golang-demo/blob/logger/logger/log.go
https://viblo.asia/p/golang-log-ra-file-su-dung-zap-BQyJK9GwVMe

Kết hợp với echo:
https://github.com/brpaz/echozap
https://www.golinuxcloud.com/golang-zap-logger/

Golang

Post navigation

Previous Post: [Docker] Temporary failure in name resolution
Next Post: [Groovy] Handle String in Groovy

More Related Articles

[Golang] To use regex to filter and give any values you want. Golang
[Golang] Zap log in Golang Golang
[Selenium] Save cookies of any website that is running on Selenium. Golang
[GRPC/Golang] Bắt đầu Project Grpc với golang trên Windows. Coding
[Golang] Return Error in Golang Golang
How to code a tool to connect Kafka by Golang Golang

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Tham Gia Group DevOps nhé!
Để Nim có nhiều động lực ra nhiều bài viết.
Để nhận được những thông báo mới nhất.

Recent Posts

  • [AWS/EKS] Cache Docker image to accelerate EKS container deployment. July 10, 2025
  • [Laravel] Laravel Helpful June 26, 2025
  • [VScode] Hướng dẫn điều chỉnh font cho terminal June 20, 2025
  • [WordPress] Hướng dấn gửi mail trên WordPress thông qua gmail. June 15, 2025
  • [Bitbucket] Git Clone/Pull/Push with Bitbucket through API Token. June 12, 2025

Archives

  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021

Categories

  • BareMetal
    • NextCloud
  • CI/CD
    • Argo Events
    • ArgoCD
    • ArgoWorkflows
    • Git
      • Bitbucket
    • Harbor
    • Jenkins
    • Spinnaker
    • TeamCity
  • Coding
    • DevSecOps
    • Golang
    • Jquery & JavaScript
    • Laravel
    • NextJS 14 & ReactJS & Type Script
    • Python
    • Selenium
    • Terraform
      • AWS – Amazon Web Service
      • Azure Cloud
      • GCP – Google Cloud
  • Kubernetes & Container
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Docker
    • Helm Chart
    • Isito-EnvoyFilter
    • Kong Gateway
    • Kubernetes
      • Ingress
      • Pod
    • Longhorn – Storage
    • MetalLB
    • OAuth2 Proxy
    • Vault
    • VictoriaMetrics
  • Log, Monitor & Tracing
    • DataDog
    • ELK
      • Kibana
      • Logstash
    • Fluent
    • Grafana
    • Prometheus
  • Uncategorized
  • Admin

Copyright © 2025 NimTechnology.