How to change logging format of log module in GO

How to change default log module logging format in Golang

Logging is a very important feature of an application in production, without which it's impossible to debug any problem that may occur in the application. Go log package is an incredible package that enables Go developers to log messages from their applications onto the console or inside a log file. It has a standard logger that can be accessed through helper functions such as Printf(), Println(), Fatalf(), Fatalln(), Panicf() and Panicln().

The logger writes to standard error and prints the date and time for each logged message. The log package comes with flags which define which text to prefix on each log entry by the logger. In this article we will cover the following subtopics about the log package.

Advertisement
  • How to change date and time format
  • How to add different log levels
  • Logging custom messages to the console
  • Logging custom messages into log file
  • Logging custom messages to both the console and into a log file

 

Getting started with the default log package

Let us have a first hand experience with the log package and advance to the other features that it has to offer to us. Create a new main.go file in your working directory and enter the below code. To get access to the log package in Go, you have to import it from the go standard library.

Example

package main
 
import "log"
 
func main() {
   log.Println("Hello, world!")
}

The above code prints out the results on the console with default logging format. Below is the result after executing the code. Output

2022/06/04 21:42:22 Hello, world!

 

Default supported flags with log module

The log package comes with different flags that can be used to format log messages.

  • Ldate  :to the local timezone e.g 2022/06/04
  • Ltime :to the local time zone e.g 01:23:23
  • Lmicroseconds : Microseconds resolution: 01:23:23.123123 assumes Ltime
  • Llongfile: Full file name and line number : /home/go/logger/main.go:25
  • Lshortfile: Final file name element and line number, it overrides Llongfile : main.go:25
  • LUTC : Used if Ldate and Ltime is set, used UTC rather than the local the zone
  • Lmsgprefix: Used to move the “prefix” from the beginning of the line to before the message
  • LstdFlags: Initial values for the standard logger

Example

package main

import "log"

const (
	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
	Ltime                         // the time in the local time zone: 01:23:23
	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
	Llongfile                     // full file name and line number: /a/b/c/d.go:23
	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
	Lmsgprefix                    // move the "prefix" from the beginning of the line to before the message
	LstdFlags     = Ldate | Ltime // initial values for the standard logger
)

func main() {
	// Log to the console
	log.Println("Default lof message")
	// Set Date to the log : user log.SetFlag()
	log.SetFlags(log.Ldate)
	// Log to the console with date prepended
	log.Println("Log to the console with date prepended")
	// Set Time to the log
	log.SetFlags(log.Ltime)
	// Log to the console with date prepended
	log.Println("Log to the console with time prepended")
	// Set Date and Time to the log
	log.SetFlags(log.Ldate | log.Ltime)
	// Log to the console with date prepended
	log.Println("Log to the console with date and time prepended")
	// Set filename to the log
	log.SetFlags(log.Lshortfile)
	// Log to the console with filename prepended
	log.Println("Log to the console with filename prepended")
	// Set date, time and filename to the log
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	// Log to the console with date, time and filename prepended
	log.Println("Log to the console with date, time and filename prepended")
}

Output

Advertisement
2022/06/08 06:45:47 Default lof message
2022/06/08 Log to the console with date prepended
06:45:47 Log to the console with time prepended
2022/06/08 06:45:47 Log to the console with date and time prepended
main.go:34: Log to the console with filename prepended
2022/06/08 06:45:47 main.go:38: Log to the console with date, time and filename prepended

 

Modify date and time format of log module

It's possible to change date and time logging formats for the prefix for each log message that gets printed out. Go logger has a SetPrefix() method which sets the output prefix for the standard logger.

To format the date and time, we need to define our date and time format that will be prepended in our log messages.

Example

package main
 
import (
   "log"
   "time"
)
 
const (
   // YYYY-MM-DD: 2022-03-23
   YYYYMMDD = "2006-01-02"
   // 24h hh:mm:ss: 14:23:20
   HHMMSS24h = "15:04:05"
   // 12h hh:mm:ss: 2:23:20 PM
   HHMMSS12h = "3:04:05 PM"
   // text date: March 23, 2022
   TextDate = "January 2, 2006"
   // text date with weekday: Wednesday, March 23, 2022
   TextDateWithWeekday = "Monday, January 2, 2006"
   // abbreviated text date: Mar 23 Wed
   AbbrTextDate = "Jan 2 Mon"
)
 
func main() {
   // Add flags: prepend filename
   log.SetFlags(log.Lshortfile)
   // Add custom date
   log.SetPrefix(time.Now().UTC().Format(YYYYMMDD) + ": ")
   log.Println("Log message with date formatted")
   // Add custom time
   log.SetPrefix(time.Now().UTC().Format(HHMMSS12h) + ": ")
   log.Println("Log message with time formatted")
   // Add custom date and time
   log.SetPrefix(time.Now().UTC().Format(YYYYMMDD+" "+HHMMSS12h) + ": ")
   log.Println("Log message with time formatted")
}

Output

2022-06-08: main.go:28: Log message with date formatted
4:03:48 AM: main.go:31: Log message with time formatted
2022-06-08 4:03:48 AM: main.go:34: Log message with time formatted

 

