DEV Community

Mohammad Gholami
Mohammad Gholami

Posted on • Edited on

Saving log messages to a custom log file in Golang

Loggin in Unix log server in Golang

The log package in Golang, allows you to send log messages to log files. This log file can be syslog, mail.log, or your custom log file.
In this article, you'll learn how to do this.

Logging to syslog

The example below shows you the way of sending log messages to /var/log/syslog file in Unix os. We are going to use log/syslog package to set the log file.

package main

import (
    "log"
    "log/syslog"
    "os"
)


func main() {
    // Log to syslog
    logWriter, err := syslog.New(syslog.LOG_SYSLOG, "My Awesome App")
    if err != nil {
        log.Fatalln("Unable to set logfile:", err.Error())
    }
    // set the log output
    log.SetOutput(logWriter)

    log.Println("This is a log from GOLANG")
}
Enter fullscreen mode Exit fullscreen mode

Now, if you run the application, This is a log from GOLANG will be logged in the syslog file.
You can check it using this command:

$ tail -f /var/log/syslog
Enter fullscreen mode Exit fullscreen mode

The output would be something like this:

...
Dec 23 01:12:21 sam My Awesome App[102379]: 2020/12/23 01:12:21 This is a log from GOLANG
Enter fullscreen mode Exit fullscreen mode

Sometimes you need to log the line number logged message. To do that, you have to set the Lshortfile flag to the log package.

package main

import (
    "log"
    "log/syslog"
    "os"
)


func main() {
    // Log to syslog
    logWriter, err := syslog.New(syslog.LOG_SYSLOG, "My Awesome App")
    if err != nil {
        log.Fatalln("Unable to set logfile:", err.Error())
    }

    // + set log flag
    log.SetFlags(log.Lshortfile)

    // set the log output
    log.SetOutput(logWriter)

    log.Println("This is a log from GOLANG")
}
Enter fullscreen mode Exit fullscreen mode

The logged message would be like this:

Dec 23 01:17:28 sam My Awesome App[103468]: logging.go:20: This is a log from GOLANG
Enter fullscreen mode Exit fullscreen mode

As you can see, logging.go:20: is added to the log message and tell you the filename and line number of the code that the log function called.

Logging to a custom log file

If you want to write your log messages to a custom log file, take a look at the example below:

package main

import (
    "log"
    "log/syslog"
    "os"
)

func main() {
    // log to custom file
    LOG_FILE := "/tmp/myapp_log"
    // open log file
    logFile, err := os.OpenFile(LOG_FILE, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
    if err != nil {
        log.Panic(err)
    }
    defer logFile.Close()

    // Set log out put and enjoy :)
    log.SetOutput(logFile)

    // optional: log date-time, filename, and line number
    log.SetFlags(log.Lshortfile | log.LstdFlags)

    log.Println("Logging to custom file")
}
Enter fullscreen mode Exit fullscreen mode

Now run the application and check the result:

$ tail -f /tmp/myapp_log
2020/12/23 01:29:25 logging.go:29: Logging to custom file
Enter fullscreen mode Exit fullscreen mode

Is log package concurrency-safe?

Yes! All functions in the log package are concurrency-safe and it means that you can use the package from multiple goroutines. It clearly mentioned in the log package documentation:

A Logger represents an active logging object that generates lines of output to an io.Writer. Each logging operation makes a single call to the Writer's Write method. A Logger can be used simultaneously from multiple goroutines; it guarantees to serialize access to the Writer.

The example below will show you a simple example that writes log messages to a given log file from multiple goroutines:

package main

import (
    "log"
    "os"
    "sync"
    "time"
)

func main() {
    logFile, err := os.OpenFile("clog", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
    if err != nil {
        log.Fatalln(err)
    }
    log.SetOutput(logFile)

    var wg sync.WaitGroup

    wg.Add(3)

    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            log.Println("F1; loop:", i)
            time.Sleep(time.Millisecond)
        }
    }()

    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            log.Println("F2; loop:", i)
            time.Sleep(time.Millisecond * 2)
        }
    }()

    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            log.Println("F3; loop:", i)
            time.Sleep(time.Millisecond * 3)
        }
    }()

    wg.Wait()

}
Enter fullscreen mode Exit fullscreen mode

If you run the code the output will be something like this:

$ go run main.go
$ cat clog
2020/12/27 01:24:20 F3; loop: 0
2020/12/27 01:24:20 F1; loop: 0
2020/12/27 01:24:20 F2; loop: 0
2020/12/27 01:24:20 F1; loop: 1
2020/12/27 01:24:20 F2; loop: 1
2020/12/27 01:24:20 F1; loop: 2
2020/12/27 01:24:20 F3; loop: 1
2020/12/27 01:24:20 F1; loop: 3
2020/12/27 01:24:20 F2; loop: 2
2020/12/27 01:24:20 F1; loop: 4
2020/12/27 01:24:20 F1; loop: 5
2020/12/27 01:24:20 F3; loop: 2
2020/12/27 01:24:20 F2; loop: 3
2020/12/27 01:24:20 F1; loop: 6
2020/12/27 01:24:20 F1; loop: 7
2020/12/27 01:24:20 F2; loop: 4
2020/12/27 01:24:20 F1; loop: 8
2020/12/27 01:24:20 F3; loop: 3
2020/12/27 01:24:20 F1; loop: 9
2020/12/27 01:24:20 F2; loop: 5
2020/12/27 01:24:20 F3; loop: 4
2020/12/27 01:24:20 F2; loop: 6
2020/12/27 01:24:20 F2; loop: 7
2020/12/27 01:24:20 F3; loop: 5
2020/12/27 01:24:20 F2; loop: 8
2020/12/27 01:24:20 F3; loop: 6
2020/12/27 01:24:20 F2; loop: 9
2020/12/27 01:24:20 F3; loop: 7
2020/12/27 01:24:20 F3; loop: 8
2020/12/27 01:24:20 F3; loop: 9
Enter fullscreen mode Exit fullscreen mode

These were 2 simple ways to save log messages to log files. I hope you find it helpful.

Top comments (1)

Collapse
 
hamidalizadeh profile image
Hamid Alizadeh

Thanks 👍