วิธีการเขียนบันทึกลงไฟล์


108

ฉันกำลังพยายามเขียนลงในล็อกไฟล์ด้วย Go

ฉันได้ลองหลายวิธีซึ่งทั้งหมดล้มเหลว นี่คือสิ่งที่ฉันได้ลอง:

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
}

ไฟล์บันทึกถูกสร้างขึ้น แต่ไม่เคยพิมพ์หรือต่อท้ายไฟล์ใด ๆ ทำไม?


2
หากคุณปรับใช้โปรแกรมของคุณใน Linux คุณสามารถเขียนบันทึกของคุณไปยังเอาต์พุต std จากนั้นไพพ์เอาต์พุตไปยังไฟล์เช่น: ./program 2> & 1 | ที logs.txt ต้องมีวิธีอื่นในระบบอื่น
nvcnvn

คำตอบ:


166

os.Open() ต้องทำงานแตกต่างกันในอดีต แต่สิ่งนี้ใช้ได้กับฉัน:

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 os.Open()ไม่สามารถใช้งานได้log.SetOutputเนื่องจากเปิดไฟล์ "for reading:"

func Open

func Open(name string) (file *File, err error) Openเปิดไฟล์ที่มีชื่อเพื่ออ่าน หากสำเร็จสามารถใช้วิธีการในไฟล์ที่ส่งคืนเพื่ออ่านได้ O_RDONLYอธิบายไฟล์ที่เกี่ยวข้องมีโหมด *PathErrorหากมีข้อผิดพลาดก็จะเป็นประเภท

แก้ไข

ย้ายdefer f.Close()ไปที่ after if err != nilcheck


9
อย่าเลื่อนปิดก่อนตรวจสอบข้อผิดพลาดศูนย์!
Volker

ไม่ใช่กิจกรรมที่เป็นอันตรายต่อการปิดในทุกกรณี iirc นั่นไม่เป็นความจริงสำหรับทุกประเภท
Dustin

2
@Dustin fอาจจะnilซึ่งจะทำให้เสียขวัญ ดังนั้นควรตรวจสอบerrก่อนที่จะเลื่อนการโทรออกไป
nemo

@ AllisonA สนใจที่จะอธิบายว่าทำไมOpenจะไม่ทำงานกับlog.SetOutput?
nemo

1
สิทธิ์ที่ปลอดภัยกว่าคือ 0644 หรือแม้แต่ 0664 เพื่ออนุญาตให้ผู้ใช้อ่าน / เขียนผู้ใช้และกลุ่มอ่าน / เขียนและในทั้งสองกรณีไม่อนุญาตให้ทุกคนเขียน
Jonathan

40

ฉันชอบความเรียบง่ายและความยืดหยุ่นของคำแนะนำแอพ 12 ปัจจัยสำหรับการบันทึก ในการผนวกเข้ากับไฟล์บันทึกคุณสามารถใช้การเปลี่ยนเส้นทางเชลล์ คนตัดไม้เริ่มต้นใน Go เขียนถึง stderr (2)

./app 2>> logfile

ดูเพิ่มเติมที่: http://12factor.net/logs


จะไม่เป็นแนวทางปฏิบัติที่ดีเมื่อคุณต้องการทำให้เกิดสิ่งต่างๆโดยเฉพาะอย่างยิ่งกับ start-tsop-daemon
Shrey

3
@Shrey Systemd สามารถดูแลการบันทึกได้อย่างง่ายดายรวมทั้งเกี่ยวกับฟังก์ชั่น start-stop
WarGasm

แม้ว่านี่จะเป็นแนวทางปฏิบัติที่ดีหรือไม่ก็ตามนี่คือประเภทของการตัดไม้ที่ฉันกำลังมองหาใน Golang ขอบคุณสำหรับการแบ่งปัน!
ติด

มีสิ่งที่คล้ายกันภายใต้หน้าต่างหรือไม่?
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' ฉันไม่ทำงานUbuntu 18.04.3
Ryosuke Hujisawa

21

ฉันมักจะพิมพ์บันทึกบนหน้าจอและเขียนลงในไฟล์ด้วย หวังว่านี่จะช่วยใครบางคนได้

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

สิ่งนี้ใช้ได้กับฉัน

  1. สร้างแพ็คเกจชื่อ logger.go

    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. นำเข้าแพ็คเกจทุกที่ที่คุณต้องการเข้าสู่ระบบเช่น 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 คุณสามารถใช้เชลล์สคริปต์

