Günlük dosyaya nasıl yazılır


108

Go ile bir günlük dosyasına yazmaya çalışıyorum.

Hepsi başarısız olan birkaç yaklaşım denedim. Bu denediğim şey:

func TestLogging(t *testing.T) {
    if !FileExists("logfile") {
        CreateFile("logfile")
    }
    f, err := os.Open("logfile")
    if err != nil {
        t.Fatalf("error: %v", err)
    }

    // attempt #1
    log.SetOutput(io.MultiWriter(os.Stderr, f))
    log.Println("hello, logfile")

    // attempt #2
    log.SetOutput(io.Writer(f))
    log.Println("hello, logfile")

    // attempt #3
    log.SetOutput(f)
    log.Println("hello, logfile")
}

func FileExists(name string) bool {
    if _, err := os.Stat(name); err != nil {
       if os.IsNotExist(err) {
            return false
        }
    }
    return true
}

func CreateFile(name string) error {
    fo, err := os.Create(name)
    if err != nil {
        return err
    }
    defer func() {
        fo.Close()
    }()
    return nil
}

Günlük dosyası oluşturulur, ancak hiçbir zaman yazdırılmaz veya üzerine hiçbir şey eklenmez. Neden?


2
Programınızı Linux'ta konuşlandırırsanız, günlüğünüzü std çıktıya yazıp, çıktıyı aşağıdaki gibi bir dosyaya aktarabilirsiniz : ./program 2> & 1 | tee logs.txt . Başka bir sistemde başka bir yol olmalı.
nvcnvn

Yanıtlar:


165

os.Open() geçmişte farklı çalışmış olmalı, ama bu benim için çalışıyor:

f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
if err != nil {
    log.Fatalf("error opening file: %v", err)
}
defer f.Close()

log.SetOutput(f)
log.Println("This is a test log entry")

Go belgelerine göre, "okumak için" dosyasını açtığı için os.Open()çalışamaz.log.SetOutput

func Open

func Open(name string) (file *File, err error) Openadlandırılmış dosyayı okumak için açar. Başarılı olursa, döndürülen dosyadaki yöntemler okumak için kullanılabilir; ilişkili dosya tanımlayıcısının modu vardır O_RDONLY. Bir hata varsa, tipte olacaktır *PathError.

DÜZENLE

Taşındı defer f.Close()sonra hiç if err != nilçek


9
Hatayı sıfır için kontrol etmeden Kapat'ı ertelemeyin!
Volker

Her durumda iirc kapatmak aslında zararlı bir aktivite değildir. Yine de bu her tür için doğru değil.
Dustin

2
@Dustin folabilir nil, bu da paniğe neden olabilir . Bu nedenle err, aramayı ertelemeden önce kontrol etmeniz önerilir.
nemo

@AllisonNeden Openbirlikte çalışmayacağını açıklamaya özen log.SetOutputmi?
nemo

1
Daha güvenli izinler, kullanıcının okuma / yazma, kullanıcı ve grup okuma / yazma izni vermek ve her iki durumda da herkesin yazmasına izin vermemek için 0644 veya hatta 0664'tür.
Jonathan

39

Günlük kaydı için 12 faktörlü uygulama önerisinin basitliğini ve esnekliğini tercih ediyorum. Bir günlük dosyasına eklemek için kabuk yeniden yönlendirmeyi kullanabilirsiniz. Go'daki varsayılan kaydedici stderr (2) 'ye yazar.

./app 2>> logfile

Ayrıca bkz: http://12factor.net/logs


Eğer ESP başlangıç TSOP-cini, Artalanda şeyler istediğinizde iyi bir antrenman olmayacağım
Shrey

3
@Shrey Systemd, başlatma-durdurma işlevlerinin yanı sıra günlüğe kaydetmeyi de kolayca halledebilir.
WarGasm

Bu iyi bir uygulama olsa da olmasa da, bu Golang'da aradığım günlük kaydı türüdür. Bunu paylaştığınız için teşekkürler!
bağımlısı

Pencerelerin altında benzer bir şey var mı?
surfmuggle

$ cd /etc/systemd/system $ sudo vi app.service ExecStart=/bin/bash -c 'sudo go run main.go >> /home/ubuntu/go/src/html_menu_1/logfile' Benim gibi çalışmıyorduUbuntu 18.04.3
Ryosuke Hujisawa

21

