runc/libcontainer/logs/logs.go

103 lines
2.2 KiB
Go

package logs
import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
"strconv"
"sync"
"github.com/sirupsen/logrus"
)
var (
configureMutex = sync.Mutex{}
// loggingConfigured will be set once logging has been configured via invoking `ConfigureLogging`.
// Subsequent invocations of `ConfigureLogging` would be no-op
loggingConfigured = false
)
type Config struct {
LogLevel logrus.Level
LogFormat string
LogFilePath string
LogPipeFd string
}
func ForwardLogs(logPipe io.Reader) {
lineReader := bufio.NewReader(logPipe)
for {
line, err := lineReader.ReadBytes('\n')
if len(line) > 0 {
processEntry(line)
}
if err == io.EOF {
logrus.Debugf("log pipe has been closed: %+v", err)
return
}
if err != nil {
logrus.Errorf("log pipe read error: %+v", err)
}
}
}
func processEntry(text []byte) {
type jsonLog struct {
Level string `json:"level"`
Msg string `json:"msg"`
}
var jl jsonLog
if err := json.Unmarshal(text, &jl); err != nil {
logrus.Errorf("failed to decode %q to json: %+v", text, err)
return
}
lvl, err := logrus.ParseLevel(jl.Level)
if err != nil {
logrus.Errorf("failed to parse log level %q: %v\n", jl.Level, err)
return
}
logrus.StandardLogger().Logf(lvl, jl.Msg)
}
func ConfigureLogging(config Config) error {
configureMutex.Lock()
defer configureMutex.Unlock()
if loggingConfigured {
logrus.Debug("logging has already been configured")
return nil
}
logrus.SetLevel(config.LogLevel)
if config.LogPipeFd != "" {
logPipeFdInt, err := strconv.Atoi(config.LogPipeFd)
if err != nil {
return fmt.Errorf("failed to convert _LIBCONTAINER_LOGPIPE environment variable value %q to int: %v", config.LogPipeFd, err)
}
logrus.SetOutput(os.NewFile(uintptr(logPipeFdInt), "logpipe"))
} else if config.LogFilePath != "" {
f, err := os.OpenFile(config.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0644)
if err != nil {
return err
}
logrus.SetOutput(f)
}
switch config.LogFormat {
case "text":
// retain logrus's default.
case "json":
logrus.SetFormatter(new(logrus.JSONFormatter))
default:
return fmt.Errorf("unknown log-format %q", config.LogFormat)
}
loggingConfigured = true
return nil
}