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
    • Isito-EnvoyFilter
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Vault
    • Longhorn – Storage
    • VictoriaMetrics
    • MetalLB
    • Kong Gateway
  • CI/CD
    • ArgoCD
    • ArgoWorkflows
    • Spinnaker
    • Jenkins
    • Harbor
    • TeamCity
    • Git
      • Bitbucket
  • Coding
    • DevSecOps
    • Terraform
      • GCP – Google Cloud
      • AWS – Amazon Web Service
    • 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, 2022November 11, 2022 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

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] Looking filepath.Walk to return any file and children folder in the folder Golang
[Golang] Create multiple CRON functions by looping through a list Golang
[Golang] Design config file or environment file with Golang Golang
[Goland/Echo Framework/For loop] Return the results twice when using the echo framework and for loop on Goland Golang
[Golang] Ứng dụng Framework echo vào trong golang. Golang
[Golang] Note mấy thứ hay ho về golang Coding

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] Look into Data Transfer on AWS May 30, 2023
  • [Ddosify] How to test the application performance with Ddosify. May 30, 2023
  • [DevSecOps/TruffleHog] Find your repository’s secrets, sensitive words, and credentials. May 29, 2023
  • [DevSecOps] Tìm hiểu về thu thập thông tin. May 25, 2023
  • [coralogix/OpenTelemetry] Monitor Your K8s by Coralogix and OpenTelemetry Collector. May 24, 2023

Archives

  • 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
    • ArgoCD
    • ArgoWorkflows
    • Git
      • Bitbucket
    • Harbor
    • Jenkins
    • Spinnaker
    • TeamCity
  • Coding
    • DevSecOps
    • Golang
    • Jquery & JavaScript
    • Laravel
    • Python
    • Selenium
    • Terraform
      • AWS – Amazon Web Service
      • GCP – Google Cloud
  • Kubernetes & Container
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Docker
    • Helm Chart
    • Isito-EnvoyFilter
    • Kong Gateway
    • Kubernetes
      • Ingress
      • Pod
    • Longhorn – Storage
    • MetalLB
    • Vault
    • VictoriaMetrics
  • Log, Monitor & Tracing
    • DataDog
    • ELK
      • Kibana
      • Logstash
    • Fluent
    • Grafana
    • Prometheus
  • Uncategorized
  • Admin

Copyright © 2023 NimTechnology.