Genellikle günlükleri ekrana yazdırıyorum ve bir dosyaya da yazıyorum. Umarım bu birine yardımcı olur.

f, err := os.OpenFile("/tmp/orders.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
    log.Fatalf("error opening file: %v", err)
}
defer f.Close()
wrt := io.MultiWriter(os.Stdout, f)
log.SetOutput(wrt)
log.Println(" Orders API Called")

7

Bu benim için çalışıyor

  1. logger.go adlı bir paket oluşturdu

    package logger
    
    import (
      "flag"
      "os"
      "log"
      "go/build"
    )
    
    var (
      Log      *log.Logger
    )
    
    
    func init() {
        // set location of log file
        var logpath = build.Default.GOPATH + "/src/chat/logger/info.log"
    
       flag.Parse()
       var file, err1 = os.Create(logpath)
    
       if err1 != nil {
          panic(err1)
       }
          Log = log.New(file, "", log.LstdFlags|log.Lshortfile)
          Log.Println("LogFile : " + logpath)
    }
    1. paketi kaydetmek istediğiniz yere içe aktarın, örneğin main.go

      package main
      
      import (
         "logger"
      )
      
      const (
         VERSION = "0.13"
       )
      
      func main() {
      
          // time to use our logger, print version, processID and number of running process
          logger.Log.Printf("Server v%s pid=%d started with processes: %d", VERSION, os.Getpid(),runtime.GOMAXPROCS(runtime.NumCPU()))
      
      }

6

Linux makinesinde ikili çalıştırırsanız, kabuk komut dosyasını kullanabilirsiniz.

bir dosyanın üzerine yaz

./binaryapp > binaryapp.log

bir dosyaya eklemek

./binaryapp >> binaryapp.log

stderr'in üzerine bir dosyaya yaz

./binaryapp &> binaryapp.error.log

stderr'i bir dosyaya eklemek

./binaryapp &>> binalyapp.error.log

kabuk komut dosyası kullanılarak daha dinamik olabilir.


Bilmek güzel, stderr'i günlüğe nasıl yazabiliriz.
imkansız

5

Go'daki varsayılan kaydedici stderr (2) 'ye yazar. dosyaya yeniden yönlendir

import ( 
    "syscall"
    "os" 
 )
