9

I was able to get the full path of the current directory, Now I would like to create a function that will read or get the filename where the code is executed. I am able to get the filename but it is return the original filename where the code is written :

func GetFileName() string {
    _, fpath, _, ok := runtime.Caller(0)
    if !ok {
        err := errors.New("failed to get filename")
        panic(err)
    }
    filename := filepath.Base(fpath)
    // remove extension
    filename = removeExtension(filename)
    return filename + ".log"
}

What I want to do is getting the current fileName where the code is executed like :

I created app.go :

package my

function getCurrentFileName() string {
    // some code here that will return the filename where this code is executed.
}

and then when I call getCurrentFileName() in a different file like hello.go in a different location. it will return hello.go.

I have been stuck here for a while and looking for an answer.

Gujarat Santana
  • 9,854
  • 17
  • 53
  • 75

2 Answers2

18

Basically this is what you tell / pass to runtime.Caller(): the number of stack entries to skip before returning an entry.

If you pass 0 as in your code, that means return the stack entry where runtime.Caller() is called (where you called runtime.Caller()). Passing 1 will skip your function, and return the function that called your function:

pc, file, line, ok := runtime.Caller(1)
if ok {
    fmt.Printf("Called from %s, line #%d, func: %v\n",
        file, line, runtime.FuncForPC(pc).Name())
}

Example calling a function that contains this (subplay.A() in my example):

 7   func main() {
 8      // Comment line
 9      subplay.A()
10   }

Output:

Called from /home/icza/gows/src/play/play.go, line #9, func: main.main

We see that the code prints that play.go called our function at line #9, from the function main() of the main package.

icza
  • 389,944
  • 63
  • 907
  • 827
1

This helper function can give those information:

func Here(skip ...int) (string, string, int, error) {
    sk := 1
    if len(skip) > 0 && skip[0] > 1 {
        sk = skip[0]
    }
    var pc uintptr
    var ok bool
    pc, fileName, fileLine, ok := runtime.Caller(sk)
    if !ok {
        return "", "", 0, fmt.Errorf("N/A")
    }
    fn := runtime.FuncForPC(pc)
    name := fn.Name()
    ix := strings.LastIndex(name, ".")
    if ix > 0 && (ix+1) < len(name) {
        name = name[ix+1:]
    }
    funcName := name
    nd, nf := filepath.Split(fileName)
    fileName = filepath.Join(filepath.Base(nd), nf)
    return funcName, fileName, fileLine, nil
}

The skip parameter is the number of caller frames that we need to go up (the chain of callers).

Kaveh Shahbazian
  • 13,088
  • 13
  • 80
  • 139