Created
January 20, 2023 03:57
-
-
Save mche/5c0193a07827d292aee382ad4bced9b5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Если нужно, запускай функционал периодического архивирования, настройки: Settings.FileZipBounce и Settings.ZipArchiveRemoveBounce | |
func StartZipTicker () { | |
go func() { | |
ticker := time.NewTicker(time.Duration(time.Minute)) | |
for range ticker.C { | |
compressLogFiles() | |
clearOldZipFiles() | |
} | |
}() | |
} | |
var reDateFile = regexp.MustCompile(`^(\d+)\D(\d+)\D(\d)`) // 2022.12.12 16-19-31.log | |
func compressLogFiles () { | |
if Settings.FileZipBounce == 0 { | |
return | |
} | |
path := fmt.Sprintf(`%s%s/*%s`, exeDir, logsDir, logFileExt) | |
files, err := filepath.Glob(path) // ./logs/*.log | |
if err != nil { | |
log.Printf("fail read dir [%v]: %v", path, err) | |
return | |
} | |
var zipPath string | |
var zipFile *os.File | |
var zipWriter *zip.Writer // zip для разных месяцев не должен случиться | |
for _, file := range files { | |
fileInfo, err := os.Stat(file) | |
if err != nil { | |
log.Printf(`faii os.Stat(%v)`, file) | |
continue | |
} | |
// .ModTime(), а может время файла брать из названия лучше | |
if diff := time.Since(fileInfo.ModTime()); diff > Settings.FileZipBounce { | |
if zipWriter == nil { | |
find := reDateFile.FindAllSubmatch([]byte(fileInfo.Name()), -1) | |
var (year string; month string) | |
if len(find) == 0 { | |
y, m, _ := time.Now().Date() // или fileInfo.ModTime().Date() | |
month = fmt.Sprintf(`%v`, int(m)) | |
year = fmt.Sprintf(`%v`, y) | |
} else { | |
year = string(find[0][1]) | |
month = string(find[0][2]) | |
} | |
zipPath = fmt.Sprintf(`%s%s/%v.%v.all_%s%s.zip`, exeDir, logsDir, year, month, exeFileName, logFileExt) | |
zipWriter, zipFile, err = openZipFileWriter(zipPath) // закрытие хэндлеров ниже, не defer | |
if err != nil || zipWriter == nil { | |
log.Printf(`fail zip writer: %v`, err) | |
return | |
} | |
} | |
if err := compressFile(fileInfo, zipWriter); err != nil { | |
log.Printf(`faii compress log file: %v`, err) | |
continue | |
} | |
log.Printf(`success compressFile(%v) after %v`, fileInfo.Name(), diff) | |
if err := os.Remove(file); err != nil { | |
log.Printf(`fail os.Remove(%v): %v`, fileInfo.Name(), err) | |
} | |
log.Printf(`success remove zipped (%v)`, fileInfo.Name()) | |
} | |
} | |
if zipFile != nil { | |
zipWriter.Close() | |
zipFile.Close() | |
// обязательно закрыть перед переименованием | |
os.Rename(zipPath + `.zip`, zipPath) // ошибка не нужна | |
} | |
} | |
/* ТАК сложно потому, что невозможно дописывать в старый зип, тут пересоздается архивный зип-райтер, в него копируются логи из старого зипа и потом переименовать(затирает старый зип). Много хандлеров в возврате чтобы закрыть когда нужно. */ | |
func openZipFileWriter (zipPath string) (*zip.Writer, *os.File, error) { | |
zr, err := zip.OpenReader(zipPath) | |
if err != nil { | |
zwf, err := os.Create(zipPath + `.zip`) | |
if err != nil { | |
return nil, nil, fmt.Errorf(`fail create zip-file: %v`, err) | |
} | |
return zip.NewWriter(zwf), zwf, nil | |
} | |
defer zr.Close() | |
zwf, err := os.Create(zipPath + `.zip`) | |
if err != nil { | |
return nil, nil, fmt.Errorf(`fail create target zip-file: %v`, err) | |
} | |
zw := zip.NewWriter(zwf) | |
for _, zipItem := range zr.File { | |
zipItemReader, err := zipItem.OpenRaw() | |
if err != nil { | |
zw.Close() | |
zwf.Close() | |
return nil, nil, fmt.Errorf(`fail open old zip-item %v`, err) | |
} | |
header := zipItem.FileHeader // clone header data | |
targetItem, err := zw.CreateRaw(&header) // use cloned data | |
if err != nil { | |
zw.Close() | |
zwf.Close() | |
return nil, nil, fmt.Errorf(`fail get old zip-item %v`, err) | |
} | |
_, err = io.Copy(targetItem, zipItemReader) | |
if err != nil { | |
zw.Close() | |
zwf.Close() | |
return nil, nil, fmt.Errorf(`fail copy old zip-item %v`, err) | |
} | |
} | |
return zw, zwf, nil | |
} | |
func compressFile (fileInfo fs.FileInfo, zipWriter *zip.Writer) error { | |
fh, err := os.Open(fmt.Sprintf(`%s%s/%s`, exeDir, logsDir, fileInfo.Name())) | |
if err != nil { | |
return fmt.Errorf(`fail os.Open(%v) %v`, fileInfo.Name(), err) | |
} | |
defer fh.Close() | |
// write handler | |
wh, err := zipWriter.Create(fileInfo.Name()) | |
if err != nil { | |
return fmt.Errorf(`fail zipWriter.Create(%v) %v`, fileInfo.Name(), err) | |
} | |
if _, err := io.Copy(wh, fh); err != nil { | |
return fmt.Errorf(`fail zip-copy file %v to archive, %v`, fileInfo.Name(), err) | |
} | |
return nil | |
} | |
func clearOldZipFiles () { | |
if Settings.ZipArchiveRemoveBounce == 0 { | |
return | |
} | |
path := fmt.Sprintf(`%s%s/*%s`, exeDir, logsDir, ".zip") | |
files, err := filepath.Glob(path) | |
if err != nil { | |
log.Printf("fail read dir [%v]: %v", path, err) | |
return | |
} | |
for _, file := range files { | |
fileInfo, err := os.Stat(file) | |
if err != nil { | |
log.Printf(`faii os.Stat(%v)`, file) | |
continue | |
} | |
if diff := time.Since(fileInfo.ModTime()); diff > Settings.ZipArchiveRemoveBounce { | |
if err := os.Remove(file); err != nil { | |
log.Printf(`fail os.Remove(%v): %v`, fileInfo.Name(), err) | |
continue | |
} | |
log.Printf(`success remove(%v) after %v`, fileInfo.Name(), diff) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment