Skip to content

NimTechnology

Trình bày các công nghệ CLOUD một cách dễ hiểu.

  • Kubernetes & Container
    • Docker
    • Kubernetes
      • Ingress
      • Pod
    • Helm Chart
    • OAuth2 Proxy
    • Isito-EnvoyFilter
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Vault
    • Longhorn – Storage
    • VictoriaMetrics
    • MetalLB
    • Kong Gateway
  • CI/CD
    • ArgoCD
    • ArgoWorkflows
    • Argo Events
    • Spinnaker
    • Jenkins
    • Harbor
    • TeamCity
    • Git
      • Bitbucket
  • Coding
    • DevSecOps
    • Terraform
      • GCP – Google Cloud
      • AWS – Amazon Web Service
      • Azure Cloud
    • Golang
    • Laravel
    • Python
    • Jquery & JavaScript
    • Selenium
  • Log, Monitor & Tracing
    • DataDog
    • Prometheus
    • Grafana
    • ELK
      • Kibana
      • Logstash
  • BareMetal
    • NextCloud
  • Toggle search form

[Golang] Zap log in Golang

Posted on January 31, 2024February 12, 2025 By nim No Comments on [Golang] Zap log in Golang

https://betterstack.com/community/guides/logging/go/zap/

Đầu tiên chúng ta sẽ bắt đầu với code demo đơn giản:

package main

import (
    "go.uber.org/zap"
)

func main() {
    logger := zap.Must(zap.NewProduction())

    defer logger.Sync()

    logger.Info("Hello from Zap logger!")
}

you must create a zap.Logger instance before you can begin to write logs. The NewProduction() method returns a Logger configured to log to the standard error in JSON format, and its minimum log level is set to INFO

và output bạn nhận được là:

{"level":"info","ts":1684092708.7246346,"caller":"zap/main.go:12","msg":"Hello from Zap logger!"}

