I have a function which returns new error with caller file path (fn from runtime.Caller(1))
But I want to get relative path (relative to the dir in which go build, also the directory of main.go)
How to achieve this gracefully?
func NewError(e interface{}) error {
if e != nil {
_, fn, line, _ := runtime.Caller(1)
return fmt.Errorf("[error] %s:%d %v", fn, line, e)
}
return nil
}
2 Likes
Use os.Args
?
It has all the arguments that starts the go program, including the go binary path (os.Args[0]
).
1 Like
go binary path can change if you move the binary file to somewhere else
but the fn returned by runtime.Caller will not change
2 Likes
In a file relative.go define the following
package main
import (
"runtime"
"filepath"
)
func init() {
initRelative()
}
var prefixPath string
func initRelative() {
_, fileName, _, _ := runtime.Caller(0)
prefixPath = filepath.Dir(fileName)
}
func relative(path string) return {
if filepath.HasPrefix(path, prefixPath) {
return path[len(prefixPath):]
}
return path
}
This code assumes that the file relative.go is stored in the build root directory. You may need to modify the code to match your specific use case.
2 Likes
Thanks!
utils/relative.go
package utils
import (
"path/filepath"
"runtime"
"strings"
)
func init() {
initRelative()
}
var prefixPath string
func initRelative() {
_, fileName, _, _ := runtime.Caller(0)
prefixPath = filepath.ToSlash(filepath.Dir(filepath.Dir(fileName))) + "/"
}
func relative(path string) string {
return strings.TrimPrefix(filepath.ToSlash(path), prefixPath)
}
utils/functions.go
package utils
import (
"fmt"
"os"
"runtime"
)
// NewError :
func NewError(e interface{}) error {
if e != nil {
_, fn, line, _ := runtime.Caller(1)
return fmt.Errorf("[error] %s:%d %v", relative(fn), line, e)
}
return nil
}
update:
use filepath.ToSlash (cross pratform)
2 Likes
That’s better than my code. But relative.go
is in the utils package and filepath.Dir(filepath.Dir(fileName))
removes only relative.go
at end of fileName
. So prefixPath ends with “…/utils/”. As a consequence, paths not starting with “…/utils/” won’t be changed into a relative path.
To fix that I suggest you change your initRelative
function into the following.
func initRelative() {
_, fileName, _, _ := runtime.Caller(0)
prefixPath = fileName[:len(fileName)-len("utils/relative.go")]
}
This should set prefixPath
to the root path of your project.
2 Likes
Christophe_Meessen:
initRelative
It will be the directory of main.go using filepath.Dir twice…
1 Like
system
(system)
Closed
January 8, 2020, 12:39pm
8
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.