-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP - Support for logging from children processes #1861
Conversation
Add support for children processes logging (including nsexec). A pipe is used to send logs from children to parent in JSON. The JSON format used is the same used by logrus JSON formatted, i.e. children process can use standard logrus APIs. Signed-off-by: Marco Vedovati <[email protected]>
Pipe close before exec is not necessary as os.Pipe() is calling pipe2 with O_CLOEXEC option. Signed-off-by: Marco Vedovati <[email protected]>
libcontainer/standard_init_linux.go
Outdated
@@ -187,6 +188,10 @@ func (l *linuxStandardInit) Init() error { | |||
return newSystemErrorWithCause(err, "init seccomp") | |||
} | |||
} | |||
|
|||
logPipe, _ := (logrus.StandardLogger().Out).(*(os.File)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three things:
-
I'm not sure it's necessary to do
(a).(*os.File)
-- I thinka.(*os.File)
will work just as fine (andgofmt
should complain at you because it's not idiomatic). -
You shouldn't ignore the
ok
value here. Even if it is impossible to occur, you should either make it panic or you should check thatlogPipe != nil
(which is the error case -- because that would also panic). -
Also we should probably set
logPipe
to beO_CLOEXEC
which would remove the requirement to close it like this.
if err != nil { | ||
return nil, newSystemErrorWithCause(err, "creating new command template") | ||
} | ||
if !p.Init { | ||
return c.newSetnsProcess(p, cmd, parentPipe, childPipe) | ||
return c.newSetnsProcess(p, cmd, parentPipe, childPipe, &logPipe) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels unnecessary to pass a reference here -- since the members are pointers there's no real risk of accidentally copying something. The later *logPipe
just makes it look confusing.
@@ -448,10 +456,10 @@ func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) { | |||
if err := c.includeExecFifo(cmd); err != nil { | |||
return nil, newSystemErrorWithCause(err, "including execfifo in cmd.Exec setup") | |||
} | |||
return c.newInitProcess(p, cmd, parentPipe, childPipe) | |||
return c.newInitProcess(p, cmd, parentPipe, childPipe, &logPipe) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto on the &logPipe
comment here too.
logrus.WarnLevel: logrus.Warn, | ||
logrus.InfoLevel: logrus.Info, | ||
logrus.DebugLevel: logrus.Debug, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit ugly, but it looks like logrus
gives us no choice (you can't call Entry.log
with an explicit level -- it even looks like there's a race condition in the level check inside logrus
!). (Not an actionable complaint, just something I noticed.)
"{\"level\":\"%s\", \"msg\": \"", strlevel[level]); | ||
|
||
va_start(args, format); | ||
len += vsnprintf(&jsonbuffer[len], sizeof(jsonbuffer) - len, format, args); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While not an immediate issue, this does mean that we cannot deal with "
(or any special characters) inside of the JSON string. Hopefully we won't hit that problem, but it is something to keep in mind.
@@ -138,6 +138,12 @@ func main() { | |||
updateCommand, | |||
} | |||
app.Before = func(context *cli.Context) error { | |||
|
|||
// do nothing if logrus was already initialized in init.go | |||
if logrus.StandardLogger().Out != logrus.New().Out { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really a fan of this -- why not set up logging for init
here (or setting a global flag) rather than doing it this way?
@@ -43,12 +43,20 @@ type parentProcess interface { | |||
externalDescriptors() []string | |||
|
|||
setExternalDescriptors(fds []string) | |||
|
|||
getChildLogs() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really like this name -- maybe forwardChildLogs
or proxyChildLogs
to make it clear that this method actually pipes directly to logrus.
Add support for children processes logging (including nsexec).
A pipe is used to send logs from children to parent in JSON.
The JSON format used is the same used by logrus JSON formatted,
i.e. children process can use standard logrus APIs.
This improves debugging and can also be used to report warning messages from the children.