log.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // Copyright 2018 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package status
  15. import (
  16. "compress/gzip"
  17. "errors"
  18. "fmt"
  19. "io"
  20. "io/ioutil"
  21. "os"
  22. "strings"
  23. "google.golang.org/protobuf/proto"
  24. "android/soong/ui/logger"
  25. soong_build_error_proto "android/soong/ui/status/build_error_proto"
  26. soong_build_progress_proto "android/soong/ui/status/build_progress_proto"
  27. )
  28. type verboseLog struct {
  29. w io.WriteCloser
  30. }
  31. func NewVerboseLog(log logger.Logger, filename string) StatusOutput {
  32. if !strings.HasSuffix(filename, ".gz") {
  33. filename += ".gz"
  34. }
  35. f, err := logger.CreateFileWithRotation(filename, 5)
  36. if err != nil {
  37. log.Println("Failed to create verbose log file:", err)
  38. return nil
  39. }
  40. w := gzip.NewWriter(f)
  41. return &verboseLog{
  42. w: w,
  43. }
  44. }
  45. func (v *verboseLog) StartAction(action *Action, counts Counts) {}
  46. func (v *verboseLog) FinishAction(result ActionResult, counts Counts) {
  47. cmd := result.Command
  48. if cmd == "" {
  49. cmd = result.Description
  50. }
  51. fmt.Fprintf(v.w, "[%d/%d] %s\n", counts.FinishedActions, counts.TotalActions, cmd)
  52. if result.Error != nil {
  53. fmt.Fprintf(v.w, "FAILED: %s\n", strings.Join(result.Outputs, " "))
  54. }
  55. if result.Output != "" {
  56. fmt.Fprintln(v.w, result.Output)
  57. }
  58. }
  59. func (v *verboseLog) Flush() {
  60. v.w.Close()
  61. }
  62. func (v *verboseLog) Message(level MsgLevel, message string) {
  63. fmt.Fprintf(v.w, "%s%s\n", level.Prefix(), message)
  64. }
  65. func (v *verboseLog) Write(p []byte) (int, error) {
  66. fmt.Fprint(v.w, string(p))
  67. return len(p), nil
  68. }
  69. type errorLog struct {
  70. w io.WriteCloser
  71. empty bool
  72. }
  73. func NewErrorLog(log logger.Logger, filename string) StatusOutput {
  74. f, err := logger.CreateFileWithRotation(filename, 5)
  75. if err != nil {
  76. log.Println("Failed to create error log file:", err)
  77. return nil
  78. }
  79. return &errorLog{
  80. w: f,
  81. empty: true,
  82. }
  83. }
  84. func (e *errorLog) StartAction(action *Action, counts Counts) {}
  85. func (e *errorLog) FinishAction(result ActionResult, counts Counts) {
  86. if result.Error == nil {
  87. return
  88. }
  89. if !e.empty {
  90. fmt.Fprintf(e.w, "\n\n")
  91. }
  92. e.empty = false
  93. fmt.Fprintf(e.w, "FAILED: %s\n", result.Description)
  94. if len(result.Outputs) > 0 {
  95. fmt.Fprintf(e.w, "Outputs: %s\n", strings.Join(result.Outputs, " "))
  96. }
  97. fmt.Fprintf(e.w, "Error: %s\n", result.Error)
  98. if result.Command != "" {
  99. fmt.Fprintf(e.w, "Command: %s\n", result.Command)
  100. }
  101. fmt.Fprintf(e.w, "Output:\n%s\n", result.Output)
  102. }
  103. func (e *errorLog) Flush() {
  104. e.w.Close()
  105. }
  106. func (e *errorLog) Message(level MsgLevel, message string) {
  107. if level < ErrorLvl {
  108. return
  109. }
  110. if !e.empty {
  111. fmt.Fprintf(e.w, "\n\n")
  112. }
  113. e.empty = false
  114. fmt.Fprintf(e.w, "error: %s\n", message)
  115. }
  116. func (e *errorLog) Write(p []byte) (int, error) {
  117. fmt.Fprint(e.w, string(p))
  118. return len(p), nil
  119. }
  120. type errorProtoLog struct {
  121. errorProto soong_build_error_proto.BuildError
  122. filename string
  123. log logger.Logger
  124. }
  125. func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
  126. os.Remove(filename)
  127. return &errorProtoLog{
  128. errorProto: soong_build_error_proto.BuildError{},
  129. filename: filename,
  130. log: log,
  131. }
  132. }
  133. func (e *errorProtoLog) StartAction(action *Action, counts Counts) {}
  134. func (e *errorProtoLog) FinishAction(result ActionResult, counts Counts) {
  135. if result.Error == nil {
  136. return
  137. }
  138. e.errorProto.ActionErrors = append(e.errorProto.ActionErrors, &soong_build_error_proto.BuildActionError{
  139. Description: proto.String(result.Description),
  140. Command: proto.String(result.Command),
  141. Output: proto.String(result.Output),
  142. Artifacts: result.Outputs,
  143. Error: proto.String(result.Error.Error()),
  144. })
  145. err := writeToFile(&e.errorProto, e.filename)
  146. if err != nil {
  147. e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
  148. }
  149. }
  150. func (e *errorProtoLog) Flush() {
  151. //Not required.
  152. }
  153. func (e *errorProtoLog) Message(level MsgLevel, message string) {
  154. if level > ErrorLvl {
  155. e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
  156. }
  157. }
  158. func (e *errorProtoLog) Write(p []byte) (int, error) {
  159. return 0, errors.New("not supported")
  160. }
  161. type buildProgressLog struct {
  162. filename string
  163. log logger.Logger
  164. failedActions uint64
  165. }
  166. func NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
  167. return &buildProgressLog{
  168. filename: filename,
  169. log: log,
  170. failedActions: 0,
  171. }
  172. }
  173. func (b *buildProgressLog) StartAction(action *Action, counts Counts) {
  174. b.updateCounters(counts)
  175. }
  176. func (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
  177. if result.Error != nil {
  178. b.failedActions++
  179. }
  180. b.updateCounters(counts)
  181. }
  182. func (b *buildProgressLog) Flush() {
  183. //Not required.
  184. }
  185. func (b *buildProgressLog) Message(level MsgLevel, message string) {
  186. // Not required.
  187. }
  188. func (b *buildProgressLog) Write(p []byte) (int, error) {
  189. return 0, errors.New("not supported")
  190. }
  191. func (b *buildProgressLog) updateCounters(counts Counts) {
  192. err := writeToFile(
  193. &soong_build_progress_proto.BuildProgress{
  194. CurrentActions: proto.Uint64(uint64(counts.RunningActions)),
  195. FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
  196. TotalActions: proto.Uint64(uint64(counts.TotalActions)),
  197. FailedActions: proto.Uint64(b.failedActions),
  198. },
  199. b.filename,
  200. )
  201. if err != nil {
  202. b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
  203. }
  204. }
  205. func writeToFile(pb proto.Message, outputPath string) (err error) {
  206. data, err := proto.Marshal(pb)
  207. if err != nil {
  208. return err
  209. }
  210. tempPath := outputPath + ".tmp"
  211. err = ioutil.WriteFile(tempPath, []byte(data), 0644)
  212. if err != nil {
  213. return err
  214. }
  215. err = os.Rename(tempPath, outputPath)
  216. if err != nil {
  217. return err
  218. }
  219. return nil
  220. }