github.com/distbuild/reclient@v0.0.0-20240401075343-3de72e395564/cmd/reclientreport/main.go (about) 1 // Copyright 2023 Google LLC 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 15 // Binary reclientreport is used to package up re-client related 16 // log files into a .tar.gz file so that the user can upload it 17 // when filing bug reports. 18 // 19 // $ RBE_log_dir=<path-to-build-output-dir> reclientreport 20 package main 21 22 import ( 23 "context" 24 "flag" 25 "fmt" 26 "os" 27 "time" 28 29 "github.com/bazelbuild/reclient/internal/pkg/collectlogfiles" 30 "github.com/bazelbuild/reclient/internal/pkg/rbeflag" 31 "github.com/bazelbuild/reclient/internal/pkg/reproxypid" 32 33 "github.com/bazelbuild/remote-apis-sdks/go/pkg/moreflag" 34 log "github.com/golang/glog" 35 ) 36 37 var ( 38 proxyLogDir []string 39 serverAddr = flag.String("server_address", "", "The server address of reproxy in the format of host:port for network, or unix:///file for unix domain sockets. If provided reclientreport will wait for this reproxy instance to exit before collecting logs") 40 shutdownTimeout = flag.Duration("shutdown_timeout", 60*time.Second, "Number of seconds to wait for reproxy to shutdown") 41 outputDir = flag.String("output_dir", os.TempDir(), "The location to which stats are written.") 42 logPath = flag.String("log_path", "", "DEPRECATED. Use proxy_log_dir instead. If provided, the path to a log file of all executed records. The format is e.g. text://full/file/path.") 43 ) 44 45 func main() { 46 flag.Var((*moreflag.StringListValue)(&proxyLogDir), "proxy_log_dir", "If provided, the directory path to a proxy log file of executed records.") 47 rbeflag.Parse() 48 49 if *serverAddr != "" { 50 if err := waitForReproxy(); err != nil { 51 log.Errorf("Error while waiting for reproxy to exit: %v", err) 52 } 53 } 54 55 fmt.Println("Collecting log files...") 56 logFile, err := os.CreateTemp("", "reclient-log-*.tar.gz") 57 if err != nil { 58 log.Exitf("Failed to create temp log file: %v", err) 59 } 60 logFileName := logFile.Name() 61 logFile.Close() 62 logDirs := append(proxyLogDir, getLogDir()) 63 logDirs = append(logDirs, *outputDir) 64 logDirs = append(logDirs, os.TempDir()) 65 if err := collectlogfiles.CreateLogsArchive(logFileName, uniqueDirs(logDirs), *logPath); err != nil { 66 os.Remove(logFileName) 67 log.Exitf("Failed to collect re-client logs: %v", err) 68 } 69 fmt.Printf("Created log file at %v. Please attach this to your bug report!\n", logFileName) 70 } 71 72 func waitForReproxy() error { 73 ctx, cancel := context.WithTimeout(context.Background(), *shutdownTimeout) 74 defer cancel() 75 pf, err := reproxypid.ReadFile(*serverAddr) 76 if err != nil { 77 return err 78 } 79 deadCh := make(chan error) 80 defer close(deadCh) 81 go pf.PollForDeath(ctx, 50*time.Millisecond, deadCh) 82 select { 83 case err := <-deadCh: 84 return err 85 case <-ctx.Done(): 86 return ctx.Err() 87 } 88 } 89 90 // getLogDir retrieves the glog log directory 91 func getLogDir() string { 92 if f := flag.Lookup("log_dir"); f != nil { 93 return f.Value.String() 94 } 95 return "" 96 } 97 98 func uniqueDirs(dirs []string) []string { 99 m := make(map[string]bool, len(dirs)) 100 out := make([]string, 0, len(dirs)) 101 for _, dir := range dirs { 102 if m[dir] || dir == "" { 103 continue 104 } 105 out = append(out, dir) 106 m[dir] = true 107 } 108 return out 109 }