8363: Save matching arv-mount log line in warningDetail.
authorTom Clegg <tom@curii.com>
Wed, 22 Sep 2021 19:34:15 +0000 (15:34 -0400)
committerTom Clegg <tom@curii.com>
Wed, 22 Sep 2021 19:34:15 +0000 (15:34 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/crunchrun/crunchrun.go
lib/crunchrun/crunchrun_test.go
lib/crunchrun/logscanner.go
lib/crunchrun/logscanner_test.go

index 4dd953a3a480a0cde374a3c60cb7a63f03c1ee14..ad4953214de6f722d9cacd244d651f0aa52c28cf 100644 (file)
@@ -1109,12 +1109,13 @@ func (runner *ContainerRunner) updateLogs() {
        }
 }
 
-func (runner *ContainerRunner) reportArvMountWarning(message string) {
+func (runner *ContainerRunner) reportArvMountWarning(pattern, text string) {
        var updated arvados.Container
        err := runner.DispatcherArvClient.Update("containers", runner.Container.UUID, arvadosclient.Dict{
                "container": arvadosclient.Dict{
                        "runtime_status": arvadosclient.Dict{
-                               "warning": "arv-mount: " + message,
+                               "warning":       "arv-mount: " + pattern,
+                               "warningDetail": text,
                        },
                },
        }, &updated)
index 53e1bed8396c892a2fd90a3cf18410d6e3e7e2c2..17f775bb81e93585d4d535f10cf49b2cff476cc4 100644 (file)
@@ -1537,7 +1537,7 @@ func (s *TestSuite) TestArvMountRuntimeStatusWarning(c *C) {
        s.runner.RunArvMount = func([]string, string) (*exec.Cmd, error) {
                os.Mkdir(s.runner.ArvMountPoint+"/by_id", 0666)
                ioutil.WriteFile(s.runner.ArvMountPoint+"/by_id/README", nil, 0666)
-               return s.runner.ArvMountCmd([]string{"bash", "-c", "echo >&2 $(date) Keep write error: I am a teapot; sleep 3"}, "")
+               return s.runner.ArvMountCmd([]string{"bash", "-c", "echo >&2 Test: Keep write error: I am a teapot; sleep 3"}, "")
        }
        s.executor.runFunc = func() {
                time.Sleep(time.Second)
@@ -1560,6 +1560,7 @@ func (s *TestSuite) TestArvMountRuntimeStatusWarning(c *C) {
        c.Assert(err, IsNil)
        c.Check(s.api.CalledWith("container.exit_code", 0), NotNil)
        c.Check(s.api.CalledWith("container.runtime_status.warning", "arv-mount: Keep write error"), NotNil)
+       c.Check(s.api.CalledWith("container.runtime_status.warningDetail", "Test: Keep write error: I am a teapot"), NotNil)
        c.Check(s.api.CalledWith("container.state", "Complete"), NotNil)
 }
 
index 9cf60b62bbc849784cd93e8d80c1be310659eae0..aa0a8347ed32ecd2393cb80f1a90e8253ef2e3d9 100644 (file)
@@ -14,7 +14,7 @@ import (
 // contain newlines.
 type logScanner struct {
        Patterns   []string
-       ReportFunc func(string)
+       ReportFunc func(pattern, text string)
        reported   bool
        buf        bytes.Buffer
 }
@@ -32,8 +32,14 @@ func (s *logScanner) Write(p []byte) (int, error) {
        s.buf.Write(p[:split+1])
        txt := s.buf.String()
        for _, pattern := range s.Patterns {
-               if strings.Contains(txt, pattern) {
-                       s.ReportFunc(pattern)
+               if found := strings.Index(txt, pattern); found >= 0 {
+                       // Report the entire line where the pattern
+                       // was found.
+                       txt = txt[strings.LastIndexByte(txt[:found], '\n')+1:]
+                       if end := strings.IndexByte(txt, '\n'); end >= 0 {
+                               txt = txt[:end]
+                       }
+                       s.ReportFunc(pattern, txt)
                        s.reported = true
                        return len(p), nil
                }
index 26b128193a3a172b946c278b95a29f93f1189a94..f6b4ba3adcec1d055a7ec0135367e71905a6f384 100644 (file)
@@ -17,12 +17,40 @@ func (s *logScannerSuite) TestCallReportFuncOnce(c *check.C) {
        var reported []string
        ls := logScanner{
                Patterns: []string{"foobar", "barbaz"},
-               ReportFunc: func(pattern string) {
-                       reported = append(reported, pattern)
+               ReportFunc: func(pattern, detail string) {
+                       reported = append(reported, pattern, detail)
                },
        }
-       ls.Write([]byte("foo\nbar\nbar"))
-       ls.Write([]byte("baz\nwaz\nqux"))
+       ls.Write([]byte("foo\nbar\n2021-01-01T00:00:00.000Z: bar"))
+       ls.Write([]byte("baz: it's a detail\nwaz\nqux"))
        ls.Write([]byte("\nfoobar\n"))
-       c.Check(reported, check.DeepEquals, []string{"barbaz"})
+       c.Check(reported, check.DeepEquals, []string{"barbaz", "2021-01-01T00:00:00.000Z: barbaz: it's a detail"})
+}
+
+func (s *logScannerSuite) TestOneWritePerLine(c *check.C) {
+       var reported []string
+       ls := logScanner{
+               Patterns: []string{"barbaz"},
+               ReportFunc: func(pattern, detail string) {
+                       reported = append(reported, pattern, detail)
+               },
+       }
+       ls.Write([]byte("foo\n"))
+       ls.Write([]byte("2021-01-01T00:00:00.000Z: barbaz: it's a detail\n"))
+       ls.Write([]byte("waz\n"))
+       c.Check(reported, check.DeepEquals, []string{"barbaz", "2021-01-01T00:00:00.000Z: barbaz: it's a detail"})
+}
+
+func (s *logScannerSuite) TestNoDetail(c *check.C) {
+       var reported []string
+       ls := logScanner{
+               Patterns: []string{"barbaz"},
+               ReportFunc: func(pattern, detail string) {
+                       reported = append(reported, pattern, detail)
+               },
+       }
+       ls.Write([]byte("foo\n"))
+       ls.Write([]byte("barbaz\n"))
+       ls.Write([]byte("waz\n"))
+       c.Check(reported, check.DeepEquals, []string{"barbaz", "barbaz"})
 }