From ec0fe737ec4f78dc68db5f858fa24eb714cab7d8 Mon Sep 17 00:00:00 2001 From: Archit Bansal Date: Thu, 16 Jul 2020 01:08:02 -0700 Subject: [PATCH] Capture the logs from stderr of custom plugins. --- pkg/custompluginmonitor/plugin/plugin.go | 48 ++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/pkg/custompluginmonitor/plugin/plugin.go b/pkg/custompluginmonitor/plugin/plugin.go index 60c7fb8cf..ecf09d9cb 100644 --- a/pkg/custompluginmonitor/plugin/plugin.go +++ b/pkg/custompluginmonitor/plugin/plugin.go @@ -19,6 +19,8 @@ package plugin import ( "context" "fmt" + "io" + "io/ioutil" "os/exec" "strings" "sync" @@ -30,6 +32,10 @@ import ( "k8s.io/node-problem-detector/pkg/util/tomb" ) +// maxCustomPluginBufferBytes is the max bytes that a custom plugin is allowed to +// send to stdout/stderr. Any bytes exceeding this value will be truncated. +const maxCustomPluginBufferBytes = 1024 * 4 + type Plugin struct { config cpmtypes.CustomPluginConfig syncChan chan struct{} @@ -127,14 +133,50 @@ func (p *Plugin) run(rule cpmtypes.CustomRule) (exitStatus cpmtypes.Status, outp defer cancel() cmd := exec.CommandContext(ctx, rule.Path, rule.Args...) - stdout, err := cmd.Output() + + stdoutPipe, err := cmd.StdoutPipe() + if err != nil { + glog.Errorf("Error creating stdout pipe for plugin %q: error - %v", rule.Path, err) + return cpmtypes.Unknown, "Error creating stdout pipe for plugin. Please check the error log" + } + stderrPipe, err := cmd.StderrPipe() + if err != nil { + glog.Errorf("Error creating stderr pipe for plugin %q: error - %v", rule.Path, err) + return cpmtypes.Unknown, "Error creating stderr pipe for plugin. Please check the error log" + } + stdoutReader := io.LimitReader(stdoutPipe, maxCustomPluginBufferBytes) + stderrReader := io.LimitReader(stderrPipe, maxCustomPluginBufferBytes) + + if err := cmd.Start(); err != nil { + glog.Errorf("Error in starting plugin %q: error - %v", rule.Path, err) + return cpmtypes.Unknown, "Error in starting plugin. Please check the error log" + } + + stdout, err := ioutil.ReadAll(stdoutReader) + if err != nil { + glog.Errorf("Error reading stdout for plugin %q: error - %v", rule.Path, err) + return cpmtypes.Unknown, "Error reading stdout for plugin. Please check the error log" + } + + stderr, err := ioutil.ReadAll(stderrReader) if err != nil { + glog.Errorf("Error reading stderr for plugin %q: error - %v", rule.Path, err) + return cpmtypes.Unknown, "Error reading stderr for plugin. Please check the error log" + } + + if err := cmd.Wait(); err != nil { if _, ok := err.(*exec.ExitError); !ok { - glog.Errorf("Error in running plugin %q: error - %v. output - %q", rule.Path, err, string(stdout)) - return cpmtypes.Unknown, "Error in running plugin. Please check the error log" + glog.Errorf("Error in waiting for plugin %q: error - %v. output - %q", rule.Path, err, string(stdout)) + return cpmtypes.Unknown, "Error in waiting for plugin. Please check the error log" } } + // log the stderr from the plugin + if len(stderr) != 0 { + glog.Infof("Start logs from plugin %q \n %s\n", rule.Path, string(stderr)) + glog.Infof("End logs from plugin %q\n", rule.Path) + } + // trim suffix useless bytes output = string(stdout) output = strings.TrimSpace(output)