Logrus is the widely used structured logger behind searches for logrus, golang logrus, logrus golang, go logrus, and logrus go. It lives at github.com/sirupsen/logrus (sometimes written sirupsen logrus). This guide gives a golang log example, explains logrus log levels, shows file and console output, JSON formatting, caller metadata, hooks, and how that relates to processing large line-oriented logs. For changing the standard library logger’s format, see change default log format. For removing a module later, see remove installed package with go get.
Tested with Go 1.24 on Linux and
github.com/sirupsen/logrusv1.9.3.
Using logrus in Go (golang logrus, go logrus)
Add the module and import path
From your module root:
go get github.com/sirupsen/logrusgo: added github.com/sirupsen/logrus v1.9.3
go: added golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8Use exactly this import path in every file:
import "github.com/sirupsen/logrus"If your editor shows a long hex token next to the module name, that is almost always a go.sum checksum or a pseudo-version string from the proxy—not something you paste into import paths.
A minimal golang log example
package main
import "github.com/sirupsen/logrus"
func main() {
logrus.Println("Hello, world!")
}go run .time="2026-06-17T22:57:37+05:30" level=info msg="Hello, world!"The default is a text formatter with time, level, and msg keys. That is a practical go logrus baseline before you tune formatters or outputs.
Logrus log levels and SetLevel
Logrus defines PanicLevel, FatalLevel, ErrorLevel, WarnLevel, InfoLevel, DebugLevel, and TraceLevel with numeric ranks 0…6 (panic is most severe; trace is the chattiest). A line is emitted when its level is numerically less than or equal to the configured level, so InfoLevel shows panic through info but hides debug and trace until you raise the threshold.
With the threshold at TraceLevel, every line below is emitted:
package main
import "github.com/sirupsen/logrus"
func main() {
logrus.SetLevel(logrus.TraceLevel)
logrus.Traceln("Trace Level")
logrus.Debugln("Debug Level")
logrus.Infoln("Info Level")
logrus.Warningln("Warning Level")
logrus.Errorln("Error Level")
}time="2026-06-17T22:57:46+05:30" level=trace msg="Trace Level"
time="2026-06-17T22:57:46+05:30" level=debug msg="Debug Level"
time="2026-06-17T22:57:46+05:30" level=info msg="Info Level"
time="2026-06-17T22:57:46+05:30" level=warning msg="Warning Level"
time="2026-06-17T22:57:46+05:30" level=error msg="Error Level"Raising the bar to DebugLevel drops trace lines:
package main
import "github.com/sirupsen/logrus"
func main() {
logrus.SetLevel(logrus.DebugLevel)
logrus.Traceln("Trace Level")
logrus.Debugln("Debug Level")
logrus.Infoln("Info Level")
}time="2026-06-17T22:57:53+05:30" level=debug msg="Debug Level"
time="2026-06-17T22:57:53+05:30" level=info msg="Info Level"Fatal and Panic helpers still log and then stop the process (os.Exit or panic); omit them in long-running demos unless you expect the exit.
Writers: stdout, stderr, files, and io.MultiWriter
SetOutput controls where entries go. The default is os.Stderr; os.Stdout is common for containers. Open a file with os.OpenFile and append flags, then assign SetOutput(f) or combine sinks:
package main
import (
"io"
"os"
"github.com/sirupsen/logrus"
)
func main() {
f, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer f.Close()
logrus.SetOutput(io.MultiWriter(os.Stdout, f))
logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
logrus.SetLevel(logrus.InfoLevel)
logrus.Info("both stdout and file")
}time="2026-06-17T22:58:00+05:30" level=info msg="both stdout and file"The same line should appear in app.log. For JSON pipelines or log hosts, switch the formatter in the next section instead of changing writers.
Structured fields, JSON, and text tweaks
Attach fields once with WithFields, or use WithField for a single pair:
package main
import "github.com/sirupsen/logrus"
func main() {
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.WithFields(logrus.Fields{"user": "ann"}).Info("login")
}{"level":"info","msg":"login","time":"2026-06-17T22:58:05+05:30","user":"ann"}TextFormatter accepts TimestampFormat, DisableColors, FullTimestamp, and FieldMap if you need syslog-style keys while staying human-readable. Colors only make sense when stderr is a terminal; see TTY notes if you run under systemd. For live service logs on Linux hosts, journalctl is often paired with JSON logs.
Caller metadata and hooks
SetReportCaller(true) adds file and function hints (exact shape depends on the formatter):
package main
import "github.com/sirupsen/logrus"
func main() {
logrus.SetReportCaller(true)
logrus.SetLevel(logrus.InfoLevel)
logrus.Info("with caller")
}time="2026-06-17T22:58:11+05:30" level=info msg="with caller" func=main.main file="/tmp/logrusdemo/main.go:10"Hooks implement logrus.Hook (Levels + Fire) to fan out certain levels—errors to a file, metrics, or tracing backends. Keep hook work fast; offload heavy I/O to a goroutine with backpressure if needed.
package main
import (
"fmt"
"os"
"github.com/sirupsen/logrus"
)
type errorFileHook struct{ f *os.File }
func (h *errorFileHook) Levels() []logrus.Level {
return []logrus.Level{logrus.ErrorLevel}
}
func (h *errorFileHook) Fire(e *logrus.Entry) error {
_, err := fmt.Fprintf(h.f, "%s %s\n", e.Time.Format("2006-01-02 15:04:05"), e.Message)
return err
}
func main() {
logger := logrus.New()
f, err := os.OpenFile("errors.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer f.Close()
logger.AddHook(&errorFileHook{f: f})
logger.Error("persisted via hook")
}Large log files, goroutines, and timestamp type message lines
Some searches describe a program that processes a large log file where each line looks like timestamp type message. That task is plain Go parsing: stream with bufio.Scanner, push lines into a buffered channel, and let a small worker pool split CPU-heavy work. Logrus does not parse arbitrary legacy files; use it inside that tool to log progress (Info every N lines), malformed-line Warn events, or final summaries. Keep Scanner’s default line cap in mind for unusually wide lines.
Sketch:
// Pseudocode shape: scanner -> jobs chan -> worker goroutines -> aggregate results.
// Use logrus.New() in each worker or pass a logger to avoid global contention if needed.Summary
Logrus gives Go developers a familiar golang logrus path: add github.com/sirupsen/logrus, start with text output, tune logrus log levels through SetLevel, and graduate to WithFields plus JSONFormatter when log hosts expect JSON. io.MultiWriter covers console-plus-file sinks, SetReportCaller improves debuggability, and hooks isolate side effects per level. Long sirupsen/logrus strings with hex come from module metadata, not imports. For huge timestamp type message files, combine normal concurrent Go I/O with logrus for observability of the parser itself—not for interpreting someone else’s format magically.
References
github.com/sirupsen/logrusrepository- Go modules reference (
go.sum, versions) - Stack Overflow: change logrus output format

