Saving log messages to a custom log file in Golang
Tags: go, logging
Published: 2020-12-25 21:27:24

## 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.

```go
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")
}
```

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:

```sh
$ tail -f /var/log/syslog
```
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
```

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

```go
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")
}
```
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
```
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:

```go
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")
}
```
Now run the application and check the result:

```sh
$ tail -f /tmp/myapp_log
2020/12/23 01:29:25 logging.go:29: Logging to custom file
```
### 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:
```go
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()

}
```

If you run the code the output will be something like this:
```bash
$ 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
```

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