Подтвердить что ты не робот

Go/Golang записывать журнал в файл

Я пытаюсь записать в файл журнала с помощью Golang.

Я пробовал несколько подходов, все из которых потерпели неудачу. Это то, что я пробовал:

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
}

Файл журнала создается, но ничто никогда не печатается или не добавляется к нему. Почему?

4b9b3361

Ответ 1

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, потому что он открывает файл "для чтения:"

func Open

func Open(name string) (file *File, err error) Open открывает именованный файл для чтения. В случае успеха методы на возвращаемом файле могут быть используется для чтения; соответствующий дескриптор файла имеет режим O_RDONLY. Если есть ошибка, она будет иметь тип *PathError.

EDIT

defer f.Close() перемещен в после проверки if err != nil

Ответ 2

Я предпочитаю простоту и гибкость рекомендации по приложению для 12 факторов для ведения журнала. Чтобы добавить файл журнала, вы можете использовать перенаправление оболочки. Регистратор по умолчанию в Go записывает в stderr (2).

./app 2>> logfile

Смотрите также: http://12factor.net/logs

Ответ 3

Я обычно печатаю журналы на экране и записываю в файл. Надеюсь, это кому-нибудь поможет.

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

Ответ 4

Это работает для меня

  • создал пакет с именем 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()))
      
      }
      

Ответ 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 */

}

Ответ 6

Объявите верхушку в своем глобальном 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!!!")
}

Ответ 7

Если вы запускаете бинарный файл на машине с Linux, вы можете использовать скрипт оболочки.

переписать в файл

./binaryapp > binaryapp.log

добавить в файл

./binaryapp >> binaryapp.log

перезаписать stderr в файл

./binaryapp &> binaryapp.error.log

добавить stderr в файл

./binaryapp &>> binalyapp.error.log

это может быть более динамичным с использованием файла сценария оболочки.

Ответ 8

Я пишу журналы в файлы, которые генерируются ежедневно (в день генерируется один файл журнала). Этот подход хорошо работает для меня:

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

Метод "shorttenFilePath()", используемый для получения имени файла из полного пути к файлу. и метод "LogServer()" используется для создания отформатированного оператора журнала (содержит: имя файла, номер строки, уровень журнала, оператор ошибки и т.д.)

Ответ 9

Основываясь на ответах Эллисон и Дипак, я начал использовать 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() в основной функции

Ответ 10

import (
    "os/exec"
)

func main() {
    // check error here...
    exec.Command("/bin/sh", "-c", "echo "+err.Error()+" >> log.log").Run()
}