Mình sẽ giải thích chút về output log trên:

  1. {"level":"info":
    • level: This indicates the severity level of the log message. Common levels include debug, info, warn, error, etc. In this case, info suggests that the message is informational.
    • This is useful for filtering logs. For example, in a production environment, you might only want to see warn and error level messages.
  2. "ts":1684092708.7246346:
    • ts: Stands for timestamp. It represents the time at which the log message was generated.
    • The number 1684092708.7246346 is a Unix timestamp in seconds with fractional part for millisecond precision. It denotes the specific time in seconds since the Unix epoch (January 1, 1970). This precise timestamp can be crucial for debugging, especially when looking at the sequence of events.
  3. "caller":"zap/main.go:12":
    • caller: This part of the log indicates where in the code the log message was generated.
    • "zap/main.go:12" means the log message was generated in the main.go file (presumably of the zap package or project) on line 12. This information is very helpful in larger projects for quickly locating the source of a log message.
  4. "msg":"Hello from Zap logger!":
    • msg: This is the actual log message.
    • The message "Hello from Zap logger!" is a human-readable string that provides information about what the log is about. In this case, it seems to be a simple test or demonstration message.

You can also utilize the NewDevelopment() preset to create a Logger that is more optimized for use in development environments. This means logging at the DEBUG level and using a more human-friendly format:
Bạn sẽ replace 1 chút:

logger := zap.Must(zap.NewDevelopment())

và output nó sẽ như thế này:

2023-05-14T20:42:39.137+0100    INFO    zap/main.go:12  Hello from Zap logger!

Contents

Toggle
  • Setting up a global logger
  • Examining Zap’s logging API
    • the low-level Logger type
    • The second higher-level API is the SugaredLogger
  • Build logger

Setting up a global logger

Chúng ta sẽ luôn muốn sử dụng init fuction để create Zap Log.

package main

import (
    "go.uber.org/zap"
)

func init() {
    zap.ReplaceGlobals(zap.Must(zap.NewProduction()))
}

func main() {
    zap.L().Info("Hello from Zap!")
}

This method replaces the global logger accessible through zap.L() with a functional Logger instance so that you can use it directly just by importing the zap package into your file.

Examining Zap’s logging API

Zap provides two primary APIs for logging:
– The first is the low-level Logger type that provides a structured way to log messages
– The SugaredLogger type which represents a more laid-back approach to logging

the low-level Logger type

func main() {
    logger := zap.Must(zap.NewProduction())

    defer logger.Sync()

    logger.Info("User logged in",
        zap.String("username", "johndoe"),
        zap.Int("userid", 123456),
        zap.String("provider", "google"),
    )
}

output:

{"level":"info","ts":1684094903.7353888,"caller":"zap/main.go:17","msg":"User logged in","username":"johndoe","userid":123456,"provider":"google"}

The second higher-level API is the SugaredLogger

func main() {
    logger := zap.Must(zap.NewProduction())

    defer logger.Sync()

    sugar := logger.Sugar()

    sugar.Info("Hello from Zap logger!")
    sugar.Infoln(
        "Hello from Zap logger!",
    )
    sugar.Infof(
        "Hello from Zap logger! The time is %s",
        time.Now().Format("03:04 AM"),
    )

    sugar.Infow("User logged in",
        "username", "johndoe",
        "userid", 123456,
        zap.String("provider", "google"),
    )
}

output:

{"level":"info","ts":1684147807.960761,"caller":"zap/main.go:17","msg":"Hello from Zap logger!"}
{"level":"info","ts":1684147807.960845,"caller":"zap/main.go:18","msg":"Hello from Zap logger!"}
{"level":"info","ts":1684147807.960909,"caller":"zap/main.go:21","msg":"Hello from Zap logger! The time is 11:50 AM"}
{"level":"info","ts":1684148355.2692218,"caller":"zap/main.go:25","msg":"User logged in","username":"johndoe","userid":123456,"provider":"google"}

Structured Logger: sử dụng Zap’s structured logger. API dài dòng hơn nhưng cũng cấp strongly-typed, structured logging (cấu trúc). mỗi log entry (mỗi khi bạn khai báo log) là một message đã được cấu trúc với các trường được defined rõ ràng.

Pros:

  1. Structured Logging: The fields are explicitly defined, which makes it easier for log parsing and indexing tools to process and query logs.
  2. Performance: Typically faster than the Sugared logger because it avoids reflection and type conversions.
  3. Type Safety: Helps catch errors at compile time, as each field requires a specific type.

Cons:

  1. Verbosity: More verbose to write, as each field needs to be explicitly mentioned.
  2. Less Flexible: Doesn’t support formatting log messages with printf-style syntax.

Sugared Logger: sử dụng Zap’s Sugared Logger. Cách thì nó sẽ link động hơn, giảm sử dài dòng, đơn giản hơn, và friendly hơn với developer.

Pros:

  1. Ease of Use: More straightforward syntax, especially for developers familiar with standard Go loggers.
  2. Flexibility: Supports printf-style formatting, which can be more intuitive for constructing messages.
  3. Compatibility: Makes it easier to migrate existing code that uses standard Go logging to Zap.

Cons:

  1. Performance: Slightly slower than the structured logger due to the use of reflection and runtime type assertions.
  2. Less Structured: Printf-style and infow-style logs are less structured, which could be a downside for parsing and indexing.

Build logger

Mục tiêu của mình là sẽ build logger và chúng ta có thể dễ dàng ghi log ở bất cứ đâu trong project của chúng ta.

package logger

import (
    "context"
    "fmt"
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "gopkg.in/natefinch/lumberjack.v2"
    "log"
    "os"
    "runtime/debug"
    "sync"
)

// refer to: https://betterstack.com/community/guides/logging/go/zap/#final-thoughts
//           https://github.com/betterstack-community/go-logging/blob/zap/logger/logger.go

type ctxKey struct{}

var once sync.Once
var Log *zap.Logger

// InitLogger replaces the init function for manual initialization
func InitLogger() {
    once.Do(func() {
        stdout := zapcore.AddSync(os.Stdout)
        file := zapcore.AddSync(&lumberjack.Logger{
            Filename:   "logs/app.log",
            MaxSize:    5, // megabytes
            MaxBackups: 10,
            MaxAge:     14, // days
            Compress:   true,
        })

        level := zap.InfoLevel
        levelEnv := os.Getenv("LOG_LEVEL")
        if levelEnv != "" {
            levelFromEnv, err := zapcore.ParseLevel(levelEnv)
            if err != nil {
                log.Println(fmt.Errorf("invalid LOG_LEVEL '%s', defaulting to INFO: %w", levelEnv, err))
            } else {
                level = levelFromEnv
            }
        }

        logLevel := zap.NewAtomicLevelAt(level)
        encoderCfg := zap.NewProductionEncoderConfig()
        encoderCfg.TimeKey = "timestamp"
        encoderCfg.EncodeTime = zapcore.ISO8601TimeEncoder
        encoderCfg.CallerKey = "caller"

        consoleEncoder := zapcore.NewConsoleEncoder(encoderCfg)
        fileEncoder := zapcore.NewJSONEncoder(encoderCfg)

        var gitRevision string
        buildInfo, ok := debug.ReadBuildInfo()
        if ok {
            for _, v := range buildInfo.Settings {
                if v.Key == "vcs.revision" {
                    gitRevision = v.Value
                    break
                }
            }
        }

        core := zapcore.NewTee(
            zapcore.NewCore(consoleEncoder, stdout, logLevel),
            zapcore.NewCore(fileEncoder, file, logLevel).With(
                []zapcore.Field{
                    zap.String("git_revision", gitRevision),
                    zap.String("go_version", buildInfo.GoVersion),
                },
            ),
        )

        Log = zap.New(core, zap.AddCaller())
    })
}

func Info(msg string, fields ...zap.Field) {
    Log.WithOptions(zap.AddCallerSkip(1)).Info(msg, fields...)
}

func Error(msg string, fields ...zap.Field) {
    Log.WithOptions(zap.AddCallerSkip(1)).Error(msg, fields...)
}

func Debug(msg string, fields ...zap.Field) {
    Log.WithOptions(zap.AddCallerSkip(1)).Debug(msg, fields...)
}

func Warn(msg string, fields ...zap.Field) {
    Log.WithOptions(zap.AddCallerSkip(1)).Warn(msg, fields...)
}

// Add other logging level methods as needed (e.g., Debug, Warn)

// FromCtx returns the Logger associated with the ctx.
// If no logger is associated, the default logger is returned.
func FromCtx(ctx context.Context) *zap.Logger {
    if l, ok := ctx.Value(ctxKey{}).(*zap.Logger); ok {
        return l
    }
    return Log
}

// WithCtx returns a copy of ctx with the Logger attached.
func WithCtx(ctx context.Context, l *zap.Logger) context.Context {
    return context.WithValue(ctx, ctxKey{}, l)
}

Tiếp đến ở hàm main thì bạn sẽ cần gọi InitLogger lên 1 lần

package main

import (
    "learn_zap_log/logger"
    "os"
)

func init() {
    // Set log level to DEBUG
    os.Setenv("LOG_LEVEL", "DEBUG")
    logger.InitLogger()
}

func main() {
    Hoge()
}

mình test việc gọi log trong file hope.go

package main

import (
    "go.uber.org/zap"
    "learn_zap_log/logger"
)

func Hoge() {
    url := "http://example.com"
    logger.Info("This is a function in some other package "+url, zap.String("key", "value"), zap.Int("count", 42))
    logger.Debug("This is a debug message")
    logger.Warn("This is a warning message")
    logger.Error("This is an error message")
}

Để sử dụng đc log debug thì bạn phải thêm biến môi trường là LOG_LEVEL = DEBUG
Nó tạo ra folder là logs và lưu file ở đó.

Golang

Post navigation

Previous Post: [Istio/OAuth2-Proxy] Authenticate applications on Kubernetes: Okta(OIDC), Istio, and OAuth2-Proxy integration.
Next Post: [Kasm] Stream your workspace directly to your web browser…on any device and from any location.

More Related Articles

[Golang] In-Memory Cache or Local Cache with Golang. Golang
[Golang] Ứng dụng Framework echo vào trong golang. Golang
[Golang] Approach Channel in Calling another function with Golang Golang
[Golang] Create multiple CRON functions by looping through a list Golang
[Golang / EKS] Accessing AWS EKS with Go: A Comprehensive Guide to Interacting with Kubernetes APIs AWS - Amazon Web Service
[GRPC/Golang] Bắt đầu Project Grpc với golang trên Windows. Coding

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Tham Gia Group DevOps nhé!
Để Nim có nhiều động lực ra nhiều bài viết.
Để nhận được những thông báo mới nhất.

Recent Posts

  • [Laravel] Laravel Helpful June 26, 2025
  • [VScode] Hướng dẫn điều chỉnh font cho terminal June 20, 2025
  • [WordPress] Hướng dấn gửi mail trên WordPress thông qua gmail. June 15, 2025
  • [Bitbucket] Git Clone/Pull/Push with Bitbucket through API Token. June 12, 2025
  • [Teamcity] How to transfer the value from pipeline A to pipeline B June 9, 2025

Archives

  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021

Categories

  • BareMetal
    • NextCloud
  • CI/CD
    • Argo Events
    • ArgoCD
    • ArgoWorkflows
    • Git
      • Bitbucket
    • Harbor
    • Jenkins
    • Spinnaker
    • TeamCity
  • Coding
    • DevSecOps
    • Golang
    • Jquery & JavaScript
    • Laravel
    • NextJS 14 & ReactJS & Type Script
    • Python
    • Selenium
    • Terraform
      • AWS – Amazon Web Service
      • Azure Cloud
      • GCP – Google Cloud
  • Kubernetes & Container
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Docker
    • Helm Chart
    • Isito-EnvoyFilter
    • Kong Gateway
    • Kubernetes
      • Ingress
      • Pod
    • Longhorn – Storage
    • MetalLB
    • OAuth2 Proxy
    • Vault
    • VictoriaMetrics
  • Log, Monitor & Tracing
    • DataDog
    • ELK
      • Kibana
      • Logstash
    • Fluent
    • Grafana
    • Prometheus
  • Uncategorized
  • Admin

Copyright © 2025 NimTechnology.