Skip to content

Instantly share code, notes, and snippets.

@mche
Created January 20, 2023 03:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mche/5c0193a07827d292aee382ad4bced9b5 to your computer and use it in GitHub Desktop.
Save mche/5c0193a07827d292aee382ad4bced9b5 to your computer and use it in GitHub Desktop.
// Если нужно, запускай функционал периодического архивирования, настройки: 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