DEV Community

Ronny Medina
Ronny Medina

Posted on • Updated on

Golang Logging Configuration with Zap: Practical Implementation Tips

Hi everybody, continuing from the previous post, which was a basic setup with Golang. In this part, we're setting up our logging in the app.

THE ORIGINAL POST HAS ADDITIONAL INFORMATION.

Installing the package zap

https://github.com/uber-go/zap

In our project, we need to install the zap package. To do this, put the following command in our terminal.

go get -u go.uber.org/zap
Enter fullscreen mode Exit fullscreen mode

If you're using Docker like me, you need to enter the container. So, if you're running the app in the background, execute this command.

docker exec -it demogolang bash
Enter fullscreen mode Exit fullscreen mode

To run the app in the background, use the command: docker-compose up -d.
The name 'demogolang' is declared inside the docker-compose.yml file.

Setting up the logging

Dockerfile

In our Dockerfile add 2 environment variables and created a folder to save the logs.

  • APP_LOG_LEVEL: The app log level could be debug or error. We use the debug level when we're in development and error when the app is in production mode. So, if you're in error mode when you print logs Info or Debug, these are not shown in the terminal. If you want to use more levels, you can edit the function to get the current level.

  • APP_LOG_FOLDER: This is the path where you place the log file. You can set whatever path you want.


ENV APP_LOG_LEVEL debug
ENV APP_LOG_FOLDER /tmp/logs/

RUN mkdir -p ${APP_LOG_FOLDER}
Enter fullscreen mode Exit fullscreen mode

Reading environment variables

Inside our app folder, I created a folder called config. Inside config, I put the file called envs.go.


package config

import "os"

var APP_ENV = os.Getenv("APP_ENV")
var IS_DEVELOP_MODE = APP_ENV == "develop"
var APP_LOG_LEVEL = os.Getenv("APP_LOG_LEVEL")
var APP_LOG_FOLDER = os.Getenv("APP_LOG_FOLDER")

Enter fullscreen mode Exit fullscreen mode

Logger file


package utils

import (
    "example/demogo/config"

    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)

var Logger *zap.SugaredLogger

func getLevelLogger(level string) zapcore.Level {
    if level == "debug" {
        return zap.DebugLevel
    }

    return zap.ErrorLevel
}

func init() {
    var err error
    level := zap.NewAtomicLevelAt(getLevelLogger(config.APP_LOG_LEVEL))
    encoder := zap.NewProductionEncoderConfig()

    zapConfig := zap.NewProductionConfig()
    zapConfig.EncoderConfig = encoder
    zapConfig.Level = level
    zapConfig.Development = config.IS_DEVELOP_MODE
    zapConfig.Encoding = "json"
    zapConfig.InitialFields = map[string]interface{}{"idtx": "999"}
    zapConfig.OutputPaths = []string{"stdout", config.APP_LOG_FOLDER + "app_log.log"}
    zapConfig.ErrorOutputPaths = []string{"stderr"}
    logger, err := zapConfig.Build()

    if err != nil {
        panic(err)
    }

    Logger = logger.Sugar()
}

Enter fullscreen mode Exit fullscreen mode

I created a global variable called Logger; this will be set when the package is initialized. The function getLevelLogger is used to get the current level from the environment variable.

The init function is automatically called before the main function.

  • encoder: Is the log format, how you want to apply the format.
  • InitialFields: The values ​​that you want to always be in the log.
  • OutputPaths: The output of the file.
  • ErrorOutputPaths: To print error log in the terminal.

Finally our main.go.


package main

import (
    "example/demogo/utils"
    "time"
)

func main() {
    defer utils.Logger.Sync()

    for {
        time.Sleep(5 * time.Second)
        utils.Logger.Infoln("hello world")
    }
}
Enter fullscreen mode Exit fullscreen mode

It's important to call defer utils.Logger.Sync() in the entry point of our app. Normally ensures that all buffered log messages are sent to their final destination if the application crashes.

docker-compose up -d --build

docker logs -f demogolang
Enter fullscreen mode Exit fullscreen mode

Top comments (0)