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
}
Файл журнала создается, но ничто никогда не печатается или не добавляется к нему. Почему?
Ответы
Ответ 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)
}
-
импортируйте пакет везде, где вы хотите зарегистрировать файл 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()
}