xref: /aosp_15_r20/build/soong/ui/status/log.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage status
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"compress/gzip"
19*333d2b36SAndroid Build Coastguard Worker	"errors"
20*333d2b36SAndroid Build Coastguard Worker	"fmt"
21*333d2b36SAndroid Build Coastguard Worker	"io"
22*333d2b36SAndroid Build Coastguard Worker	"io/ioutil"
23*333d2b36SAndroid Build Coastguard Worker	"os"
24*333d2b36SAndroid Build Coastguard Worker	"strings"
25*333d2b36SAndroid Build Coastguard Worker	"sync"
26*333d2b36SAndroid Build Coastguard Worker	"time"
27*333d2b36SAndroid Build Coastguard Worker
28*333d2b36SAndroid Build Coastguard Worker	"google.golang.org/protobuf/proto"
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Worker	"android/soong/ui/logger"
31*333d2b36SAndroid Build Coastguard Worker	soong_build_error_proto "android/soong/ui/status/build_error_proto"
32*333d2b36SAndroid Build Coastguard Worker	soong_build_progress_proto "android/soong/ui/status/build_progress_proto"
33*333d2b36SAndroid Build Coastguard Worker)
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Workertype verboseLog struct {
36*333d2b36SAndroid Build Coastguard Worker	w    *gzip.Writer
37*333d2b36SAndroid Build Coastguard Worker	lock *sync.Mutex
38*333d2b36SAndroid Build Coastguard Worker	data chan []string
39*333d2b36SAndroid Build Coastguard Worker	stop chan bool
40*333d2b36SAndroid Build Coastguard Worker}
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Workerfunc NewVerboseLog(log logger.Logger, filename string) StatusOutput {
43*333d2b36SAndroid Build Coastguard Worker	if !strings.HasSuffix(filename, ".gz") {
44*333d2b36SAndroid Build Coastguard Worker		filename += ".gz"
45*333d2b36SAndroid Build Coastguard Worker	}
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker	f, err := logger.CreateFileWithRotation(filename, 5)
48*333d2b36SAndroid Build Coastguard Worker	if err != nil {
49*333d2b36SAndroid Build Coastguard Worker		log.Println("Failed to create verbose log file:", err)
50*333d2b36SAndroid Build Coastguard Worker		return nil
51*333d2b36SAndroid Build Coastguard Worker	}
52*333d2b36SAndroid Build Coastguard Worker
53*333d2b36SAndroid Build Coastguard Worker	w := gzip.NewWriter(f)
54*333d2b36SAndroid Build Coastguard Worker
55*333d2b36SAndroid Build Coastguard Worker	l := &verboseLog{
56*333d2b36SAndroid Build Coastguard Worker		w:    w,
57*333d2b36SAndroid Build Coastguard Worker		lock: &sync.Mutex{},
58*333d2b36SAndroid Build Coastguard Worker		data: make(chan []string),
59*333d2b36SAndroid Build Coastguard Worker		stop: make(chan bool),
60*333d2b36SAndroid Build Coastguard Worker	}
61*333d2b36SAndroid Build Coastguard Worker	l.startWriter()
62*333d2b36SAndroid Build Coastguard Worker	return l
63*333d2b36SAndroid Build Coastguard Worker}
64*333d2b36SAndroid Build Coastguard Worker
65*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) startWriter() {
66*333d2b36SAndroid Build Coastguard Worker	go func() {
67*333d2b36SAndroid Build Coastguard Worker		tick := time.Tick(time.Second)
68*333d2b36SAndroid Build Coastguard Worker		for {
69*333d2b36SAndroid Build Coastguard Worker			select {
70*333d2b36SAndroid Build Coastguard Worker			case <-v.stop:
71*333d2b36SAndroid Build Coastguard Worker				close(v.data)
72*333d2b36SAndroid Build Coastguard Worker				v.w.Close()
73*333d2b36SAndroid Build Coastguard Worker				return
74*333d2b36SAndroid Build Coastguard Worker			case <-tick:
75*333d2b36SAndroid Build Coastguard Worker				v.w.Flush()
76*333d2b36SAndroid Build Coastguard Worker			case dataList := <-v.data:
77*333d2b36SAndroid Build Coastguard Worker				for _, data := range dataList {
78*333d2b36SAndroid Build Coastguard Worker					fmt.Fprint(v.w, data)
79*333d2b36SAndroid Build Coastguard Worker				}
80*333d2b36SAndroid Build Coastguard Worker			}
81*333d2b36SAndroid Build Coastguard Worker		}
82*333d2b36SAndroid Build Coastguard Worker	}()
83*333d2b36SAndroid Build Coastguard Worker}
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) stopWriter() {
86*333d2b36SAndroid Build Coastguard Worker	v.stop <- true
87*333d2b36SAndroid Build Coastguard Worker}
88*333d2b36SAndroid Build Coastguard Worker
89*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) queueWrite(s ...string) {
90*333d2b36SAndroid Build Coastguard Worker	v.data <- s
91*333d2b36SAndroid Build Coastguard Worker}
92*333d2b36SAndroid Build Coastguard Worker
93*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) StartAction(action *Action, counts Counts) {}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) FinishAction(result ActionResult, counts Counts) {
96*333d2b36SAndroid Build Coastguard Worker	cmd := result.Command
97*333d2b36SAndroid Build Coastguard Worker	if cmd == "" {
98*333d2b36SAndroid Build Coastguard Worker		cmd = result.Description
99*333d2b36SAndroid Build Coastguard Worker	}
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Worker	v.queueWrite(fmt.Sprintf("[%d/%d] ", counts.FinishedActions, counts.TotalActions), cmd, "\n")
102*333d2b36SAndroid Build Coastguard Worker
103*333d2b36SAndroid Build Coastguard Worker	if result.Error != nil {
104*333d2b36SAndroid Build Coastguard Worker		v.queueWrite("FAILED: ", strings.Join(result.Outputs, " "), "\n")
105*333d2b36SAndroid Build Coastguard Worker	}
106*333d2b36SAndroid Build Coastguard Worker
107*333d2b36SAndroid Build Coastguard Worker	if result.Output != "" {
108*333d2b36SAndroid Build Coastguard Worker		v.queueWrite(result.Output, "\n")
109*333d2b36SAndroid Build Coastguard Worker	}
110*333d2b36SAndroid Build Coastguard Worker}
111*333d2b36SAndroid Build Coastguard Worker
112*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) Flush() {
113*333d2b36SAndroid Build Coastguard Worker	v.stopWriter()
114*333d2b36SAndroid Build Coastguard Worker}
115*333d2b36SAndroid Build Coastguard Worker
116*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) Message(level MsgLevel, message string) {
117*333d2b36SAndroid Build Coastguard Worker	v.queueWrite(level.Prefix(), message, "\n")
118*333d2b36SAndroid Build Coastguard Worker}
119*333d2b36SAndroid Build Coastguard Worker
120*333d2b36SAndroid Build Coastguard Workerfunc (v *verboseLog) Write(p []byte) (int, error) {
121*333d2b36SAndroid Build Coastguard Worker	v.queueWrite(string(p))
122*333d2b36SAndroid Build Coastguard Worker	return len(p), nil
123*333d2b36SAndroid Build Coastguard Worker}
124*333d2b36SAndroid Build Coastguard Worker
125*333d2b36SAndroid Build Coastguard Workertype errorLog struct {
126*333d2b36SAndroid Build Coastguard Worker	w     io.WriteCloser
127*333d2b36SAndroid Build Coastguard Worker	empty bool
128*333d2b36SAndroid Build Coastguard Worker}
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Workerfunc NewErrorLog(log logger.Logger, filename string) StatusOutput {
131*333d2b36SAndroid Build Coastguard Worker	f, err := logger.CreateFileWithRotation(filename, 5)
132*333d2b36SAndroid Build Coastguard Worker	if err != nil {
133*333d2b36SAndroid Build Coastguard Worker		log.Println("Failed to create error log file:", err)
134*333d2b36SAndroid Build Coastguard Worker		return nil
135*333d2b36SAndroid Build Coastguard Worker	}
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Worker	return &errorLog{
138*333d2b36SAndroid Build Coastguard Worker		w:     f,
139*333d2b36SAndroid Build Coastguard Worker		empty: true,
140*333d2b36SAndroid Build Coastguard Worker	}
141*333d2b36SAndroid Build Coastguard Worker}
142*333d2b36SAndroid Build Coastguard Worker
143*333d2b36SAndroid Build Coastguard Workerfunc (e *errorLog) StartAction(action *Action, counts Counts) {}
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Workerfunc (e *errorLog) FinishAction(result ActionResult, counts Counts) {
146*333d2b36SAndroid Build Coastguard Worker	if result.Error == nil {
147*333d2b36SAndroid Build Coastguard Worker		return
148*333d2b36SAndroid Build Coastguard Worker	}
149*333d2b36SAndroid Build Coastguard Worker
150*333d2b36SAndroid Build Coastguard Worker	if !e.empty {
151*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(e.w, "\n\n")
152*333d2b36SAndroid Build Coastguard Worker	}
153*333d2b36SAndroid Build Coastguard Worker	e.empty = false
154*333d2b36SAndroid Build Coastguard Worker
155*333d2b36SAndroid Build Coastguard Worker	fmt.Fprintf(e.w, "FAILED: %s\n", result.Description)
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard Worker	if len(result.Outputs) > 0 {
158*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(e.w, "Outputs: %s\n", strings.Join(result.Outputs, " "))
159*333d2b36SAndroid Build Coastguard Worker	}
160*333d2b36SAndroid Build Coastguard Worker
161*333d2b36SAndroid Build Coastguard Worker	fmt.Fprintf(e.w, "Error: %s\n", result.Error)
162*333d2b36SAndroid Build Coastguard Worker	if result.Command != "" {
163*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(e.w, "Command: %s\n", result.Command)
164*333d2b36SAndroid Build Coastguard Worker	}
165*333d2b36SAndroid Build Coastguard Worker	fmt.Fprintf(e.w, "Output:\n%s\n", result.Output)
166*333d2b36SAndroid Build Coastguard Worker}
167*333d2b36SAndroid Build Coastguard Worker
168*333d2b36SAndroid Build Coastguard Workerfunc (e *errorLog) Flush() {
169*333d2b36SAndroid Build Coastguard Worker	e.w.Close()
170*333d2b36SAndroid Build Coastguard Worker}
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Workerfunc (e *errorLog) Message(level MsgLevel, message string) {
173*333d2b36SAndroid Build Coastguard Worker	if level < ErrorLvl {
174*333d2b36SAndroid Build Coastguard Worker		return
175*333d2b36SAndroid Build Coastguard Worker	}
176*333d2b36SAndroid Build Coastguard Worker
177*333d2b36SAndroid Build Coastguard Worker	if !e.empty {
178*333d2b36SAndroid Build Coastguard Worker		fmt.Fprintf(e.w, "\n\n")
179*333d2b36SAndroid Build Coastguard Worker	}
180*333d2b36SAndroid Build Coastguard Worker	e.empty = false
181*333d2b36SAndroid Build Coastguard Worker
182*333d2b36SAndroid Build Coastguard Worker	fmt.Fprintf(e.w, "error: %s\n", message)
183*333d2b36SAndroid Build Coastguard Worker}
184*333d2b36SAndroid Build Coastguard Worker
185*333d2b36SAndroid Build Coastguard Workerfunc (e *errorLog) Write(p []byte) (int, error) {
186*333d2b36SAndroid Build Coastguard Worker	fmt.Fprint(e.w, string(p))
187*333d2b36SAndroid Build Coastguard Worker	return len(p), nil
188*333d2b36SAndroid Build Coastguard Worker}
189*333d2b36SAndroid Build Coastguard Worker
190*333d2b36SAndroid Build Coastguard Workertype errorProtoLog struct {
191*333d2b36SAndroid Build Coastguard Worker	errorProto soong_build_error_proto.BuildError
192*333d2b36SAndroid Build Coastguard Worker	filename   string
193*333d2b36SAndroid Build Coastguard Worker	log        logger.Logger
194*333d2b36SAndroid Build Coastguard Worker}
195*333d2b36SAndroid Build Coastguard Worker
196*333d2b36SAndroid Build Coastguard Workerfunc NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
197*333d2b36SAndroid Build Coastguard Worker	os.Remove(filename)
198*333d2b36SAndroid Build Coastguard Worker	return &errorProtoLog{
199*333d2b36SAndroid Build Coastguard Worker		errorProto: soong_build_error_proto.BuildError{},
200*333d2b36SAndroid Build Coastguard Worker		filename:   filename,
201*333d2b36SAndroid Build Coastguard Worker		log:        log,
202*333d2b36SAndroid Build Coastguard Worker	}
203*333d2b36SAndroid Build Coastguard Worker}
204*333d2b36SAndroid Build Coastguard Worker
205*333d2b36SAndroid Build Coastguard Workerfunc (e *errorProtoLog) StartAction(action *Action, counts Counts) {}
206*333d2b36SAndroid Build Coastguard Worker
207*333d2b36SAndroid Build Coastguard Workerfunc (e *errorProtoLog) FinishAction(result ActionResult, counts Counts) {
208*333d2b36SAndroid Build Coastguard Worker	if result.Error == nil {
209*333d2b36SAndroid Build Coastguard Worker		return
210*333d2b36SAndroid Build Coastguard Worker	}
211*333d2b36SAndroid Build Coastguard Worker
212*333d2b36SAndroid Build Coastguard Worker	e.errorProto.ActionErrors = append(e.errorProto.ActionErrors, &soong_build_error_proto.BuildActionError{
213*333d2b36SAndroid Build Coastguard Worker		Description: proto.String(result.Description),
214*333d2b36SAndroid Build Coastguard Worker		Command:     proto.String(result.Command),
215*333d2b36SAndroid Build Coastguard Worker		Output:      proto.String(result.Output),
216*333d2b36SAndroid Build Coastguard Worker		Artifacts:   result.Outputs,
217*333d2b36SAndroid Build Coastguard Worker		Error:       proto.String(result.Error.Error()),
218*333d2b36SAndroid Build Coastguard Worker	})
219*333d2b36SAndroid Build Coastguard Worker
220*333d2b36SAndroid Build Coastguard Worker	err := writeToFile(&e.errorProto, e.filename)
221*333d2b36SAndroid Build Coastguard Worker	if err != nil {
222*333d2b36SAndroid Build Coastguard Worker		e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
223*333d2b36SAndroid Build Coastguard Worker	}
224*333d2b36SAndroid Build Coastguard Worker}
225*333d2b36SAndroid Build Coastguard Worker
226*333d2b36SAndroid Build Coastguard Workerfunc (e *errorProtoLog) Flush() {
227*333d2b36SAndroid Build Coastguard Worker	//Not required.
228*333d2b36SAndroid Build Coastguard Worker}
229*333d2b36SAndroid Build Coastguard Worker
230*333d2b36SAndroid Build Coastguard Workerfunc (e *errorProtoLog) Message(level MsgLevel, message string) {
231*333d2b36SAndroid Build Coastguard Worker	if level > ErrorLvl {
232*333d2b36SAndroid Build Coastguard Worker		e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
233*333d2b36SAndroid Build Coastguard Worker	}
234*333d2b36SAndroid Build Coastguard Worker}
235*333d2b36SAndroid Build Coastguard Worker
236*333d2b36SAndroid Build Coastguard Workerfunc (e *errorProtoLog) Write(p []byte) (int, error) {
237*333d2b36SAndroid Build Coastguard Worker	return 0, errors.New("not supported")
238*333d2b36SAndroid Build Coastguard Worker}
239*333d2b36SAndroid Build Coastguard Worker
240*333d2b36SAndroid Build Coastguard Workertype buildProgressLog struct {
241*333d2b36SAndroid Build Coastguard Worker	filename      string
242*333d2b36SAndroid Build Coastguard Worker	log           logger.Logger
243*333d2b36SAndroid Build Coastguard Worker	failedActions uint64
244*333d2b36SAndroid Build Coastguard Worker}
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Workerfunc NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
247*333d2b36SAndroid Build Coastguard Worker	return &buildProgressLog{
248*333d2b36SAndroid Build Coastguard Worker		filename:      filename,
249*333d2b36SAndroid Build Coastguard Worker		log:           log,
250*333d2b36SAndroid Build Coastguard Worker		failedActions: 0,
251*333d2b36SAndroid Build Coastguard Worker	}
252*333d2b36SAndroid Build Coastguard Worker}
253*333d2b36SAndroid Build Coastguard Worker
254*333d2b36SAndroid Build Coastguard Workerfunc (b *buildProgressLog) StartAction(action *Action, counts Counts) {
255*333d2b36SAndroid Build Coastguard Worker	b.updateCounters(counts)
256*333d2b36SAndroid Build Coastguard Worker}
257*333d2b36SAndroid Build Coastguard Worker
258*333d2b36SAndroid Build Coastguard Workerfunc (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
259*333d2b36SAndroid Build Coastguard Worker	if result.Error != nil {
260*333d2b36SAndroid Build Coastguard Worker		b.failedActions++
261*333d2b36SAndroid Build Coastguard Worker	}
262*333d2b36SAndroid Build Coastguard Worker	b.updateCounters(counts)
263*333d2b36SAndroid Build Coastguard Worker}
264*333d2b36SAndroid Build Coastguard Worker
265*333d2b36SAndroid Build Coastguard Workerfunc (b *buildProgressLog) Flush() {
266*333d2b36SAndroid Build Coastguard Worker	//Not required.
267*333d2b36SAndroid Build Coastguard Worker}
268*333d2b36SAndroid Build Coastguard Worker
269*333d2b36SAndroid Build Coastguard Workerfunc (b *buildProgressLog) Message(level MsgLevel, message string) {
270*333d2b36SAndroid Build Coastguard Worker	// Not required.
271*333d2b36SAndroid Build Coastguard Worker}
272*333d2b36SAndroid Build Coastguard Worker
273*333d2b36SAndroid Build Coastguard Workerfunc (b *buildProgressLog) Write(p []byte) (int, error) {
274*333d2b36SAndroid Build Coastguard Worker	return 0, errors.New("not supported")
275*333d2b36SAndroid Build Coastguard Worker}
276*333d2b36SAndroid Build Coastguard Worker
277*333d2b36SAndroid Build Coastguard Workerfunc (b *buildProgressLog) updateCounters(counts Counts) {
278*333d2b36SAndroid Build Coastguard Worker	err := writeToFile(
279*333d2b36SAndroid Build Coastguard Worker		&soong_build_progress_proto.BuildProgress{
280*333d2b36SAndroid Build Coastguard Worker			CurrentActions:  proto.Uint64(uint64(counts.RunningActions)),
281*333d2b36SAndroid Build Coastguard Worker			FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
282*333d2b36SAndroid Build Coastguard Worker			TotalActions:    proto.Uint64(uint64(counts.TotalActions)),
283*333d2b36SAndroid Build Coastguard Worker			FailedActions:   proto.Uint64(b.failedActions),
284*333d2b36SAndroid Build Coastguard Worker		},
285*333d2b36SAndroid Build Coastguard Worker		b.filename,
286*333d2b36SAndroid Build Coastguard Worker	)
287*333d2b36SAndroid Build Coastguard Worker	if err != nil {
288*333d2b36SAndroid Build Coastguard Worker		b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
289*333d2b36SAndroid Build Coastguard Worker	}
290*333d2b36SAndroid Build Coastguard Worker}
291*333d2b36SAndroid Build Coastguard Worker
292*333d2b36SAndroid Build Coastguard Workerfunc writeToFile(pb proto.Message, outputPath string) (err error) {
293*333d2b36SAndroid Build Coastguard Worker	data, err := proto.Marshal(pb)
294*333d2b36SAndroid Build Coastguard Worker	if err != nil {
295*333d2b36SAndroid Build Coastguard Worker		return err
296*333d2b36SAndroid Build Coastguard Worker	}
297*333d2b36SAndroid Build Coastguard Worker
298*333d2b36SAndroid Build Coastguard Worker	tempPath := outputPath + ".tmp"
299*333d2b36SAndroid Build Coastguard Worker	err = ioutil.WriteFile(tempPath, []byte(data), 0644)
300*333d2b36SAndroid Build Coastguard Worker	if err != nil {
301*333d2b36SAndroid Build Coastguard Worker		return err
302*333d2b36SAndroid Build Coastguard Worker	}
303*333d2b36SAndroid Build Coastguard Worker
304*333d2b36SAndroid Build Coastguard Worker	err = os.Rename(tempPath, outputPath)
305*333d2b36SAndroid Build Coastguard Worker	if err != nil {
306*333d2b36SAndroid Build Coastguard Worker		return err
307*333d2b36SAndroid Build Coastguard Worker	}
308*333d2b36SAndroid Build Coastguard Worker
309*333d2b36SAndroid Build Coastguard Worker	return nil
310*333d2b36SAndroid Build Coastguard Worker}
311