func main(){
  fErr, err = os.OpenFile("Errfile", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
  syscall.Dup2(int(fErr.Fd()), 1) /* -- stdout */
  syscall.Dup2(int(fErr.Fd()), 2) /* -- stderr */

}

5

varGerekirse tüm süreçlerinizin erişebilmesi için global olarak en üstte beyan edin .

package main

import (
    "log"
    "os"
)
var (
    outfile, _ = os.Create("path/to/my.log") // update path for your needs
    l      = log.New(outfile, "", 0)
)

func main() {
    l.Println("hello, log!!!")
}

Hey @CostaHuang, lütfen ayrıntılı geri bildirim bırakın. Teşekkürler
openwonk

@CostaHuang, kod pasajımı çalıştırdım ve çalışıyor.
openwonk

Merhaba @openwonk, tekrar test ettim ve bilgisayarımda çalışmadı. Benim versiyonum, go version go1.10.2 windows/amd64seninki nedir?
Costa Huang

@CostaHuang, seninle aynı kurulumla örnek oluşturdum. Örnek, önceden ayarlanmış bir klasör yapınız olduğunu varsayar. Bunu kontrol etmenin kolay yolları var, ancak örnekle amacım bir günlük dosyasına yazmanın ne kadar basit olduğunu göstermektir. Kodunuzu olarak değiştirin outfile, _ = os.Create("my.log")ve beklendiği gibi çalışacaktır.
openwonk

Kodunuz çalışıyor. Kullanıyordum outfile, _ = os.Create("./path/to/my.log"). Her nasılsa, kodun path/toklasörleri ve my.logdosyayı oluşturacağı beklentisine sahiptim , ancak görünüşe göre işe yaramadı. Cevabınızı olarak değiştirmenizi öneririm outfile, _ = os.Create("./my.log"). Bu şekilde, mevcut klasörde bir günlük oluşturduğunu açıkça biliyoruz.
Costa Huang

5

Allison ve Deepak'ın cevabına dayanarak, logrus kullanmaya başladım ve gerçekten beğendim:

var log = logrus.New()

func init() {

    // log to console and file
    f, err := os.OpenFile("crawler.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        log.Fatalf("error opening file: %v", err)
    }
    wrt := io.MultiWriter(os.Stdout, f)

    log.SetOutput(wrt)
}

Ana işlevde bir erteleme f.Close () var


0

Günlük olarak oluşturulan dosyalara günlükler yazıyorum (her gün bir günlük dosyası oluşturuluyor). Bu yaklaşım benim için iyi çalışıyor:

var (
    serverLogger *log.Logger
)

func init() {
    // set location of log file
    date := time.Now().Format("2006-01-02")
    var logpath = os.Getenv(constant.XDirectoryPath) + constant.LogFilePath + date + constant.LogFileExtension
    os.MkdirAll(os.Getenv(constant.XDirectoryPath)+constant.LogFilePath, os.ModePerm)
    flag.Parse()
    var file, err1 = os.OpenFile(logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)

    if err1 != nil {
        panic(err1)
    }
    mw := io.MultiWriter(os.Stdout, file)
    serverLogger = log.New(mw, constant.Empty, log.LstdFlags)
    serverLogger.Println("LogFile : " + logpath)
}

// LogServer logs to server's log file
func LogServer(logLevel enum.LogLevel, message string) {
    _, file, no, ok := runtime.Caller(1)
    logLineData := "logger_server.go"
    if ok {
        file = shortenFilePath(file)
        logLineData = fmt.Sprintf(file + constant.ColonWithSpace + strconv.Itoa(no) + constant.HyphenWithSpace)
    }
    serverLogger.Println(logLineData + logLevel.String() + constant.HyphenWithSpace + message)
}

// ShortenFilePath Shortens file path to a/b/c/d.go tp d.go
func shortenFilePath(file string) string {
    short := file
    for i := len(file) - 1; i > 0; i-- {
        if file[i] == constant.ForwardSlash {
            short = file[i+1:]
            break
        }
    }
    file = short
    return file
}

Dosyanın adını dosyanın tam yolundan almak için kullanılan "shortenFilePath ()" yöntemi. ve "LogServer ()" yöntemi, biçimlendirilmiş bir günlük ifadesi oluşturmak için kullanılır (içerir: dosya adı, satır numarası, günlük seviyesi, hata ifadesi vb.)


0

Başkalarına yardımcı olmak için, her iki durumda da günlük kaydını işlemek için temel bir günlük işlevi oluşturuyorum, eğer çıktının stdout olmasını istiyorsanız, ardından hata ayıklamayı açın, bu, çıktınızı seçebilmeniz için bir anahtar bayrağı yapmak basittir.

func myLog(msg ...interface{}) {
    defer func() { r := recover(); if r != nil { fmt.Print("Error detected logging:", r) } }()
    if conf.DEBUG {
        fmt.Println(msg)
    } else {
        logfile, err := os.OpenFile(conf.LOGDIR+"/"+conf.AppName+".log", os.O_RDWR | os.O_CREATE | os.O_APPEND,0666)
        if !checkErr(err) {
            log.SetOutput(logfile)
            log.Println(msg)
        }
        defer logfile.Close()
    }
}




0

belki bu size yardımcı olabilir (günlük dosyası varsa kullanın, yoksa oluşturun):

package main

import (
    "flag"
    "log"
    "os"
)
//Se declara la variable Log. Esta será usada para registrar los eventos.
var (
    Log *log.Logger = Loggerx()
)

func Loggerx() *log.Logger {
    LOG_FILE_LOCATION := os.Getenv("LOG_FILE_LOCATION")
        //En el caso que la variable de entorno exista, el sistema usa la configuración del docker.
    if LOG_FILE_LOCATION == "" {
        LOG_FILE_LOCATION = "../logs/" + APP_NAME + ".log"
    } else {
        LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + ".log"
    }
    flag.Parse()
        //Si el archivo existe se rehusa, es decir, no elimina el archivo log y crea uno nuevo.
    if _, err := os.Stat(LOG_FILE_LOCATION); os.IsNotExist(err) {
        file, err1 := os.Create(LOG_FILE_LOCATION)
        if err1 != nil {
            panic(err1)
        }
                //si no existe,se crea uno nuevo.
        return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
    } else {
                //si existe se rehusa.
        file, err := os.OpenFile(LOG_FILE_LOCATION, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
        if err != nil {
            panic(err)
        }
        return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
    }
}

Daha fazla ayrıntı için: https://su9.co/9BAE74B

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.