How can I enter golang in a log rotation file?

I am trying to write a web application that will run on a remote server. I need to log in to capture errors / debugging / auditing. I found that several log packages are available for the golang, including the standard "log" package. However, I need to fulfill three requirements:

  • Log Files Must Be Rotated
  • This applies to included packages that use the "log"
  • It must be cross-platform. The environment is Dev Linux and must be deployed to Windows.
+15
source share
6 answers

The best way to fulfill all three of your requirements, instead of creating an alternative logger structure, if you were satisfied with log.log at a basic level, you should instead configure the log output to your own io.Writer instance.

So basically, what I'm going to do here is an example when I create my own io.Writer:

import ( "os" "sync" "time" ) type RotateWriter struct { lock sync.Mutex filename string // should be set to the actual filename fp *os.File } // Make a new RotateWriter. Return nil if error occurs during setup. func New(filename string) *RotateWriter { w := &RotateWriter{filename: filename} err := w.Rotate() if err != nil { return nil } return w } // Write satisfies the io.Writer interface. func (w *RotateWriter) Write(output []byte) (int, error) { w.lock.Lock() defer w.lock.Unlock() return w.fp.Write(output) } // Perform the actual act of rotating and reopening file. func (w *RotateWriter) Rotate() (err error) { w.lock.Lock() defer w.lock.Unlock() // Close existing file if open if w.fp != nil { err = w.fp.Close() w.fp = nil if err != nil { return } } // Rename dest file if it already exists _, err = os.Stat(w.filename) if err == nil { err = os.Rename(w.filename, w.filename+"."+time.Now().Format(time.RFC3339)) if err != nil { return } } // Create a file. w.fp, err = os.Create(w.filename) return } 

Then you create a RotateWriter and use log.SetOutput to set this script (if other packages use a standard log instance) or alternately create your own instances using log.New to go through.

I have not decided the situation when the call to turn, I will leave it to you to decide. It would be quite simple to call it based on time, or alternately do it after a certain number of records or a certain number of bytes.

+15
source

Although @Crast gave a very good answer, I also want to draw attention to this - logger Nate Finch , which I eventually used.

Here's how to use it:

  1. First, clone the lumberjack's storage OR somehow get it.
  2. Run the go install command for the folder.
  3. Now import go "log" package and "lumberjack package".

Import ("magazine" "Github.com/natefinch/lumberjack")

  1. Now use it in your code like this:

Outside of main, declare a log variable.

 var errLog *log.Logger 

Inside the main:

 e, err := os.OpenFile("./foo.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { fmt.Printf("error opening file: %v", err) os.Exit(1) } errLog = log.New(e, "", log.Ldate|log.Ltime) errLog.SetOutput(&lumberjack.Logger{ Filename: "./foo.log", MaxSize: 1, // megabytes after which new file is created MaxBackups: 3, // number of backups MaxAge: 28, //days }) 

Now, as soon as the file size is 1 MB, a new file is created to save previous logs with current timestamps, and new logs will continue to be logged in the foo.log file. In addition, I created the file using os.OpenFile, but you may not need it, since this is done internally by the lumberjack, but I preferred it that way. Thanks, hope this helps. Thanks again @Crast and NateFinch .

+15
source

Here is a light weighted logging package that supports log rotation and automatic cleanup

https://github.com/antigloss/go/tree/master/logger

 // logger.Init must be called first to setup logger logger.Init("./log", // specify the directory to save the logfiles 400, // maximum logfiles allowed under the specified log directory 20, // number of logfiles to delete when number of logfiles exceeds the configured limit 100, // maximum size of a logfile in MB false) // whether logs with Trace level are written down logger.Info("Failed to find player! uid=%d plid=%d cmd=%s xxx=%d", 1234, 678942, "getplayer", 102020101) logger.Warn("Failed to parse protocol! uid=%d plid=%d cmd=%s", 1234, 678942, "getplayer") 
+3
source

One option that comes to mind is to wrap logging in your own type and provide a reload function, for example:

 type Logger struct { l *log.Logger f *os.File m sync.RWMutex } func NewLogger(fn string) (*Logger, error) { f, err := os.Create(fn) if err != nil { return nil, err } l := &Logger{ l: log.New(f, "your-app", log.Lshortfile), f: f, } return l, nil } func (l *Logger) Logf(f string, args ...interface{}) { lmRLock() llPrintf(f, args...) lmRUnlock() } func (l *Logger) Reload() (err error) { lmLock() defer lmUnlock() lfClose() if lf, err = os.Create(lfName()); err != nil { return } ll = log.New(lf, "your-app", log.Lshortfile) return } 

Then either listen for the signal (usually -HUP on * nix), or add an endpoint to your application that will call Logger.Reload() .

0
source

https://github.com/jame2981/log My package can help you.

 l1 := log.Pool.New("l1", "file:///tmp/test1.log") l2 := log.Pool.New("l2", "file:///tmp/test2.log") l3 := log.Pool.New("l3", "file:///tmp/test3.log") l4 := log.Pool.New("l4", "file:///tmp/test4.log") l1.Rotate() // rotate l1 only log.Pool.Rotate() // was rotate all instances. // rotate with signal reopen := make(chan os.Signal, 1) signal.Notify(reopen, syscall.SIGUSR1) go func() { for{ <-reopen l.Pool.Rotate() } }() 

install std logger writer to rotate the job yet.

 // std logger writer import "log" logger := log.New("test", "", 0) logger.SetOutput(l1.Writer()) 
0
source
 func (l *Logger) Logf(f string, args ...interface{}) { lmRLock() llPrintf(f, args...) lmRUnlock() } logger = log.New(lf, "your-app", log.Lshortfile) 

When this registrar is called from other files, the log.Lshortfile file always names the file in which the registrar is implemented. How can the registrar take the name of the file from which Logf is called?

0
source

Source: https://habr.com/ru/post/983186/


All Articles