เขียนทับลงในไฟล์

./binaryapp > binaryapp.log

ผนวกเข้ากับไฟล์

./binaryapp >> binaryapp.log

เขียนทับ stderr ลงในไฟล์

./binaryapp &> binaryapp.error.log

ต่อท้าย stderr ลงในไฟล์

./binaryapp &>> binalyapp.error.log

มันสามารถเป็นแบบไดนามิกมากขึ้นโดยใช้ไฟล์เชลล์สคริปต์


ยินดีที่ได้ทราบเราจะลบล้าง stderr เพื่อบันทึกได้อย่างไร
เป็นไปไม่ได้

5

คนตัดไม้เริ่มต้นใน Go เขียนถึง stderr (2) เปลี่ยนเส้นทางไปยังไฟล์

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

ประกาศขึ้นอันดับต้น ๆ ในโกลบอลของคุณvarเพื่อให้กระบวนการทั้งหมดของคุณสามารถเข้าถึงได้หากจำเป็น

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

เฮ้ @CostaHuang โปรดแสดงความคิดเห็นโดยละเอียด ขอบคุณ
openwonk

@CostaHuang ฉันเพิ่งเรียกใช้ข้อมูลโค้ดและใช้งานได้
openwonk

สวัสดี @openwonk ฉันได้ทดสอบอีกครั้งและมันไม่ทำงานบนคอมพิวเตอร์ของฉัน เวอร์ชันของฉันคือ go version go1.10.2 windows/amd64ของคุณคืออะไร?
Costa Huang

@CostaHuang ฉันเพิ่งวิ่งตัวอย่างกับการตั้งค่าเดียวกับคุณ ตัวอย่างจะถือว่าคุณได้ตั้งค่าโครงสร้างโฟลเดอร์ไว้แล้ว มีวิธีง่ายๆในการตรวจสอบสิ่งนี้อย่างไรก็ตามเป้าหมายของฉันพร้อมตัวอย่างคือการแสดงให้เห็นว่าการเขียนไฟล์บันทึกเป็นเรื่องง่ายเพียงใด เปลี่ยนรหัสของคุณoutfile, _ = os.Create("my.log")และจะทำงานตามที่คาดไว้
openwonk

รหัสของคุณใช้งานได้ ฉันใช้outfile, _ = os.Create("./path/to/my.log"). ฉันคาดหวังว่าโค้ดจะสร้างpath/toโฟลเดอร์และmy.logไฟล์ แต่ดูเหมือนว่ามันใช้ไม่ได้ outfile, _ = os.Create("./my.log")ผมขอแนะนำว่าคุณปรับเปลี่ยนคำตอบของคุณจะเป็น ด้วยวิธีนี้เราจึงทราบได้อย่างชัดเจนว่ากำลังสร้างบันทึกในโฟลเดอร์ปัจจุบัน
Costa Huang

5

จากคำตอบของ Allison และ Deepak ฉันเริ่มใช้ logrus และชอบมันมาก:

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

ฉันมีการเลื่อน f.Close () ในฟังก์ชันหลัก


0

ฉันกำลังเขียนบันทึกลงในไฟล์ซึ่งสร้างขึ้นทุกวัน (ต่อวันจะมีการสร้างไฟล์บันทึกหนึ่งไฟล์) วิธีนี้ใช้ได้ผลดีสำหรับฉัน:

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
}

"shortenFilePath ()" เมธอดที่ใช้รับชื่อไฟล์จากพา ธ เต็มของไฟล์ และเมธอด "LogServer ()" ใช้เพื่อสร้างคำสั่งบันทึกที่จัดรูปแบบ (ประกอบด้วย: ชื่อไฟล์หมายเลขบรรทัดระดับบันทึกคำสั่งข้อผิดพลาด ฯลฯ ... )


0

เพื่อช่วยเหลือผู้อื่นฉันสร้างฟังก์ชันบันทึกพื้นฐานเพื่อจัดการการบันทึกในทั้งสองกรณีหากคุณต้องการให้เอาต์พุตเป็น stdout จากนั้นเปิดการดีบักตรงไปตรงมาเพื่อทำแฟล็กสวิตช์เพื่อให้คุณสามารถเลือกเอาต์พุตได้

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

บางทีนี่อาจช่วยคุณได้ (หากมีไฟล์บันทึกให้ใช้หากไม่มีอยู่ให้สร้างขึ้น):

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

สำหรับรายละเอียดเพิ่มเติม: https://su9.co/9BAE74B

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.