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
}
ログファイルは作成されますが、何も印刷または追加されません。どうして?
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
になります。
編集
defer f.Close()
をif err != nil
チェックの後に移動しました
ロギングに関する12因子アプリの推奨事項のシンプルさと柔軟性を好みます。ログファイルに追加するには、シェルリダイレクトを使用できます。 Goのデフォルトのロガーは、stderr(2)に書き込みます。
./app 2>> logfile
私は通常、画面にログを印刷し、同様にファイルに書き込みます。これが誰かを助けることを願っています。
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")
これは私のために働く
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()))
}
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 */
}
グローバル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!!!")
}
Linuxマシンでバイナリを実行する場合、シェルスクリプトを使用できます。
ファイルに上書きする
./binaryapp > binaryapp.log
ファイルに追加する
./binaryapp >> binaryapp.log
stderrをファイルに上書きします
./binaryapp &> binaryapp.error.log
ファイルにstderrを追加します
./binaryapp &>> binalyapp.error.log
シェルスクリプトファイルを使用すると、より動的になります。
毎日生成されるファイルにログを書き込みます(1日ごとに1つのログファイルが生成されます)。このアプローチは私のためにうまく機能しています:
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()」メソッドを使用して、フォーマットされたログステートメントを作成します(ファイル名、行番号、ログレベル、エラーステートメントなどを含む)。
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()があります