github.com/qlik-oss/gopherciser@v0.18.6/logger/filewriter.go (about) 1 package logger 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strconv" 8 9 "github.com/pkg/errors" 10 ) 11 12 type ( 13 // Writer simple implementation of a file writer 14 Writer struct { 15 fil *os.File 16 } 17 ) 18 19 // NewWriter create new instance of Writer 20 func NewWriter(name string) (*Writer, error) { 21 w := &Writer{} 22 23 basePath := filepath.Dir(name) 24 if basePath != "." { 25 // "." is returned when there's no base path, hence no directory 26 // needs to be created in advance 27 if err := os.MkdirAll(basePath, os.ModePerm); err != nil { 28 return nil, errors.Wrapf(err, "failed to create base folder <%s>", basePath) 29 } 30 } 31 32 if err := w.createFile(name); err != nil { 33 return nil, errors.Wrapf(err, "failed to create file<%s>", name) 34 } 35 return w, nil 36 } 37 38 // Write implement io.Writer interface 39 func (w Writer) Write(p []byte) (int, error) { 40 if w.fil == nil { 41 return 0, nil 42 } 43 44 n, err := w.fil.Write(p) 45 if err != nil { 46 return n, errors.WithStack(err) 47 } 48 49 return n, nil 50 } 51 52 func (w *Writer) createFile(name string) error { 53 if fileExists(name) { 54 name = backupName(name) 55 } 56 57 fil, err := os.Create(name) 58 if err != nil { 59 return errors.Wrapf(err, "Failed to create log file<%s>", name) 60 } 61 62 w.fil = fil 63 return nil 64 } 65 66 // Close writer 67 func (w *Writer) Close() error { 68 if w.fil == nil { 69 return nil 70 } 71 72 return errors.WithStack(w.fil.Close()) 73 } 74 75 func backupName(name string) string { 76 if fileExists(name) { 77 return backupName(addDashEnd(name)) 78 } 79 return name 80 } 81 82 func fileExists(name string) bool { 83 if _, err := os.Stat(name); !os.IsNotExist(err) { 84 return true 85 } 86 return false 87 } 88 89 func addDashEnd(name string) string { 90 num := "-001" 91 92 ext := filepath.Ext(name) 93 runes := []rune(name[0:(len(name) - len(ext))]) 94 95 if len(name) > 4 && len(runes) > 3 && runes[len(runes)-4] == '-' { 96 cNum := runes[len(runes)-3:] 97 if cInt, err := strconv.Atoi(string(cNum)); err == nil { //else is not number, keep num 98 runes = runes[0:(len(runes) - 4)] //Remove current dash numbering 99 cInt++ 100 num = fmt.Sprintf("-%0.3d", cInt) 101 } 102 } 103 104 return fmt.Sprintf("%s%s%s", string(runes), num, ext) 105 }