Add logging project

Adds a logging daemon that collects logs in a ring buffer in a runc container.
The tools logwrite and logread can be used to read/write logs. The logging
daemon can be sent open file descriptors that will be read and included
in the logs.

Modifies init to start the daemon and use logwrite to capture logs from runc.

Signed-off-by: Magnus Skjegstad <magnus@skjegstad.com>
This commit is contained in:
Magnus Skjegstad
2017-04-14 11:27:54 +02:00
parent 967819afc0
commit 0511fdb431
22 changed files with 2181 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
package main
import (
"flag"
"fmt"
"io"
"log"
"net"
"os"
"os/exec"
"syscall"
)
func getLogFileSocketPair() (*os.File, int) {
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
panic(err)
}
localFd := fds[0]
remoteFd := fds[1]
localLogFile := os.NewFile(uintptr(localFd), "")
return localLogFile, remoteFd
}
func sendFD(conn *net.UnixConn, remoteAddr *net.UnixAddr, source string, fd int) error {
oobs := syscall.UnixRights(fd)
_, _, err := conn.WriteMsgUnix([]byte(source), oobs, remoteAddr)
return err
}
func main() {
var err error
var ok bool
var serverSocket string
var name string
flag.StringVar(&serverSocket, "socket", "/tmp/memlogd.sock", "socket to pass fd's to memlogd")
flag.StringVar(&name, "n", "", "name of sender, defaults to first argument if left blank")
flag.Parse()
args := flag.Args()
if len(args) < 1 {
log.Fatal("no command specified")
}
if name == "" {
name = args[0]
}
localStdoutLog, remoteStdoutFd := getLogFileSocketPair()
localStderrLog, remoteStderrFd := getLogFileSocketPair()
var outSocket int
if outSocket, err = syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0); err != nil {
log.Fatal("Unable to create socket: ", err)
}
var outFile net.Conn
if outFile, err = net.FileConn(os.NewFile(uintptr(outSocket), "")); err != nil {
log.Fatal(err)
}
var conn *net.UnixConn
if conn, ok = outFile.(*net.UnixConn); !ok {
log.Fatal("Internal error, invalid cast.")
}
raddr := net.UnixAddr{Name: serverSocket, Net: "unixgram"}
if err = sendFD(conn, &raddr, name+".stdout", remoteStdoutFd); err != nil {
log.Fatal("fd stdout send failed: ", err)
}
if err = sendFD(conn, &raddr, name+".stderr", remoteStderrFd); err != nil {
log.Fatal("fd stderr send failed: ", err)
}
cmd := exec.Command(args[0], args[1:]...)
outStderr := io.MultiWriter(localStderrLog, os.Stderr)
outStdout := io.MultiWriter(localStdoutLog, os.Stdout)
cmd.Stderr = outStderr
cmd.Stdout = outStdout
if err = cmd.Run(); err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
// exit with exit code from process
status := exitError.Sys().(syscall.WaitStatus)
os.Exit(status.ExitStatus())
} else {
// no exit code, report error and exit 1
fmt.Println(err)
os.Exit(1)
}
}
}