In the previous post, we already discussed some examples of working with logrus in Golang. In today’s post, we will show you how to include the function name, filename, and line number using logrus. Logrus is a structured logger for Go and is compatible with the standard log package. The standard logging package is limited in some ways, leading to the development of other logging packages like Logrus, oklog and zerolog. Logging is an important aspect of modern programming and is used to :
- Log Errors or Warning messages that developers need to know about.
- Log performance metrics, memory consumption, etc
- Log Debug messages to help developers troubleshoot their software.
Example 1: Set the option SetReportCaller to true
At the end of 2018, this option is available within the library itself.
If you want to log the function name, filename, and line number, simply
set the SetReportCaller to true. Here is an example of how to print
the function name, filename, and line number using logrus:
func SetReportCaller(include bool): SetReportCaller sets whether the
standard logger will include the calling method as a field.
package main
import (
"time"
log "github.com/sirupsen/logrus"
)
func main() {
// set this to true to print the function name, file name and line number
log.SetReportCaller(true)
log.Println("Hello Golinux cloud members!")
log.Println("Now is:", time.Now())
}
Output:
time="2023-01-03T23:02:34+07:00" level=info msg="Hello Golinux cloud members!" func=main.main file="C:/Users/nguye/OneDrive/Desktop/golang/main/logrus.go:13"
time="2023-01-03T23:02:34+07:00" level=info msg="Now is: 2023-01-03 23:02:34.9017448 +0700 +07 m=+0.002107101" func=main.main file="C:/Users/nguye/OneDrive/Desktop/golang/main/logrus.go:14"
Example 2: Customize the logrus.JSONFormatter format
In logrus, the built-in logging formatters are:
logrus.TextFormatter. Logs the event in colors if stdout is a tty,
otherwise without colors.
ForceColorsfield totrue. To force no colored output even if
there is a TTY set theDisableColorsfield totrue. For Windows,
seegithub.com/mattn/go-colorable.
When colors are enabled, levels are truncated to 4 characters by
default. To disable truncation set theDisableLevelTruncationfield
totrue.
When outputting to a TTY, it’s often helpful to visually scan down a
column where all the levels are the same width. Setting
thePadLevelTextfield totrueenables this behavior, by adding
padding to the level text.
All options are listed in thegenerated docs.
logrus.JSONFormatter. Logs fields as JSON.
All options are listed in thegenerated docs.
In this example, we will set the log.SetReportCaller to true and then
use the CallerPrettyfier() function to customize the
logrus.JSONFormatter
CallerPrettyfier(): CallerPrettyfier can be set by the user to modify
the content of the function and file keys in the JSON data when
ReportCaller is activated. If any of the returned values is an empty
string the corresponding key will be removed from JSON fields.
Let’s take a look at the example below to see how we can display the function name, file name, and line number in a customized format:
package main
import (
"path"
"runtime"
"strconv"
"time"
log "github.com/sirupsen/logrus"
)
func main() {
log.SetReportCaller(true)
//customize the formatter
log.SetFormatter(&log.JSONFormatter{
CallerPrettyfier: func(frame *runtime.Frame) (function string, file string) {
fileName := path.Base(frame.File) + ", lineNumber:" + strconv.Itoa(frame.Line)
return frame.Function, fileName
},
})
log.Println("Hello Golinux cloud members!")
log.Println("Now is:", time.Now())
}
Output:
{"file":"logrus.go, lineNumber:22","func":"main.main","level":"info","msg":"Hello Golinux cloud members!","time":"2023-01-03T23:16:16+07:00"}
{"file":"logrus.go, lineNumber:23","func":"main.main","level":"info","msg":"Now is: 2023-01-03 23:16:16.8059898 +0700 +07 m=+0.002165001","time":"2023-01-03T23:16:16+07:00"}
Example 3: Create custom logrus Formatter
Instead of customizing the existing formatter we can also create our own
formatter to be used with logrus. Here we have used SetReportCaller to
get the line number of the call which has been executed. This will
capture all the success and failed event’s line number called by logger
function.
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
"github.com/sirupsen/logrus"
)
type MyFormatter struct{}
var levelList = []string{
"panic",
"fatal",
"error",
"warn",
"info",
"debug",
"trace",
}
var logFile = "/tmp/app.log"
func (mf *MyFormatter) Format(entry *logrus.Entry) ([]byte, error) {
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
// define supported log levels
level := levelList[int(entry.Level)]
strList := strings.Split(entry.Caller.File, "/")
// get the go file name
fileName := strList[len(strList)-1]
b.WriteString(fmt.Sprintf("%28s, %5s, [%s:%d] - %s\n",
// Custom Time Format
entry.Time.Format("2006-01-02T15:04:05.9999999Z"),
level, fileName, entry.Caller.Line, entry.Message))
return b.Bytes(), nil
}
func configureLogging() *logrus.Logger {
// read the logfile
f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
logger := logrus.New()
// Log the messages on console as well as log file
logger.SetOutput(io.MultiWriter(f, os.Stdout))
logger.SetLevel(logrus.DebugLevel)
// Required to get line number
logger.SetReportCaller(true)
// Set custom formatter
logger.SetFormatter(&MyFormatter{})
return logger
}
func main() {
logger := configureLogging()
logger.Info("Hello World")
}
Output:
# go run main.go
2023-01-06T00:01:59.8623697Z, info, [main.go:70] - Hello World
# cat /tmp/app.log
2023-01-04T19:13:51.8677253Z, info, auth, [<nil>:main.go:65] - Hello World
2023-01-04T19:16:01.4347405Z, info, [main.go:65] - Hello World
2023-01-05T23:59:57.1855156Z, info, [main.go:63] - Hello World
2023-01-06T00:01:59.8623697Z, info, [main.go:70] - Hello World
Example 4: Using a third-party logging formatter
We can use powerful-logrus-formatter to get
fileName, the log’s line number, and the latest function’s name when
printing the log. If you want to use this package, first install it by
running the below command:
github.com/zput/zxcTool/ztLog/zt_formatter
This package allows us to:
- Print the name and line about the file and the latest function name while this log
- Save the log to file
Here is an example of using the zt_formatter along with the logrus to
print out the function name, file name, and line number:
package main
import (
"fmt"
"path"
"runtime"
nested "github.com/antonfisher/nested-logrus-formatter"
"github.com/sirupsen/logrus"
"github.com/zput/zxcTool/ztLog/zt_formatter"
)
func main() {
// use the specific formatter
var exampleFormatter = &zt_formatter.ZtFormatter{
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
filename := path.Base(f.File)
return fmt.Sprintf("%s()", f.Function), fmt.Sprintf("%s:%d", filename, f.Line)
},
Formatter: nested.Formatter{
//HideKeys: true,
FieldsOrder: []string{"component", "category"},
},
}
l := logrus.New()
// set the SetReportCaller to true
l.SetReportCaller(true)
if exampleFormatter != nil {
l.SetFormatter(exampleFormatter)
}
l.Infof("this is %v demo", "Hello world!")
}
Output:
[logrus.go:30::main.main()] Jan 3 23:28:56.705 [I] this is Hello world! demo
Example 5: Write your own function to log the file name, function name, and line number
In the example below, we will use the runtime.Caller() to get the file
name, function name, and line number. Then we use the
logrus.WithFields to export the logger:
func Caller(skip int) (pc uintptr, file string, line int, ok bool):
Caller reports file and line number information about
function invocations on the calling goroutine’s stack. The argument skip
is the number of stack frames to ascend, with 0 identifying the caller
of the Caller.
package main
import (
"fmt"
"runtime"
"strings"
"github.com/sirupsen/logrus"
)
func main() {
Warn("this is a warning!")
}
func Warn(msg ...interface{}) {
if pc, file, line, ok := runtime.Caller(1); ok {
//get the file name
file = file[strings.LastIndex(file, "/")+1:]
//get the function name
funcName := runtime.FuncForPC(pc).Name()
// export the logger
logrus.WithFields(
logrus.Fields{
"src": fmt.Sprintf("%s:%s:%d", file, funcName, line),
}).Warn(msg...)
}
}
Output:
time="2023-01-03T23:38:50+07:00" level=warning msg="this is a warning!" src="logrus.go:main.main:12"
Summary
In this tutorial, I have given you some examples of printing the
function name, file name, and line number using the logrus. We can
easily get the SetReportCaller to true which means including the
calling method as a field. In the next step, we can use the default, a
customized format, or a third-party formatter to print the log to the
console. Another way is using the runtime.Caller() function to get all
the information about the file name, and function name and parse it as a
field of the logger.
References
https://github.com/sirupsen/logrus
https://github.com/zput/zxcTool
https://pkg.go.dev/runtime#Caller

![Print Function, File Name, Line Number in GO [SOLVED]](/logrus-print-function-file-name-line-number/golang-logrus-line-number.jpg)