Add different log levels to log module

The Log package can also be used to change logging format to define custom log levels that can be categorized into:

  • Warning
  • Error
  • Info
  • Debug
  • Fatal

 

Method-1: Using log.SetPrefix() Method

Adding log level is achieved using the SetPrefix() method.

Example

package main
 
import (
   "log"
   "time"
)
 
const (
   // YYYY-MM-DD: 2022-03-23
   YYYYMMDD = "2006-01-02"
   // 24h hh:mm:ss: 14:23:20
   HHMMSS24h = "15:04:05"
   // 12h hh:mm:ss: 2:23:20 PM
   HHMMSS12h = "3:04:05 PM"
   // text date: March 23, 2022
   TextDate = "January 2, 2006"
   // text date with weekday: Wednesday, March 23, 2022
   TextDateWithWeekday = "Monday, January 2, 2006"
   // abbreviated text date: Mar 23 Wed
   AbbrTextDate = "Jan 2 Mon"
)
 
func main() {
   // Define flags to be used
   flags := log.Lshortfile
   // Log without log level
   datetime := time.Now().UTC().Format(YYYYMMDD+" "+HHMMSS12h) + ": "
   log.Println("Without log levels")
   // Set log level SetPrefix
   log.SetFlags(flags)
   // INFO log level
   log.SetPrefix("INFO: " + datetime)
   log.Println("INFO level")
   // WARNING log level
   log.SetPrefix("WARN: " + datetime)
   log.Println("WARN level")
   // DEBUG log level
   log.SetPrefix("DEBUG: " + datetime)
   log.Println("DEBUG level")
   // ERROR log level
   log.SetPrefix("ERROR: " + datetime)
   log.Println("ERROR level")
   // FATA log level
   log.SetPrefix("FATA: " + datetime)
   log.Println("FATA level")
}

Output

2022/06/08 07:37:31 Without log levels
INFO: 2022-06-08 4:37:31 AM: main.go:33: INFO level
WARN: 2022-06-08 4:37:31 AM: main.go:36: WARN level
DEBUG: 2022-06-08 4:37:31 AM: main.go:39: DEBUG level
ERROR: 2022-06-08 4:37:31 AM: main.go:42: ERROR level
FATAL: 2022-06-08 4:37:31 AM: main.go:45: FATAL level

 

Method-2: Using log.New() Method

Log levels can also be defined using New()function that takes three arguments, namely out, prefix and flag.

  1. Out: This is any type that implements the io.Writer interface e.g os.Stdout
  2. Prefix : This a simple text that is prepended at the beginning of each log message.
  3. Flag : These are flags that define which text to prefix logs generated by the logger

Example

package main
 
import (
   "log"
   "os"
   "time"
)
 
const (
   // YYYY-MM-DD: 2022-03-23
   YYYYMMDD = "2006-01-02"
   // 24h hh:mm:ss: 14:23:20
   HHMMSS24h = "15:04:05"
   // 12h hh:mm:ss: 2:23:20 PM
   HHMMSS12h = "3:04:05 PM"
   // text date: March 23, 2022
   TextDate = "January 2, 2006"
   // text date with weekday: Wednesday, March 23, 2022
   TextDateWithWeekday = "Monday, January 2, 2006"
   // abbreviated text date: Mar 23 Wed
   AbbrTextDate = "Jan 2 Mon"
)
 
func main() {
   // Defines flags
   flags := log.Lshortfile
   // Create a new logger
   logger := log.New(os.Stdout, "", flags)
   // Define date and time format
   datetime := time.Now().UTC().Format(YYYYMMDD+" "+HHMMSS12h) + ": "
   // Set INFO prefix
   logger.SetPrefix("INFO: " + datetime)
   logger.Println("INFO level")
   // Set WARNING prefix
   logger.SetPrefix("WARN: " + datetime)
   logger.Println("WARN level")
   // Set ERROR prefix
   logger.SetPrefix("ERROR: " + datetime)
   logger.Println("ERROR level")
   // Set DEBUG prefix
   logger.SetPrefix("DEBUG: " + datetime)
   logger.Println("DEBUG level")
   // Set FATAL prefix
   logger.SetPrefix("FATAL: " + datetime)
   logger.Println("FATAL level")
 
}

Output

INFO: 2022-06-08 4:36:42 AM: main.go:33: INFO level
WARN: 2022-06-08 4:36:42 AM: main.go:36: WARN level
ERROR: 2022-06-08 4:36:42 AM: main.go:39: ERROR level
DEBUG: 2022-06-08 4:36:42 AM: main.go:42: DEBUG level
FATAL: 2022-06-08 4:36:42 AM: main.go:45: FATAL level

 

Print messages to the console with custom logging format

By default, the log package prints messages on the console. It is possible to  define the standard output explicitly if need be. Using the New()

Advertisement

function in the log package we can define where we want to print our messages.

Example

package main

import (
	"log"
	"time"
)

