0

I am trying to use a global variable defined in parent package in the internal package. There are no errors but none of the logs from internal package are printed. My assumption on order of init is: parent.go global variables and then init() from internal package; which seems right when tested with fmt.Println(). But looks like the call to ReplaceGlobals is dropped during compilation. Is there a way to fix it so that I can use global variable from internal package?

Here is the zap package I am using: zap. The API in question is discussed here. Here is the code snippet.

~/parent/parent.go

package main

import (
    "log"

    "go.uber.org/zap"
    "parent/internal"
)

var (
    logger = GetMyLogger()
    undo   = zap.ReplaceGlobals(logger.Desugar())
)

func GetMyLogger() *zap.SugaredLogger {
    xx, err := zap.NewProduction()
    if err != nil {
        log.Fatal("error")
    }
    sugar := xx.Sugar()
    return sugar
}

func main() {
    logger.Infof("logger in main")
    internal.New()
}

Then in ~/parent/internal/internal.go

package internal

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

var logger *zap.SugaredLogger

func init() {
    logger = zap.L().Sugar()
    logger.Infof("init() from internal: %v\n", logger)

    logger = zap.S()
    logger.Infof("init() from internal: %v\n", logger)
}

func New() {
    logger.Infof("New() from internal")
}
bladeWalker
  • 978
  • 1
  • 13
  • 30
  • 2
    Package are initialised as described here: https://golang.org/ref/spec#Package_initialization So internal.init is executed before undo = zap.ReplaceGlobals(logger.Desugar()). This cannot be changed. You cannot do this magic in internal.init but must move it to internal.New (e.g. by using a sync.Once) or redesign. Redesign is probably the better option. Package main should set up logging and inject the logger into all other code. – Volker Dec 14 '20 at 07:15
  • Also worth noting that there is no such thing as a "parent" package. While the directory structure is hierarchical, packages themselves are not. – Adrian Dec 14 '20 at 15:38

1 Answers1

2

Package initialization order is well defined, see Spec: Package initialization. Basically you can be sure that if you refer to a package, that package's initialization will be done first, recursively.

Since your internal package does not refer to your main, you have no guarantee if main is initialized before anything is executed from internal.

An easy solution in your case is to move the logger to your internal package, and have main refer / use that.

If you have more packages involved and you want to use the same logger from other packages, you may have a designated package holding the logger, and have everyone refer / use that.

icza
  • 389,944
  • 63
  • 907
  • 827