-4

I have a init() function defined in "config/config.go"

config.go

package config

import(
    log "github.com/sirupsen/logrus"
)

func init() {
    log.SetReportCaller(true)
}

I have another go file called auth.go in auth package

package auth

import(
    log "github.com/sirupsen/logrus"
)

func auth(username string, pwd string) {
     //some auth code
    log.Info("Auth success")
}

When log.Info() is called in auth.go the log prints as below

2018-11-09T16:38:27+05:30 auth/auth.go:36 level=info msg="Auth success"

What I am confused here is that, how "log" in auth.go is aware of the settings done in config.go. log.SetReportCaller() is in config.go but even when auth.go is logged it takes settings of log.SetReportCaller() done in config.go

Since log.SetReportCaller() is not set in auth.go expected log should be as below without showing line number of caller method.

2018-11-09T16:38:27+05:30 level=info msg="Auth success"

main.go

package main

import (
    "path/to/auth" 
    log "github.com/sirupsen/logrus"
    "net/http"
 )

func main() {
    r := server.Route()

    log.Info("Listening on 8080")

    http.Handle("/", r)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

auth/router.go

package auth

import (
    "github.com/gorilla/mux"
    "github.com/rs/cors"
    "net/http"
)

func Route() http.Handler {
    r := mux.NewRouter()
    // UI handlers
    r.HandleFunc("/", IndexPageHandler)
    r.HandleFunc("/login", LoginHandler).Methods("POST")
    handler := cors.Default().Handler(r)
    return 
}

auth/login.go

package auth

import (
    "fmt"
    "path/to/config"
    log "github.com/sirupsen/logrus"
    "net/http"
)
func LoginHandler(w http.ResponseWriter, r *http.Request) {

    username := r.FormValue("username")
    password := r.FormValue("password")

    status, userName, mail, _ := auth(username, password)
    //some code goes here

}

Kindly explain how this is happening

Aditya C S
  • 653
  • 1
  • 8
  • 17
  • can you show the file where your `main` function is. I am suspecting that file imports `config` package. – Emruz Hossain Nov 09 '18 at 11:27
  • question is updated with main.go code – Aditya C S Nov 09 '18 at 11:39
  • 2
    We can't see the dependency tree so I'm guessing `config` is a dependency somewhere here. if that is the case, it is not mystery why the `init()` function is called. – ssemilla Nov 09 '18 at 11:42
  • 1
    Does this answer your question? [When is the init() function run?](https://stackoverflow.com/questions/24790175/when-is-the-init-function-run) – Charlie Parker Feb 21 '22 at 23:04

2 Answers2

7

Check this diagram to understand how init() work: diagram

Initialization order are as follows,

  1. If a package imports other packages, the imported packages are initialised first.

  2. Package level variables are initialised then.

  3. init function of current package is called next. A package can have multiple init functions (either in a single file or distributed across multiple files) and they are called in the order in which they are presented to the compiler.

You will found an example explaining this here.

I am suspecting in dependency tree, there is a common ancestor file that import both config package and auth package.

Here is official doc on initialization: Package initialization

UPD: As you have added respective codes, let's visualize what is happening here. Look at the picture bellow,

enter image description here

What happening:

  1. Your main package start initialing. But it is has imported auth package. So to complete initialization, auth package must be initialized.
  2. auth package start initializing. But it has imported config package. So to complete initialization, config package must be initialized.
  3. config package complete initialization(log.SetReportCaller(true) is called).
  4. auth package complete initialization.
  5. main package complete initialization.
  6. main() function starts executing...
Emruz Hossain
  • 4,764
  • 18
  • 26
  • @peterSO thank you for pointing me there. I have updated my answer to include this information. – Emruz Hossain Nov 09 '18 at 13:29
  • I have added all the dependent code. Kindly refer the edited question and throw me some light on how dependency is working here. – Aditya C S Nov 10 '18 at 04:49
  • @AdityaCS I have updated my answer to explain what is happening. – Emruz Hossain Nov 10 '18 at 15:57
  • thanks for the explanation. Still my doubt is, is the "log" package imported and referenced in main.go the same as "log" imported and referenced in config.go. Both imports has different "log" reference right? How it still works? – Aditya C S Nov 10 '18 at 17:08
  • 2
    @Adrian has already answer this in his answer. "`SetReportCaller` sets a global variable in github.com/sirupsen/logrus" . All imports from different packages refers to same instance until you create new one using `logrus.New()` – Emruz Hossain Nov 10 '18 at 17:22
2

The behavior you're asking about actually has nothing to do with how init() functions work. SetReportCaller sets a global variable in github.com/sirupsen/logrus, not in your config or auth packages. So it doesn't matter where you call that function or where you call log.Info et al; the setting affects all calls to logrus regardless of call origin.

Adrian
  • 42,911
  • 6
  • 107
  • 99