Golang'da küresel günlüğe doğru yaklaşım


120

Go'da uygulama oturum açma düzeni nedir? Diyelim ki, giriş yapmam gereken 5 gorutin varsa, ben ...

  • Bir single oluşturup log.Loggerdağıtmak mı?
  • Buna bir işaretçi log.Loggermi vereceksin ?
  • Her bir gorutin veya fonksiyon bir kaydedici oluşturmalı mı?
  • Logger'ı global bir değişken olarak oluşturmalı mıyım?

Yanıtlar:


59
  • Tek bir günlük oluşturun. Kaydedin ve iletilsin mi?

Bu mümkündür. Bir log.Logger , birden fazla gorutinden aynı anda kullanılabilir.

  • Bu günlüğe bir işaretçi iletin.

log.New*Logger , genellikle nesneyi bir işaretçi olarak geçirmeniz gerektiğini gösteren bir gösterge döndürür . Bunu değer olarak geçirmek yapının bir kopyasını (yani Logger'ın bir kopyasını) yaratır ve daha sonra birden fazla gorutin aynı io.Writer'a aynı anda yazabilir . Yazarın uygulamasına bağlı olarak bu ciddi bir sorun olabilir.

  • Her bir gorutin veya fonksiyon bir kaydedici oluşturmalı mı?

Her işlev veya program için ayrı bir kaydedici oluşturmazdım. Gorutinler (ve işlevler), ayrı bir kaydedicinin bakımını haklı çıkarmayacak çok hafif görevler için kullanılır. Projenizin her büyük bileşeni için bir kaydedici oluşturmak muhtemelen iyi bir fikirdir. Örneğin, projeniz posta göndermek için bir SMTP hizmeti kullanıyorsa, posta hizmeti için ayrı bir kaydedici oluşturmak, çıkışı ayrı ayrı filtreleyip kapatabilmeniz için iyi bir fikir gibi görünür.

  • Logger'ı global bir değişken olarak oluşturmalı mıyım?

Bu paketinize bağlıdır. Önceki posta hizmeti örneğinde, hizmetinizin her örneği için bir günlük kaydediciye sahip olmak muhtemelen iyi bir fikirdir, böylece kullanıcılar gmail posta hizmetini kullanırken yerel MTA'yı kullanırken meydana gelen hatalardan farklı olarak hataları günlüğe kaydedebilir (ör. Sendmail ).


37

Basit durumlar için, günlük paketinde tanımlanmış bir global kaydedici vardır log.Logger. Bu global kaydedici üzerinden yapılandırılabilir log.SetFlags.

Daha sonra, günlük paketinin log.Printfve log.Fatalfbu global örneği kullanan üst düzey işlevleri çağırılabilir.


Özel bir kaydedici kullanamayacağınız bayrakları ayarlayabileceğinizi düşündüm.
0xcaff

@caffinatedmonkey, io.Writerarayüzü uygularlarsa özel kaydedicileri kullanabilirsiniz ve varsayılan günlükçünün çıktısını SetOutput().
congusbongus

16

Bu basit bir kaydedicidir

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),
    }
}

Bu şekilde kullanabilirsin

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")
}

10

Bu sorunun biraz eski olduğunu biliyorum, ancak benim gibi projeleriniz birden fazla küçük dosyadan oluşuyorsa 4. seçeneğiniz için oy veriyorum - logger.gomain paketinin bir parçası olan bir tane oluşturdum . Bu go dosyası kaydediciyi oluşturur, onu bir dosyaya atar ve ana dosyanın geri kalanına sağlar. Not Hata günlüğünü kapatmak için zarif bir yol bulamadım ...

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)
}

8
Zarif kapanış için, olabilir muhtemelen defer errorlog.Close()yürütme sonunda veya Go sinyal paketi kullanarak kapalı kurmak sinyal işleyici sağlamak daha iyi golang.org/pkg/os/signal
Anfernee

4

Bu daha eski bir soru, ancak http://github.com/romana/rlog (geliştirdiğimiz) kullanılmasını önermek istiyorum . Ortam değişkenleri aracılığıyla yapılandırılır, günlükçü nesnesi oluşturulur ve rlog içe aktarıldığında başlatılır. Bu nedenle, bir kaydedicinin etrafından dolaşmaya gerek yoktur.

rlog birkaç özelliğe sahiptir:

  • Tamamen yapılandırılabilir tarih / saat damgaları
  • Dosyanın yanı sıra stderr veya stdout'a eşzamanlı çıktı.
  • Standart günlük seviyeleri (Hata Ayıklama, Bilgi, vb.) Ve serbestçe yapılandırılabilen çok seviyeli günlük kaydı.
  • Arayan bilgilerinin isteğe bağlı olarak günlüğe kaydedilmesi (dosya, satır numarası, işlev).
  • Farklı kaynak dosyalar için farklı günlük seviyeleri belirleyebilme.

Çok küçüktür, standart Golang kütüphanesi dışında harici bağımlılıkları yoktur ve aktif olarak geliştirilmektedir. Depoda örnekler verilmiştir.


3
Önerdiğiniz ürünle olan ilişkinizi açıkladığınız için teşekkür ederiz! Takdir edildi.
Robert Columbia

2

Varsayılan günlük paketini ( https://golang.org/pkg/log/ ) biraz sınırlayıcı buldum . Örneğin, bilgi ve hata ayıklama günlükleri desteği yoktur.
Biraz dolaştıktan sonra, https://github.com/golang/glog kullanmaya karar verdik . Bu bir https://github.com/google/glog bağlantı noktası gibi görünüyor ve günlük tutmada iyi bir esneklik sağlıyor. Örneğin, bir uygulamayı yerel olarak çalıştırırken, DEBUG seviyesi günlüğünü isteyebilirsiniz, ancak üretimde yalnızca INFO / ERROR seviyesinde çalıştırmak isteyebilirsiniz. Tam özelliklerin / kılavuzun listesi burada https://google-glog.googlecode.com/svn/trunk/doc/glog.html (Bu c ++ modülü içindir, ancak çoğunlukla golang bağlantı noktasına çevrilir)


0

Değerlendirebileceğiniz günlük kaydı modüllerinden biri klog'dur . Belirli bir düzeyde oturum açma esnekliği sağlayan 'V' günlük kaydını destekler

klog bir glog çatalıdır ve aşağıdaki dezavantajların üstesinden gelir

  • glog pek çok "sorun" sunar ve kapsayıcıya alınmış ortamlarda, tümü iyi belgelenmemiş zorluklar sunar.
  • glog, günlükleri test etmenin kolay bir yolunu sağlamaz, bu da onu kullanan yazılımın kararlılığını azaltır
  • glog C ++ tabanlıdır ve klog saf bir golang uygulamasıdır

Örnek Uygulama

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()
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.