github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/engine/log_event_writer.go (about) 1 package engine 2 3 import ( 4 "io" 5 "strings" 6 "unicode/utf8" 7 8 "code.cloudfoundry.org/clock" 9 "github.com/pf-qiu/concourse/v6/atc/db" 10 "github.com/pf-qiu/concourse/v6/atc/event" 11 "github.com/pf-qiu/concourse/v6/atc/exec" 12 ) 13 14 func newDBEventWriter(build db.Build, origin event.Origin, clock clock.Clock) io.WriteCloser { 15 return &dbEventWriter{ 16 build: build, 17 origin: origin, 18 clock: clock, 19 } 20 } 21 22 type dbEventWriter struct { 23 build db.Build 24 origin event.Origin 25 clock clock.Clock 26 dangling []byte 27 } 28 29 func (writer *dbEventWriter) Write(data []byte) (int, error) { 30 text := writer.writeDangling(data) 31 if text == nil { 32 return len(data), nil 33 } 34 35 err := writer.saveLog(string(text)) 36 if err != nil { 37 return 0, err 38 } 39 40 return len(data), nil 41 } 42 43 func (writer *dbEventWriter) writeDangling(data []byte) []byte { 44 text := append(writer.dangling, data...) 45 46 checkEncoding, _ := utf8.DecodeLastRune(text) 47 if checkEncoding == utf8.RuneError { 48 writer.dangling = text 49 return nil 50 } 51 52 writer.dangling = nil 53 return text 54 } 55 56 func (writer *dbEventWriter) saveLog(text string) error { 57 return writer.build.SaveEvent(event.Log{ 58 Time: writer.clock.Now().Unix(), 59 Payload: text, 60 Origin: writer.origin, 61 }) 62 } 63 64 func (writer *dbEventWriter) Close() error { 65 return nil 66 } 67 68 func newDBEventWriterWithSecretRedaction(build db.Build, origin event.Origin, clock clock.Clock, filter exec.BuildOutputFilter) io.Writer { 69 return &dbEventWriterWithSecretRedaction{ 70 dbEventWriter: dbEventWriter{ 71 build: build, 72 origin: origin, 73 clock: clock, 74 }, 75 filter: filter, 76 } 77 } 78 79 type dbEventWriterWithSecretRedaction struct { 80 dbEventWriter 81 filter exec.BuildOutputFilter 82 } 83 84 func (writer *dbEventWriterWithSecretRedaction) Write(data []byte) (int, error) { 85 var text []byte 86 87 if data != nil { 88 text = writer.writeDangling(data) 89 if text == nil { 90 return len(data), nil 91 } 92 } else { 93 if writer.dangling == nil || len(writer.dangling) == 0 { 94 return 0, nil 95 } 96 text = writer.dangling 97 } 98 99 payload := string(text) 100 if data != nil { 101 idx := strings.LastIndex(payload, "\n") 102 if idx >= 0 && idx < len(payload) { 103 // Cache content after the last new-line, and proceed contents 104 // before the last new-line. 105 writer.dangling = ([]byte)(payload[idx+1:]) 106 payload = payload[:idx+1] 107 } else { 108 // No new-line found, then cache the log. 109 writer.dangling = text 110 return len(data), nil 111 } 112 } 113 114 payload = writer.filter(payload) 115 err := writer.saveLog(payload) 116 if err != nil { 117 return 0, err 118 } 119 120 return len(data), nil 121 } 122 123 func (writer *dbEventWriterWithSecretRedaction) Close() error { 124 writer.Write(nil) 125 return nil 126 }