لاگ باید جوری باشه که وقتی پروژه رفت بالا یا روی سیستم کسی ، به هیچ وجه نیاز به تفسیر و دیباگ نباشه

حتی صرفا نباید خطا رخ بده تا لاگ رو بخونیم

به گونه ای که طرف اگه لاگ رو خوند ، باید کامل بدونیم جنسش چی بوده ، کجا رخ داده ، داده هایی که طرف داده و ترکیده چی بوده و …

کدام api کال شده

https://www.kelche.co/blog/go/zap/

  package logger
  
  import (
  	"go.uber.org/zap/zapcore"
  	"os"
  	"sync"
  	"time"
  
  	"go.uber.org/zap"
  )
  
  var once sync.Once
  
  var instance *zap.Logger
  
  func Connect() *zap.Logger {
  
  	once.Do(func() {
  
  		config := zap.NewProductionEncoderConfig()
  		config.EncodeLevel = zapcore.CapitalColorLevelEncoder
  		config.EncodeTime = zapcore.TimeEncoderOfLayout(time.DateTime)
  		consoleEncoder := zapcore.NewConsoleEncoder(config)
  		defaultLogLevel := zapcore.InfoLevel
  
  		deepLevel := zapcore.FatalLevel
  		core := zapcore.NewTee(
  			zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), defaultLogLevel),
  		)
  
  		instance = zap.New(core, zap.AddCaller(), zap.AddStacktrace(deepLevel))
  
  		//logger, _ := zap.NewProduction()
  		//defer logger.Sync() // flushes buffer, if any
  		//logger.Sugar()
  		//instance1 := logger.Sugar()
  		//instance1.Info()
  		//var filename string
  		//err := os.MkdirAll("/var/logger/exploit/", 0555)
  		//if err != nil {
  		//	fmt.Println("MkdirAll : ", err)
  		//	filename = "./logs.logger"
  		//
  		//} else {
  		//	filename = "/var/logger/exploit/logs.logger"
  		//}
  		//filename = "/var/logger/exploit/logs.logger"
  		//
  		//config := zap.NewProductionEncoderConfig()
  		//config.EncodeTime = zapcore.ISO8601TimeEncoder
  		//fileEncoder := zapcore.NewJSONEncoder(config)
  		//logFile, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0777)
  		//if err != nil {
  		//	fmt.Println("os.OpenFile var/logger/exploit/logs.logger ", err)
  		//	filename = "./logs.logger"
  		//
  		//	logFile, err = os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0777)
  		//	if err != nil {
  		//		fmt.Println("os.OpenFile logs.logger ", err)
  		//
  		//		os.Exit(1)
  		//	}
  		//}
  		//writer := zapcore.AddSync(logFile)
  		//defaultLogLevel := zapcore.DebugLevel
  		//core := zapcore.NewTee(
  		//	zapcore.NewCore(fileEncoder, writer, defaultLogLevel),
  		//)
  		//instance = zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
  
  	})
  
  	return instance
  }

tips

توجه شود ارور زیر مجموعه لاگ است و می توان لاگ لول اینفو باشد ، می توان ارور باشد

بهتر است در محیط توسعه لاگ بین لایه ها هم باشد اما در محیط پروداکت ، لاگ در ابتدا و انتهای سرویس باشد مثلن در مانی در لایه ی کافکا لاگ زده میشه ، همون ابتدا می گیم در خواست اومده و اطلاعات در خواست ، و در نهایتهنگام پاسخ ، لاگ زده میشه و اگر ارور بود ، باید لاگ از لایه های زیری wrap شده باشه و لاگ شود یکی از ساختار های سادهلاگ :

{
  "timestamp": "2024-07-11T15:30:00Z",
  "level": "INFO",
  "service": "example-service",
  "message": "User successfully logged in",
  "logger": "com.example.service.UserService",
  "thread": "main",
  "context": {
    "user_id": "123456",
    "request_id": "abc-123-def-456",
    "ip_address": "192.168.1.100",
    "request_link": "https://your-service.com/requests/abc-123-def-456",
    "request_payload": {
      "username": "example_user",
      "password": "*****"
      // Add other relevant request payload fields as needed
    }
  }
}

و در نهایت میشه خروجی برنامه رو با logstash توی الستیک دامپ کرد

نکته : اگر در اجرای داکری سرویس از دستور زیر استفاده کنیم ، تمام لاگ ها مستقیم درون فایل لاگ ریخته میشود و هیچ لاگی در صفحه سیستم عامل پرینت نمی شود ، و در نهایت نتیجه می گیریم لاگ های داکری همیشه خالی است .

CMD /app/postgres_tailer >> /app/logs/log_tailer.log 2>>/app/logs/error.log

با توجه به فرض بالا ، لاگ های داکر همیشه خالی است :

docker logs -f id ------ empty

اگر هم سرویس را بدون ریختن لاگ در جایی طراحی کنیم ، لاگ ها درون docker logs ریخته میشود ، اما اگر در خارج از محیط داکری اجرا کنیم . لاگ ها را از دست می دهیم :) مطالعه شود بست پرکتیس سنتری !