const (
	// YYYY-MM-DD: 2022-03-23
	YYYYMMDD = "2006-01-02"
	// 24h hh:mm:ss: 14:23:20
	HHMMSS24h = "15:04:05"
	// 12h hh:mm:ss: 2:23:20 PM
	HHMMSS12h = "3:04:05 PM"
	// text date: March 23, 2022
	TextDate = "January 2, 2006"
	// text date with weekday: Wednesday, March 23, 2022
	TextDateWithWeekday = "Monday, January 2, 2006"
	// abbreviated text date: Mar 23 Wed
	AbbrTextDate = "Jan 2 Mon"
)

func main() {
	// Defines flags
	flags := log.Lshortfile
	// Define date and time format
	datetime := time.Now().UTC().Format(YYYYMMDD+" "+HHMMSS12h) + ": "
	// Set Flags
	log.SetFlags(flags)
	// Set INFO prefix
	log.SetPrefix("INFO: " + datetime)
	log.Println("Log to console")
}

Output

INFO: 2022-06-08 5:14:41 AM: main.go:32: Log to console

 

Log messages into log file with custom logging format

Logging messages into a log file involves creating a file to write logs into . The log file will store all the log messages instead of logging in the console.

Example

package main
 
import (
   "log"
   "os"
   "time"
)
 
const (
   // YYYY-MM-DD: 2022-03-23
   YYYYMMDD = "2006-01-02"
   // 24h hh:mm:ss: 14:23:20
   HHMMSS24h = "15:04:05"
   // 12h hh:mm:ss: 2:23:20 PM
   HHMMSS12h = "3:04:05 PM"
   // text date: March 23, 2022
   TextDate = "January 2, 2006"
   // text date with weekday: Wednesday, March 23, 2022
   TextDateWithWeekday = "Monday, January 2, 2006"
   // abbreviated text date: Mar 23 Wed
   AbbrTextDate = "Jan 2 Mon"
)
 
func main() {
   // Defines flags
   flags := log.Lshortfile
   // Define date and time format
   datetime := time.Now().UTC().Format(YYYYMMDD+" "+HHMMSS12h) + ": "
   // Set INFO prefix
 
   // Open a file if it exist or create one if file does not exist
   file, err := os.OpenFile("logs.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
   if err != nil {
       // Set file as the destination to log messages with log level "FATAL"
       logger := log.New(file, "", flags)
       logger.SetPrefix("FATAL: " + datetime)
       // Log a fatal message into the log file
       logger.Println(err)
   }
 
   defer file.Close()
   logger := log.New(file, "", flags)
   logger.SetPrefix("INFO : " + datetime)
   // Log a fatal message into the log file
   logger.Println("Log custom date and time in a logs.log file")
 
}

Output

Advertisement
INFO : 2022-06-08 4:46:30 AM: main.go:45: Log custom date and time in a logs.log file

 

Log messages with custom logging format to both the console and into a log file

Logging on the console and file can be achieved with the call to io.MultiWriter()that takes two arguments, os.Stdout()and the log file. The write destination is defined by theSetOutput() .

Example

package main
 
import (
   "io"
   "log"
   "os"
   "time"
)
 
const (
   // YYYY-MM-DD: 2022-03-23
   YYYYMMDD = "2006-01-02"
   // 24h hh:mm:ss: 14:23:20
   HHMMSS24h = "15:04:05"
   // 12h hh:mm:ss: 2:23:20 PM
   HHMMSS12h = "3:04:05 PM"
   // text date: March 23, 2022
   TextDate = "January 2, 2006"
   // text date with weekday: Wednesday, March 23, 2022
   TextDateWithWeekday = "Monday, January 2, 2006"
   // abbreviated text date: Mar 23 Wed
   AbbrTextDate = "Jan 2 Mon"
)
 
func main() {
   // Defines flags
   flags := log.Lshortfile
   // Define date and time format
   datetime := time.Now().UTC().Format(YYYYMMDD+" "+HHMMSS12h) + ": "
   // Set INFO prefix
 
   // Open a file if it exist or create one if file does not exist
   file, err := os.OpenFile("logs.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
   if err != nil {
       // Set file as the destination to log messages with log level "FATAL"
       logger := log.New(file, "", flags)
       logger.SetPrefix("FATAL: " + datetime)
       // Log a fatal message into the log file
       logger.Println(err)
   }
 
   defer file.Close()
   logger := log.New(file, "", flags)
   logger.SetPrefix("INFO : " + datetime)
   // Log a fatal message into the log file
   mw := io.MultiWriter(os.Stdout, file)
   logger.SetOutput(mw)
   logger.Println("Log to console and file")
}

Output

INFO : 2022-06-08 4:52:36 AM: main.go:48: Log to console and file

 

Summary

Applications running in production need to log messages so that it is easy to keep track of what is happening with the application. When applications in production run with logging messages , it will be almost impossible to debug issues or errors that come up. For these reasons and  many others, go engineers added the log package to the standard library that can keep track of log messages and categorize them into different levels such as debug, error, warning, fatal and info. This can be achieved using multiple third party modules but for any one who wants to stick to default log module and still be able to customized logging format for date and time or adding log levels, this article can help them.

 

References

https://pkg.go.dev/log#New
https://www.ardanlabs.com/blog/2013/11/using-log-package-in-go.html

 

Categories GO

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X