파일에 로그를 쓰는 방법


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 | tee logs.txt . 다른 시스템에는 다른 방법이 있어야합니다.
nvcnvn 2013

답변:


165

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읽기 위해 명명 된 파일을 엽니 다. 성공하면 반환 된 파일의 메서드를 사용하여 읽을 수 있습니다. 연관된 파일 설명자에는 mode가 있습니다 O_RDONLY. 오류가있는 경우 유형이 *PathError됩니다.

편집하다

확인 defer f.Close()후 이동if err != nil


9
nil에 대한 err을 확인하기 전에 Close를 연기하지 마십시오!
Volker 2013

모든 경우 iirc를 닫는 것이 실제로 해로운 활동은 아닙니다. 하지만 모든 유형에 해당되는 것은 아닙니다.
Dustin 2013

2
@Dustin f은 일 수 있으며 nil이로 인해 패닉이 발생할 수 있습니다 . 따라서 err통화를 연기하기 전에 확인하는 것이 좋습니다.
nemo 2013

@AllisonA 관심이 왜 Open작동하지 log.SetOutput않을까요?
nemo

1
더 안전한 권한은 사용자 읽기 / 쓰기, 사용자 및 그룹 읽기 / 쓰기를 허용하는 0644 또는 0664이며 두 경우 모두 모든 사람이 쓰기를 허용하지 않습니다.
Jonathan

39

로깅을위한 12 단계 앱 권장 사항의 단순성과 유연성을 선호합니다. 로그 파일에 추가하려면 셸 리디렉션을 사용할 수 있습니다. Go의 기본 로거는 stderr (2)에 기록합니다.

./app 2>> logfile

참조 : http://12factor.net/logs


당신이 ESP 시작 TSOP-데몬, 데몬으로 일을 할 때 좋은 연습이 될 실 거예요
Shrey

3
@Shrey Systemd는 로깅 및 시작-중지 기능을 쉽게 처리 할 수 ​​있습니다.
WarGasm

이것이 좋은 관행인지 아닌지에도 불구하고 이것이 내가 Golang에서 찾고 있던 로깅 유형입니다. 공유 해주셔서 감사합니다!
중독 됨

창문 아래에 비슷한 것이 있습니까?
surfmuggle 19 년

$ 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
않았다

20

나는 보통 화면에 로그를 인쇄하고 파일에도 씁니다. 이것이 누군가를 돕기를 바랍니다.

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

리눅스 머신에서 바이너리를 실행한다면 쉘 스크립트를 사용할 수 있습니다.

파일로 덮어 쓰기

./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.