github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/modules/logger/parser/store.go (about) 1 // Package logger/parser contains methods to parse and restructure log output from go testing and terratest 2 package parser 3 4 import ( 5 "os" 6 "path/filepath" 7 8 "github.com/gruntwork-io/go-commons/errors" 9 "github.com/gruntwork-io/go-commons/files" 10 junitformatter "github.com/jstemmer/go-junit-report/formatter" 11 junitparser "github.com/jstemmer/go-junit-report/parser" 12 "github.com/sirupsen/logrus" 13 ) 14 15 type LogWriter struct { 16 // Represents an open file to a log corresponding to a test (key = test name) 17 lookup map[string]*os.File 18 outputDir string 19 } 20 21 // LogWriter.getOrCreateFile will get the corresponding file to a log for the provided test name, or create a new file. 22 func (logWriter LogWriter) getOrCreateFile(logger *logrus.Logger, testName string) (*os.File, error) { 23 file, hasKey := logWriter.lookup[testName] 24 if hasKey { 25 return file, nil 26 } 27 28 filename := filepath.Join(logWriter.outputDir, testName+".log") 29 file, err := createLogFile(logger, filename) 30 if err != nil { 31 return nil, errors.WithStackTrace(err) 32 } 33 logWriter.lookup[testName] = file 34 return file, nil 35 } 36 37 // LogWriter.closeChannels closes all the channels in the lookup dictionary 38 func (logWriter LogWriter) closeFiles(logger *logrus.Logger) { 39 logger.Infof("Closing all the files in log writer") 40 for testName, file := range logWriter.lookup { 41 err := file.Close() 42 if err != nil { 43 logger.Errorf("Error closing log file for test %s: %s", testName, err) 44 } 45 } 46 } 47 48 // writeLog will write the provided text to the corresponding log file for the provided test. 49 func (logWriter LogWriter) writeLog(logger *logrus.Logger, testName string, text string) error { 50 file, err := logWriter.getOrCreateFile(logger, testName) 51 if err != nil { 52 logger.Errorf("Error retrieving log for test: %s", testName) 53 return errors.WithStackTrace(err) 54 } 55 _, err = file.WriteString(text + "\n") 56 if err != nil { 57 logger.Errorf("Error (%s) writing log entry: %s", err, text) 58 return errors.WithStackTrace(err) 59 } 60 file.Sync() 61 return nil 62 } 63 64 // createLogFile will create and return the open file handle for the file at provided filename, creating all directories 65 // in the process. 66 func createLogFile(logger *logrus.Logger, filename string) (*os.File, error) { 67 // We extract and create the directory for interpolated filename, to handle nested tests where testname contains '/' 68 dirName := filepath.Dir(filename) 69 err := ensureDirectoryExists(logger, dirName) 70 if err != nil { 71 return nil, errors.WithStackTrace(err) 72 } 73 file, err := os.Create(filename) 74 if err != nil { 75 return nil, errors.WithStackTrace(err) 76 } 77 return file, nil 78 } 79 80 // ensureDirectoryExists will only attempt to create the directory if it does not exist 81 func ensureDirectoryExists(logger *logrus.Logger, dirName string) error { 82 if files.IsDir(dirName) { 83 logger.Infof("Directory %s already exists", dirName) 84 return nil 85 } 86 logger.Infof("Creating directory %s", dirName) 87 err := os.MkdirAll(dirName, os.ModePerm) 88 if err != nil { 89 logger.Errorf("Error making directory %s: %s", dirName, err) 90 return errors.WithStackTrace(err) 91 } 92 return nil 93 } 94 95 // storeJunitReport takes a parsed Junit report and stores it as report.xml in the output directory 96 func storeJunitReport(logger *logrus.Logger, outputDir string, report *junitparser.Report) { 97 ensureDirectoryExists(logger, outputDir) 98 filename := filepath.Join(outputDir, "report.xml") 99 f, err := os.Create(filename) 100 if err != nil { 101 logger.Errorf("Error making file %s for junit report", filename) 102 return 103 } 104 defer f.Close() 105 106 err = junitformatter.JUnitReportXML(report, false, "", f) 107 if err != nil { 108 logger.Errorf("Error formatting junit xml report: %s", err) 109 return 110 } 111 }