Logrus adalah logger terstruktur untuk Go (golang), sepenuhnya kompatibel dengan API dengan logger perpustakaan standar.
Logrus sedang dalam mode pemeliharaan. Kami tidak akan memperkenalkan fitur baru. Ini terlalu sulit untuk dilakukan dengan cara yang tidak akan merusak proyek banyak orang, yang merupakan hal terakhir yang Anda inginkan dari perpustakaan Logging Anda (sekali lagi...).
Ini tidak berarti Logrus sudah mati. Logrus akan terus dipertahankan untuk keamanan, perbaikan bug (kompatibel dengan versi sebelumnya), dan kinerja (jika kami dibatasi oleh antarmuka).
Saya yakin kontribusi terbesar Logrus adalah berperan dalam meluasnya penggunaan logging terstruktur di Golang. Tampaknya tidak ada alasan untuk melakukan terobosan besar, dengan memecah iterasi ke dalam Logrus V2, karena komunitas Go yang luar biasa telah membangunnya secara mandiri. Banyak alternatif fantastis bermunculan. Logrus akan terlihat seperti itu, jika didesain ulang dengan apa yang kita ketahui tentang logging terstruktur di Go saat ini. Lihat, misalnya, Zerolog, Zap, dan Apex.
Melihat masalah peka huruf besar-kecil yang aneh? Di masa lalu, Logrus dapat diimpor dalam huruf besar dan kecil. Karena lingkungan paket Go, hal ini menyebabkan masalah di komunitas dan kami memerlukan standar. Beberapa lingkungan mengalami masalah dengan varian huruf besar, sehingga diputuskan huruf kecil. Segala sesuatu yang menggunakan logrus
harus menggunakan huruf kecil: github.com/sirupsen/logrus
. Paket apa pun yang tidak, harus diubah.
Untuk memperbaiki Glide, lihat komentar ini. Untuk penjelasan mendalam mengenai masalah casing, lihat komentar ini.
Kode warna yang bagus dalam pengembangan (saat TTY dilampirkan, jika tidak, hanya teks biasa):
Dengan log.SetFormatter(&log.JSONFormatter{})
, agar mudah diuraikan dengan logstash atau Splunk:
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
{"level":"warning","msg":"The group's number increased tremendously!",
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
Dengan log.SetFormatter(&log.TextFormatter{})
default ketika TTY tidak dilampirkan, outputnya kompatibel dengan format logfmt:
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
Untuk memastikan perilaku ini meskipun TTY terpasang, atur formatter Anda sebagai berikut:
log . SetFormatter ( & log. TextFormatter {
DisableColors : true ,
FullTimestamp : true ,
})
Jika Anda ingin menambahkan metode pemanggilan sebagai kolom, instruksikan logger melalui:
log . SetReportCaller ( true )
Ini menambahkan penelepon sebagai 'metode' seperti:
{ "animal" : " penguin " , "level" : " fatal " , "method" : " github.com/sirupsen/arcticcreatures.migrate " , "msg" : " a penguin swims by " ,
"time" : " 2014-03-10 19:57:38.562543129 -0400 EDT " }
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
Perhatikan bahwa hal ini menambah overhead yang terukur - biayanya akan bergantung pada versi Go, namun berkisar antara 20 dan 40% dalam pengujian terbaru dengan 1.6 dan 1.7. Anda dapat memvalidasi ini di lingkungan Anda melalui tolok ukur:
go test -bench=.*CallerTracing
Nama organisasi diubah menjadi huruf kecil--dan ini tidak akan diubah kembali. Jika Anda mengalami konflik impor karena sensitivitas huruf besar-kecil, harap gunakan impor huruf kecil: github.com/sirupsen/logrus
.
Cara paling sederhana untuk menggunakan Logrus adalah dengan mengekspor logger tingkat paket:
package main
import (
log "github.com/sirupsen/logrus"
)
func main () {
log . WithFields (log. Fields {
"animal" : "walrus" ,
}). Info ( "A walrus appears" )
}
Perhatikan bahwa ini sepenuhnya kompatibel dengan api dengan logger stdlib, sehingga Anda dapat mengganti impor log
Anda di mana saja dengan log "github.com/sirupsen/logrus"
dan sekarang Anda akan memiliki fleksibilitas Logrus. Anda dapat menyesuaikannya sesuka Anda:
package main
import (
"os"
log "github.com/sirupsen/logrus"
)
func init () {
// Log as JSON instead of the default ASCII formatter.
log . SetFormatter ( & log. JSONFormatter {})
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log . SetOutput ( os . Stdout )
// Only log the warning severity or above.
log . SetLevel ( log . WarnLevel )
}
func main () {
log . WithFields (log. Fields {
"animal" : "walrus" ,
"size" : 10 ,
}). Info ( "A group of walrus emerges from the ocean" )
log . WithFields (log. Fields {
"omg" : true ,
"number" : 122 ,
}). Warn ( "The group's number increased tremendously!" )
log . WithFields (log. Fields {
"omg" : true ,
"number" : 100 ,
}). Fatal ( "The ice breaks!" )
// A common pattern is to re-use fields between logging statements by re-using
// the logrus.Entry returned from WithFields()
contextLogger := log . WithFields (log. Fields {
"common" : "this is a common field" ,
"other" : "I also should be logged always" ,
})
contextLogger . Info ( "I'll be logged with common and other field" )
contextLogger . Info ( "Me too" )
}
Untuk penggunaan lebih lanjut seperti masuk ke beberapa lokasi dari aplikasi yang sama, Anda juga dapat membuat instance logrus
Logger:
package main
import (
"os"
"github.com/sirupsen/logrus"
)
// Create a new instance of the logger. You can have any number of instances.
var log = logrus . New ()
func main () {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log . Out = os . Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log . WithFields (logrus. Fields {
"animal" : "walrus" ,
"size" : 10 ,
}). Info ( "A group of walrus emerges from the ocean" )
}
Logrus mendorong pencatatan log yang hati-hati dan terstruktur melalui kolom pencatatan, bukannya pesan kesalahan yang panjang dan tidak dapat diurai. Misalnya, alih-alih: log.Fatalf("Failed to send event %s to topic %s with key %d")
, Anda harus mencatat log yang lebih mudah ditemukan:
log . WithFields (log. Fields {
"event" : event ,
"topic" : topic ,
"key" : key ,
}). Fatal ( "Failed to send event" )
Kami menemukan API ini memaksa Anda untuk berpikir tentang logging dengan cara yang menghasilkan pesan logging yang jauh lebih berguna. Kami telah berada dalam situasi yang tak terhitung jumlahnya di mana hanya satu bidang tambahan ke pernyataan log yang sudah ada akan menghemat waktu kami. Panggilan WithFields
bersifat opsional.
Secara umum, dengan Logrus menggunakan salah satu fungsi printf
-family harus dilihat sebagai petunjuk Anda harus menambahkan bidang, namun, Anda masih dapat menggunakan fungsi printf
-family dengan Logrus.
Seringkali akan membantu jika kolom selalu dilampirkan ke pernyataan log dalam suatu aplikasi atau bagian dari aplikasi tersebut. Misalnya, Anda mungkin ingin selalu mencatat request_id
dan user_ip
dalam konteks permintaan. Daripada menulis log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
di setiap baris, Anda dapat membuat logrus.Entry
untuk dibagikan:
requestLogger := log . WithFields (log. Fields { "request_id" : request_id , "user_ip" : user_ip })
requestLogger. Info ( "something happened on that request" ) # will log request_id and user_ip
requestLogger . Warn ( "something not great happened" )
Anda dapat menambahkan kait untuk level logging. Misalnya untuk mengirim kesalahan ke layanan pelacakan pengecualian pada Error
, Fatal
dan Panic
, info ke StatsD atau login ke beberapa tempat secara bersamaan, misalnya syslog.
Logrus dilengkapi dengan kait bawaan. Tambahkan itu, atau pengait khusus Anda, di init
:
import (
log "github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
"log/syslog"
)
func init () {
// Use the Airbrake hook to report errors that have Error severity or above to
// an exception tracker. You can create custom hooks, see the Hooks section.
log . AddHook ( airbrake . NewHook ( 123 , "xyz" , "production" ))
hook , err := logrus_syslog . NewSyslogHook ( "udp" , "localhost:514" , syslog . LOG_INFO , "" )
if err != nil {
log . Error ( "Unable to connect to local syslog daemon" )
} else {
log . AddHook ( hook )
}
}
Catatan: Syslog hook juga mendukung koneksi ke syslog lokal (Mis. "/dev/log" atau "/var/run/syslog" atau "/var/run/log"). Untuk detailnya, silakan periksa README hook syslog.
Daftar kait layanan yang dikenal saat ini dapat ditemukan di halaman wiki ini
Logrus memiliki tujuh level logging: Trace, Debug, Info, Warning, Error, Fatal dan Panic.
log . Trace ( "Something very low level." )
log . Debug ( "Useful debugging information." )
log . Info ( "Something noteworthy happened!" )
log . Warn ( "You should probably take a look at this." )
log . Error ( "Something failed but I'm not quitting." )
// Calls os.Exit(1) after logging
log . Fatal ( "Bye." )
// Calls panic() after logging
log . Panic ( "I'm bailing." )
Anda dapat mengatur tingkat logging pada Logger
, lalu ia hanya akan mencatat entri dengan tingkat keparahan tersebut atau apa pun di atasnya:
// Will log anything that is info or above (warn, error, fatal, panic). Default.
log . SetLevel ( log . InfoLevel )
Mungkin berguna untuk menyetel log.Level = logrus.DebugLevel
di lingkungan debug atau verbose jika aplikasi Anda memilikinya.
Catatan: Jika Anda menginginkan level log yang berbeda untuk logging global ( log.SetLevel(...)
) dan syslog, silakan periksa README kait syslog.
Selain bidang yang ditambahkan dengan WithField
atau WithFields
beberapa bidang secara otomatis ditambahkan ke semua peristiwa logging:
time
. Stempel waktu saat entri dibuat.msg
. Pesan logging diteruskan ke {Info,Warn,Error,Fatal,Panic}
setelah panggilan AddFields
. Misalnya Failed to send event.
level
. Tingkat pencatatan. Misalnya info
. Logrus tidak memiliki gagasan tentang lingkungan.
Jika Anda ingin hook dan formatter hanya digunakan di lingkungan tertentu, Anda harus menanganinya sendiri. Misalnya, jika aplikasi Anda memiliki variabel global Environment
, yang merupakan representasi string dari lingkungan, Anda dapat melakukan:
import (
log "github.com/sirupsen/logrus"
)
func init () {
// do something here to set environment depending on an environment variable
// or command-line flag
if Environment == "production" {
log . SetFormatter ( & log. JSONFormatter {})
} else {
// The TextFormatter is default, you don't actually have to do this.
log . SetFormatter ( & log. TextFormatter {})
}
}
Konfigurasi ini adalah bagaimana logrus
dimaksudkan untuk digunakan, tetapi JSON dalam produksi sebagian besar hanya berguna jika Anda melakukan agregasi log dengan alat seperti Splunk atau Logstash.
Pemformat logging bawaan adalah:
logrus.TextFormatter
. Mencatat peristiwa dalam warna jika stdout adalah tty, jika tidak, tanpa warna.ForceColors
ke true
. Untuk memaksa tidak ada keluaran berwarna meskipun ada TTY, setel bidang DisableColors
ke true
. Untuk Windows, lihat github.com/mattn/go-colorable.DisableLevelTruncation
ke true
.PadLevelText
ke true
mengaktifkan perilaku ini, dengan menambahkan padding ke teks level.logrus.JSONFormatter
. Bidang log sebagai JSON.Pemformat logging pihak ketiga:
FluentdFormatter
. Memformat entri yang dapat diurai oleh Kubernetes dan Google Container Engine.GELF
. Memformat entri agar sesuai dengan spesifikasi GELF 1.1 Graylog.logstash
. Bidang log sebagai Peristiwa Logstash.prefixed
. Menampilkan sumber entri log beserta tata letak alternatif.zalgo
. Memanggil Kekuatan Zalgo.nested-logrus-formatter
. Mengonversi bidang logrus menjadi struktur bersarang.powerful-logrus-formatter
. dapatkan nama file, nomor baris log dan nama fungsi terbaru saat mencetak log; Simpan log ke file.caption-json-formatter
. pemformat json pesan logrus dengan teks yang dapat dibaca manusia ditambahkan. Anda dapat menentukan formatter Anda dengan mengimplementasikan antarmuka Formatter
, yang memerlukan metode Format
. Format
membutuhkan *Entry
. entry.Data
adalah tipe Fields
( map[string]interface{}
) dengan semua bidang Anda serta bidang default (lihat bagian Entri di atas):
type MyJSONFormatter struct {
}
log . SetFormatter ( new ( MyJSONFormatter ))
func ( f * MyJSONFormatter ) Format ( entry * Entry ) ([] byte , error ) {
// Note this doesn't include Time, Level and Message which are available on
// the Entry. Consult `godoc` on information about those fields or read the
// source of the official loggers.
serialized , err := json . Marshal ( entry . Data )
if err != nil {
return nil , fmt . Errorf ( "Failed to marshal fields to JSON, %w" , err )
}
return append ( serialized , 'n' ), nil
}
io.Writer
Logrus dapat diubah menjadi io.Writer
. Penulis itu adalah akhir dari io.Pipe
dan Anda bertanggung jawab untuk menutupnya.
w := logger . Writer ()
defer w . Close ()
srv := http. Server {
// create a stdlib log.Logger that writes to
// logrus.Logger.
ErrorLog : log . New ( w , "" , 0 ),
}
Setiap baris yang ditulis kepada penulis tersebut akan dicetak dengan cara biasa, menggunakan formatter dan hook. Level untuk entri tersebut adalah info
.
Ini berarti kita dapat mengganti logger perpustakaan standar dengan mudah:
logger := logrus . New ()
logger . Formatter = & logrus. JSONFormatter {}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log . SetOutput ( logger . Writer ())
Rotasi log tidak disediakan dengan Logrus. Rotasi log harus dilakukan oleh program eksternal (seperti logrotate(8)
) yang dapat mengompresi dan menghapus entri log lama. Ini tidak boleh menjadi fitur logger tingkat aplikasi.
Alat | Keterangan |
---|---|
Teman Logrus | Logrus mate adalah alat bagi Logrus untuk mengelola logger, Anda dapat menginisialisasi level logger, menghubungkan dan memformat dengan file konfigurasi, logger akan dihasilkan dengan konfigurasi berbeda di lingkungan berbeda. |
Pembantu Logrus Viper | Pembantu di sekitar Logrus untuk membungkus dengan spf13/Viper untuk memuat konfigurasi dengan taring! Dan untuk menyederhanakan konfigurasi Logrus gunakan beberapa perilaku Logrus Mate. mencicipi |
Logrus memiliki fasilitas bawaan untuk menegaskan keberadaan pesan log. Ini diimplementasikan melalui test
hook dan menyediakan:
test.NewLocal
dan test.NewGlobal
) yang pada dasarnya hanya menambahkan test
hooktest.NewNullLogger
) yang hanya mencatat pesan log (dan tidak menghasilkan keluaran apa pun): import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSomething ( t * testing. T ){
logger , hook := test . NewNullLogger ()
logger . Error ( "Helloerror" )
assert . Equal ( t , 1 , len ( hook . Entries ))
assert . Equal ( t , logrus . ErrorLevel , hook . LastEntry (). Level )
assert . Equal ( t , "Helloerror" , hook . LastEntry (). Message )
hook . Reset ()
assert . Nil ( t , hook . LastEntry ())
}
Logrus dapat mendaftarkan satu atau lebih fungsi yang akan dipanggil ketika pesan tingkat fatal
apa pun dicatat. Penangan terdaftar akan dieksekusi sebelum logrus melakukan os.Exit(1)
. Perilaku ini mungkin berguna jika penelepon perlu mematikannya dengan baik. Berbeda dengan panggilan panic("Something went wrong...")
yang dapat disadap dengan recover
yang ditangguhkan, panggilan ke os.Exit(1)
tidak dapat disadap.
...
handler := func() {
// gracefully shutdown something...
}
logrus.RegisterExitHandler(handler)
...
Secara default, Logger dilindungi oleh mutex untuk penulisan bersamaan. Mutex ditahan saat memanggil hook dan menulis log. Jika Anda yakin penguncian tersebut tidak diperlukan, Anda dapat memanggil logger.SetNoLock() untuk menonaktifkan penguncian.
Situasi ketika penguncian tidak diperlukan meliputi:
Anda tidak memiliki hook yang terdaftar, atau pemanggilan hook sudah aman untuk thread.
Menulis ke logger.Out sudah aman untuk thread, misalnya:
logger.Out dilindungi oleh kunci.
logger.Out adalah penangan os.File yang dibuka dengan flag O_APPEND
, dan setiap penulisan lebih kecil dari 4k. (Ini memungkinkan penulisan multi-utas/multi-proses)
(Lihat http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)