WIP
This commit is contained in:
parent
96e877b0c2
commit
6806a81588
|
@ -94,13 +94,13 @@ func (lf *LogFile) truncate() error {
|
||||||
|
|
||||||
func prettyByteSize(b int64) string {
|
func prettyByteSize(b int64) string {
|
||||||
bf := float64(b)
|
bf := float64(b)
|
||||||
for _, unit := range []string{"", "K", "M", "G", "T", "P", "E", "Z"} {
|
for _, unit := range []string{"", "K", "M", "G", "T", "P"} {
|
||||||
if math.Abs(bf) < 1024.0 {
|
if math.Abs(bf) < 1024.0 {
|
||||||
return fmt.Sprintf("%3.1f%sB", bf, unit)
|
return fmt.Sprintf("%3.1f%sB", bf, unit)
|
||||||
}
|
}
|
||||||
bf /= 1024.0
|
bf /= 1024.0
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%.1fYB", bf)
|
return fmt.Sprintf("%.1fEB", bf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compressOldFile(fname string) error {
|
func compressOldFile(fname string) error {
|
||||||
|
|
120
logger_test.go
120
logger_test.go
|
@ -2,7 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTruncate(t *testing.T) {
|
func TestTruncate(t *testing.T) {
|
||||||
|
@ -11,14 +14,123 @@ func TestTruncate(t *testing.T) {
|
||||||
mkDirForTest(t, fmt.Sprintf("%s/tmp", tmpDir))
|
mkDirForTest(t, fmt.Sprintf("%s/tmp", tmpDir))
|
||||||
rulesJsonFp := "testData/app_over_size.log"
|
rulesJsonFp := "testData/app_over_size.log"
|
||||||
|
|
||||||
expected := fmt.Sprintf("%s/tmp/app.log", tmpDir)
|
tmpLf := fmt.Sprintf("%s/tmp/app.log", tmpDir)
|
||||||
|
|
||||||
cpFileForTest(t, rulesJsonFp, expected)
|
cpFileForTest(t, rulesJsonFp, tmpLf)
|
||||||
|
|
||||||
cfg := &LogFile{
|
lf := &LogFile{
|
||||||
path: expected,
|
path: tmpLf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lf.path = tmpLf
|
||||||
// Continue from here
|
// Continue from here
|
||||||
|
isEmpty := isFileEmpty(t, tmpLf)
|
||||||
|
assert.Equal(t, isEmpty, false)
|
||||||
|
|
||||||
|
err := lf.truncate()
|
||||||
|
assert.Equal(t, err, nil)
|
||||||
|
isEmpty = isFileEmpty(t, tmpLf)
|
||||||
|
assert.Equal(t, isEmpty, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeCopyTo(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
mkDirForTest(t, fmt.Sprintf("%s/tmp", tmpDir))
|
||||||
|
rulesJsonFp := "testData/app_over_size.log"
|
||||||
|
|
||||||
|
tmpLf := fmt.Sprintf("%s/tmp/app.log", tmpDir)
|
||||||
|
|
||||||
|
cpFileForTest(t, rulesJsonFp, tmpLf)
|
||||||
|
|
||||||
|
newLocation := fmt.Sprintf("%s/tmp/app.1.log", tmpDir)
|
||||||
|
|
||||||
|
lf := &LogFile{
|
||||||
|
path: tmpLf,
|
||||||
|
}
|
||||||
|
|
||||||
|
lf.path = tmpLf
|
||||||
|
|
||||||
|
isEmpty := isFileEmpty(t, tmpLf)
|
||||||
|
assert.Equal(t, isEmpty, false)
|
||||||
|
|
||||||
|
err := lf.makeCopyTo(newLocation)
|
||||||
|
assert.Equal(t, err, nil)
|
||||||
|
isEmpty = isFileEmpty(t, tmpLf)
|
||||||
|
assert.Equal(t, isEmpty, false)
|
||||||
|
ok := areFilesTheSame(t, lf.path, newLocation)
|
||||||
|
assert.Equal(t, ok, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrettyByteSize(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
input int
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
"KB": {input: 5675, want: "5.5KB"},
|
||||||
|
"MB": {input: 7060600, want: "6.7MB"},
|
||||||
|
"GB": {input: 8000000000, want: "7.5GB"},
|
||||||
|
"TB": {input: 1300007000000, want: "1.2TB"},
|
||||||
|
"EB": {input: 1300007000000000000, want: "1.1EB"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
got := prettyByteSize(int64(tc.input))
|
||||||
|
assert.Equal(t, got, tc.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompressFile(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
mkDirForTest(t, fmt.Sprintf("%s/tmp", tmpDir))
|
||||||
|
rulesJsonFp := "testData/app_over_size.log"
|
||||||
|
|
||||||
|
tmpLf := fmt.Sprintf("%s/tmp/app.log", tmpDir)
|
||||||
|
|
||||||
|
cpFileForTest(t, rulesJsonFp, tmpLf)
|
||||||
|
|
||||||
|
expected := fmt.Sprintf("%s/tmp/app.log.gz", tmpDir)
|
||||||
|
|
||||||
|
err := compressOldFile(tmpLf)
|
||||||
|
assert.Equal(t, err, nil)
|
||||||
|
exists := doesFileExist(tmpLf)
|
||||||
|
assert.Equal(t, exists, false)
|
||||||
|
exists = doesFileExist(expected)
|
||||||
|
assert.Equal(t, exists, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRotate(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
mkDirForTest(t, fmt.Sprintf("%s/tmp", tmpDir))
|
||||||
|
rulesJsonFp := "testData/app_over_size.log"
|
||||||
|
|
||||||
|
tmpLf := fmt.Sprintf("%s/tmp/app.log", tmpDir)
|
||||||
|
|
||||||
|
cpFileForTest(t, rulesJsonFp, tmpLf)
|
||||||
|
|
||||||
|
lf := &LogFile{
|
||||||
|
path: tmpLf,
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, _ := os.Open(tmpLf)
|
||||||
|
lf.handle = fd
|
||||||
|
|
||||||
|
isEmpty := isFileEmpty(t, tmpLf)
|
||||||
|
assert.Equal(t, isEmpty, false)
|
||||||
|
err := lf.rotate(true)
|
||||||
|
assert.Equal(t, err, nil)
|
||||||
|
exists := doesFileExist(tmpLf)
|
||||||
|
assert.Equal(t, exists, true)
|
||||||
|
isEmpty = isFileEmpty(t, tmpLf)
|
||||||
|
assert.Equal(t, isEmpty, true)
|
||||||
|
|
||||||
|
expected := walkMatch(t, tmpDir, "*.gz")
|
||||||
|
assert.NotEmpty(t, expected)
|
||||||
|
t.Logf("%+v", expected)
|
||||||
|
|
||||||
|
assert.NotEqual(t, lf.handle, fd)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,6 +83,29 @@ func doesFileExist(name string) bool {
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derived from here (https://stackoverflow.com/a/55300382)
|
||||||
|
func walkMatch(t *testing.T, root, pattern string) []string {
|
||||||
|
var matches []string
|
||||||
|
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil {
|
||||||
|
return err
|
||||||
|
} else if matched {
|
||||||
|
matches = append(matches, path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
// func doesFileExist(name string) bool {
|
// func doesFileExist(name string) bool {
|
||||||
// _, err := os.Stat(name)
|
// _, err := os.Stat(name)
|
||||||
// return !errors.Is(err, fs.ErrNotExist)
|
// return !errors.Is(err, fs.ErrNotExist)
|
||||||
|
@ -113,3 +138,72 @@ func isFileEmpty(t *testing.T, name string) bool {
|
||||||
}
|
}
|
||||||
return finfo.Size() < 1
|
return finfo.Size() < 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derived from here (https://stackoverflow.com/a/73411967)
|
||||||
|
func areFilesTheSame(t *testing.T, fp_1 string, fp_2 string) bool {
|
||||||
|
chunkSize := 4 * 1024
|
||||||
|
|
||||||
|
// shortcuts: check file metadata
|
||||||
|
finfo_1, err := os.Stat(fp_1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
finfo_2, err := os.Stat(fp_2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// are inputs are literally the same file?
|
||||||
|
if os.SameFile(finfo_1, finfo_2) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// do inputs at least have the same size?
|
||||||
|
if finfo_1.Size() != finfo_2.Size() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// long way: compare contents
|
||||||
|
fd_1, err := os.Open(fp_1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fd_1.Close()
|
||||||
|
|
||||||
|
fd_2, err := os.Open(fp_2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer fd_2.Close()
|
||||||
|
|
||||||
|
bfd_1 := make([]byte, chunkSize)
|
||||||
|
bfd_2 := make([]byte, chunkSize)
|
||||||
|
for {
|
||||||
|
n1, err1 := io.ReadFull(fd_1, bfd_1)
|
||||||
|
n2, err2 := io.ReadFull(fd_2, bfd_2)
|
||||||
|
|
||||||
|
// https://pkg.go.dev/io#Reader
|
||||||
|
// > Callers should always process the n > 0 bytes returned
|
||||||
|
// > before considering the error err. Doing so correctly
|
||||||
|
// > handles I/O errors that happen after reading some bytes
|
||||||
|
// > and also both of the allowed EOF behaviors.
|
||||||
|
|
||||||
|
if !bytes.Equal(bfd_1[:n1], bfd_2[:n2]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err1 == io.EOF && err2 == io.EOF) || (err1 == io.ErrUnexpectedEOF && err2 == io.ErrUnexpectedEOF) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// some other error, like a dropped network connection or a bad transfer
|
||||||
|
if err1 != nil {
|
||||||
|
t.Fatal(err1)
|
||||||
|
}
|
||||||
|
if err2 != nil {
|
||||||
|
t.Fatal(err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue