Pendekatan yang benar untuk penebangan global di Golang

120

Apa pola untuk aplikasi login di Go? Jika saya memiliki, katakanlah, 5 goroutine yang harus saya log in, haruskah saya ...

  • Buat single log.Loggerdan bagikan?
  • Berikan petunjuk ke itu log.Logger?
  • Haruskah setiap goroutine atau fungsi membuat logger?
  • Haruskah saya membuat logger sebagai variabel global?
Carson
sumber

Jawaban:

59
  • Buat satu log. Logger dan bagikan?

Itu mungkin. Sebuah log.Logger bisa digunakan secara bersamaan dari beberapa goroutine.

  • Berikan pointer ke log itu. Logger?

log.New mengembalikan *Loggeryang biasanya merupakan indikasi bahwa Anda harus meneruskan objek sebagai penunjuk. Meneruskannya sebagai nilai akan membuat salinan dari struct (yaitu salinan Logger) dan kemudian beberapa goroutine mungkin menulis ke io.Writer yang sama secara bersamaan. Itu mungkin masalah serius, tergantung pada implementasi penulisnya.

  • Haruskah setiap goroutine atau fungsi membuat logger?

Saya tidak akan membuat logger terpisah untuk setiap fungsi atau goroutine. Goroutine (dan fungsi) digunakan untuk tugas-tugas yang sangat ringan yang tidak akan membenarkan pemeliharaan pencatat terpisah. Mungkin ide yang bagus untuk membuat logger untuk setiap komponen yang lebih besar dari proyek Anda. Misalnya, jika proyek Anda menggunakan layanan SMTP untuk mengirim email, membuat logger terpisah untuk layanan email terdengar seperti ide yang bagus sehingga Anda dapat memfilter dan mematikan keluaran secara terpisah.

  • Haruskah saya membuat logger sebagai variabel global?

Itu tergantung pada paket Anda. Dalam contoh layanan email sebelumnya, mungkin ide yang bagus untuk memiliki satu pencatat untuk setiap layanan Anda, sehingga pengguna dapat mencatat kegagalan saat menggunakan layanan email gmail secara berbeda dari kegagalan yang terjadi saat menggunakan MTA lokal (mis. Sendmail ).

tux21b
sumber
37

Untuk kasus sederhana, ada logger global yang ditentukan dalam paket log log.Logger,. Logger global ini dapat dikonfigurasi melalui log.SetFlags.

Setelah itu seseorang dapat memanggil fungsi tingkat atas dari paket log seperti log.Printfdan log.Fatalf, yang menggunakan contoh global tersebut.

zzzz
sumber
Pikir Anda dapat mengatur bendera Anda tidak dapat menggunakan logger kustom.
0xcaff
Sebenarnya @caffinatedmonkey, Anda dapat menggunakan logger khusus jika mereka menerapkan io.Writerantarmuka dan Anda mengubah keluaran dari pencatat default melalui SetOutput().
congusbongus
16

Ini adalah logger sederhana

package customlogger

import (
    "log"
    "os"
    "sync"
)

type logger struct {
    filename string
    *log.Logger
}

var logger *logger
var once sync.Once

// start loggeando
func GetInstance() *logger {
    once.Do(func() {
        logger = createLogger("mylogger.log")
    })
    return logger
}

func createLogger(fname string) *logger {
    file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)

    return &logger{
        filename: fname,
        Logger:   log.New(file, "My app Name ", log.Lshortfile),
    }
}

Anda bisa menggunakannya dengan cara ini

package main

import (
    "customlogger"
    "fmt"
    "net/http"
)

func main() {
    logger := customlogger.GetInstance()
    logger.Println("Starting")

    http.HandleFunc("/", sroot)
    http.ListenAndServe(":8080", nil)
}

func sroot(w http.ResponseWriter, r *http.Request) {
    logger := customlogger.GetInstance()

    fmt.Fprintf(w, "welcome")
    logger.Println("Starting")
}
Israel Barba
sumber
10

Saya tahu pertanyaan ini agak lama, tetapi jika, seperti saya, proyek Anda terdiri dari beberapa file yang lebih kecil, saya memilih opsi ke-4 Anda - Saya telah membuat logger.goyang merupakan bagian dari paket utama. File go ini membuat logger, menugaskannya ke file, dan menyediakannya ke main. Catatan Saya belum menemukan cara yang anggun untuk menutup errorlog ...

package main

import (
    "fmt"
    "log"
    "os"
)

var errorlog *os.File
var logger *log.Logger

func init() {
    errorlog, err := os.OpenFile(logfile,  os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Printf("error opening file: %v", err)
        os.Exit(1)
    }

    logger = log.New(errorlog, "applog: ", log.Lshortfile|log.LstdFlags)
}
Omortis
sumber
8
Untuk penutupan yang anggun, Anda mungkin bisa defer errorlog.Close()di akhir eksekusi, atau untuk lebih memastikannya tertutup, atur penangan sinyal menggunakan paket sinyal Go golang.org/pkg/os/signal
Anfernee
4

Ini adalah pertanyaan lama, tapi saya ingin menyarankan penggunaan http://github.com/romana/rlog (yang kami kembangkan). Ini dikonfigurasi melalui variabel lingkungan, objek logger dibuat dan diinisialisasi ketika rlog diimpor. Oleh karena itu, tidak perlu melewati logger.

rlog memiliki beberapa fitur:

  • Stempel tanggal / waktu yang dapat dikonfigurasi sepenuhnya
  • Output simultan ke stderr atau stdout serta file.
  • Level log standar (Debug, Info, dll.) Serta logging multi level yang dapat dikonfigurasi secara bebas.
  • Atas permintaan pencatatan info pemanggil (file, nomor baris, fungsi).
  • Kemampuan untuk mengatur tingkat log yang berbeda untuk file sumber yang berbeda.

Ini sangat kecil, tidak memiliki ketergantungan eksternal, kecuali pustaka Golang standar dan sedang dikembangkan secara aktif. Contoh disediakan di repo.

Juergen Brendel
sumber
3
Terima kasih telah mengungkapkan afiliasi Anda dengan produk yang Anda rekomendasikan! Itu dihargai.
Robert Columbia
2

Saya menemukan paket log default ( https://golang.org/pkg/log/ ) agak membatasi. Misalnya, tidak ada dukungan untuk info vs. log debug.
Setelah melihat-lihat, gunakan https://github.com/golang/glog . Ini tampaknya menjadi porta https://github.com/google/glog dan memberikan fleksibilitas yang layak dalam logging. Misalnya saat menjalankan aplikasi secara lokal Anda mungkin menginginkan log level DEBUG tetapi mungkin ingin menjalankan hanya di tingkat INFO / ERROR dalam produksi. Daftar fitur / panduan lengkap ada, di sini https://google-glog.googlecode.com/svn/trunk/doc/glog.html (Ini untuk modul c ++, tetapi sebagian besar diterjemahkan ke port golang)

pembantu
sumber
0

Salah satu modul logging yang bisa Anda pertimbangkan adalah klog . Ini mendukung logging 'V' yang memberikan fleksibilitas untuk log pada level tertentu

klog adalah garpu glog dan mengatasi kelemahan berikut

  • glog menghadirkan banyak "gotchas" dan memperkenalkan tantangan dalam lingkungan dalam peti kemas, yang semuanya tidak didokumentasikan dengan baik.
  • glog tidak menyediakan cara mudah untuk menguji log, yang mengurangi stabilitas perangkat lunak yang menggunakannya
  • glog adalah berbasis C ++ dan klog adalah implementasi golang murni

Implementasi Sampel

package main

import (
    "flag"

    "k8s.io/klog"


)

type myError struct {
    str string
}

func (e myError) Error() string {
    return e.str
}

func main() {
    klog.InitFlags(nil)
    flag.Set("v", "1")
    flag.Parse()

    klog.Info("hello", "val1", 1, "val2", map[string]int{"k": 1})
    klog.V(3).Info("nice to meet you")
    klog.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14})
    klog.Error(myError{"an error occurred"}, "goodbye", "code", -1)
    klog.Flush()
}
Chids
sumber