J'essaie d'écrire dans un fichier journal avec Golang.
J'ai essayé plusieurs approches, qui ont toutes échoué. C'est ce que j'ai essayé:
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
}
Le fichier journal est créé, mais rien n’est jamais imprimé ou ajouté. Pourquoi?
os.Open()
a dû travailler différemment dans le passé, mais cela fonctionne pour moi:
_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")
_
Selon la documentation Go, os.Open()
ne peut pas fonctionner pour _log.SetOutput
_, car il ouvre le fichier "pour la lecture:"
_
func Open
_
func Open(name string) (file *File, err error)
Open
ouvre le fichier nommé en lecture. En cas de succès, les méthodes du fichier renvoyé peuvent être utilisées pour la lecture. le descripteur de fichier associé a le mode _O_RDONLY
_. S'il y a une erreur, ce sera de type _*PathError
_.
EDIT
Déplacé de defer f.Close()
à après _if err != nil
_ check
Je préfère la simplicité et la flexibilité de la recommandation d'application à 12 facteurs pour la journalisation. Pour ajouter à un fichier journal, vous pouvez utiliser la redirection Shell. L'enregistreur par défaut dans Go écrit sur stderr (2).
./app 2>> logfile
Voir aussi: http://12factor.net/logs
J'imprime généralement les journaux à l'écran et j'écris également dans un fichier. J'espère que ça aide quelqu'un.
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")
Ça marche pour moi
créé un paquet appelé 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)
}
importer le package où vous souhaitez vous connecter, par exemple 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()))
}
L'enregistreur par défaut dans Go écrit sur stderr (2). rediriger vers un fichier
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 */
}
Déclarez en haut dans votre global var
afin que tous vos processus puissent y accéder si nécessaire.
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!!!")
}
Si vous utilisez binaire sur une machine Linux, vous pouvez utiliser le script shell.
écraser dans un fichier
./binaryapp > binaryapp.log
ajouter dans un fichier
./binaryapp >> binaryapp.log
écraser stderr dans un fichier
./binaryapp &> binaryapp.error.log
ajouter stderr dans un fichier
./binaryapp &>> binalyapp.error.log
il peut être plus dynamique en utilisant un fichier de script shell.
J'écris des journaux dans les fichiers, qui sont générés quotidiennement (chaque jour, un fichier journal est généré). Cette approche fonctionne bien pour moi:
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
}
Méthode "shortenFilePath ()" utilisée pour obtenir le nom du fichier à partir du chemin complet du fichier. et la méthode "LogServer ()" est utilisée pour créer une instruction de journal formatée (contient: nom du fichier, numéro de la ligne, niveau du journal, instruction d'erreur etc ...)
En me basant sur la réponse de Allison et Deepak, j'ai commencé à utiliser logrus et je l'aime vraiment:
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)
}
J'ai un différé f.Close () dans la fonction principale