diff options
| author | Jeroen Wijenbergh <jeroen.wijenbergh@geant.org> | 2026-02-12 12:34:08 +0100 |
|---|---|---|
| committer | Jeroen Wijenbergh <jeroen.wijenbergh@geant.org> | 2026-02-12 12:59:03 +0100 |
| commit | a30ef6b27e578a4cf0a674b24f5b52b4c1516c63 (patch) | |
| tree | 27c7321cbceac2a487c1ba17151711de3d438a53 /internal/log | |
| parent | b00ce8214479c50e137db73c77b0cc1393c5e7d4 (diff) | |
All: Rename packages that sound useless or clash with std
Diffstat (limited to 'internal/log')
| -rw-r--r-- | internal/log/log.go | 37 | ||||
| -rw-r--r-- | internal/log/rotate.go | 109 | ||||
| -rw-r--r-- | internal/log/rotate_test.go | 144 |
3 files changed, 0 insertions, 290 deletions
diff --git a/internal/log/log.go b/internal/log/log.go deleted file mode 100644 index 91eaed8..0000000 --- a/internal/log/log.go +++ /dev/null @@ -1,37 +0,0 @@ -// Package log implements a basic level based logger -package log - -import ( - "fmt" - "io" - "log/slog" - "os" - "path" -) - -type Logger struct { - fr *FileRotater -} - -func (l *Logger) Init(dir string) (*slog.Logger, error) { - err := os.MkdirAll(dir, 0o700) - if err != nil { - return nil, err - } - name := path.Join(dir, "log") - - fr, err := NewFileRotater(name) - if err != nil { - return nil, fmt.Errorf("failed creating log rotater: %w", err) - } - l.fr = fr - multi := io.MultiWriter(os.Stdout, fr) - handler := slog.NewTextHandler(multi, &slog.HandlerOptions{ - Level: slog.LevelDebug, - }) - return slog.New(handler), nil -} - -func (l *Logger) Close() error { - return l.fr.Close() -} diff --git a/internal/log/rotate.go b/internal/log/rotate.go deleted file mode 100644 index 2971f70..0000000 --- a/internal/log/rotate.go +++ /dev/null @@ -1,109 +0,0 @@ -package log - -import ( - "io" - "os" - "sync" - - "codeberg.org/eduVPN/eduvpn-common/internal/atomicfile" -) - -var ( - // MaxSize is the maximum size in bytes from when to start trimming - MaxSize int64 = 10 * 1024 * 1024 - - // TrimSize denotes how much to trim from the beginning - TrimSize = MaxSize / 2 - - // TrimMsg is the message to display when it was trimmed - TrimMsg = "--- previous part was trimmed by eduvpn-common as the file was too big (10MB) ---\n" -) - -// FileRotater is a file that is trimmed when a maximum size is reached -// This is for logging useful -type FileRotater struct { - filename string - file *os.File - mu sync.Mutex -} - -// NewFileRotater creates a new log file rotater -func NewFileRotater(filename string) (*FileRotater, error) { - fr := &FileRotater{ - filename: filename, - } - - err := fr.open() - if err != nil { - return nil, err - } - return fr, nil -} - -func (fr *FileRotater) open() error { - f, err := os.OpenFile(fr.filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666) - if err != nil { - return err - } - fr.file = f - return nil -} - -func (fr *FileRotater) trim() error { - // We need to seek to the trim size to skip over that part as we discard it - _, err := fr.file.Seek(TrimSize, io.SeekStart) - if err != nil { - return err - } - - // get the part of the file that we want to keep - keep, err := io.ReadAll(fr.file) - if err != nil { - return err - } - - all := []byte(TrimMsg) - all = append(all, keep...) - err = atomicfile.WriteFile(fr.file.Name(), all, 0o666) - if err != nil { - return err - } - - // re-open the handle as the file was renamed - err = fr.file.Close() - if err != nil { - return err - } - err = fr.open() - if err != nil { - return err - } - return nil -} - -// Write implements io.Writer for the log rotater -func (fr *FileRotater) Write(p []byte) (n int, err error) { - fr.mu.Lock() - defer fr.mu.Unlock() - fi, err := fr.file.Stat() - if err != nil { - return 0, err - } - - if fi.Size() >= MaxSize { - err = fr.trim() - if err != nil { - return 0, err - } - } - // we don't write atomically here as we want it to be as fast as possible - // and if we lose a part of one log statement it's not a big deal - return fr.file.Write(p) -} - -// Close closes the file in a safe way by locking and unlocking the mutex -func (fr *FileRotater) Close() error { - fr.mu.Lock() - defer fr.mu.Unlock() - return fr.file.Close() -} diff --git a/internal/log/rotate_test.go b/internal/log/rotate_test.go deleted file mode 100644 index 4fa77fd..0000000 --- a/internal/log/rotate_test.go +++ /dev/null @@ -1,144 +0,0 @@ -package log - -import ( - "io" - "os" - "path/filepath" - "strings" - "sync" - "testing" -) - -func createFileRotater(t *testing.T) (*FileRotater, func()) { - d, err := os.MkdirTemp("", "logtest") - if err != nil { - t.Fatalf("failed creating tmp dir: %v", err) - } - fn := filepath.Join(d, "test.log") - fr, err := NewFileRotater(fn) - if err != nil { - t.Fatalf("NewFileRotater error: %v", err) - } - if fr == nil { - t.Fatal("NewFileRotater returned nil") - } - return fr, func() { - err := os.RemoveAll(d) - if err != nil { - t.Errorf("failed removing file: %v", err) - } - } -} - -func TestNewFileRotater(t *testing.T) { - _, cleanup := createFileRotater(t) - cleanup() - - d, err := os.MkdirTemp("", "anotherlogtest") - if err != nil { - t.Fatalf("failed creating another tmp dir: %v", err) - } - nef := filepath.Join(d, "notexist", "test.log") - _, err = NewFileRotater(nef) - if err == nil { - t.Error("NewFileRotater returned no error with nonexistent dir") - } -} - -func TestWriteConcurrent(t *testing.T) { - fr, cleanup := createFileRotater(t) - defer cleanup() - MaxSize = 5 - var wg sync.WaitGroup - for range 5 { - wg.Add(1) - go func() { - _, err := fr.Write([]byte("test")) - defer wg.Done() - if err != nil { - t.Errorf("concurrent write returned an error: %v", err) - } - }() - } - wg.Wait() -} - -func TestWriteTrim(t *testing.T) { - fr, cleanup := createFileRotater(t) - defer cleanup() - writeNCheckSize := func(n int, size int64) { - buf := make([]byte, n) - - for i := range n { - buf[i] = 'x' - } - _, err := fr.Write(buf) - if err != nil { - t.Fatalf("failed writing: %v", err) - } - - fs, err := fr.file.Stat() - if err != nil { - t.Fatalf("failed getting size: %v", err) - } - - gsize := fs.Size() - - if gsize != size { - t.Fatalf("got: %v, want: %v, max size: %v", gsize, size, MaxSize) - } - } - - // we test by writing a start message and checking if it disappears after trimmign - // the max size we set to the length of the start message + 20 bytes - begS := "this is the start" - begB := []byte(begS) - startN := int64(len(begB)) - MaxSize = startN + 20 - TrimSize = MaxSize / 2 - - // no trim yet - _, err := fr.Write(begB) - if err != nil { - t.Fatalf("failed writing start message: %v", err) - } - - // write until the trimming size - writeNCheckSize(5, startN+5) - writeNCheckSize(15, MaxSize) - - // set the length we want to write - var n int64 = 11 - - // now the size should be the length of the trimmed message plus the remaining (non-trimmed part of the file) plus the length we want to write - - size := int64(len(TrimMsg)) + (MaxSize - TrimSize) + n - writeNCheckSize(11, size) - - // disable trimming by setting it to a high value - MaxSize = 9000 - TrimSize = 9000 - - // now the size should be the old size plus the write size - newN := 12 - writeNCheckSize(newN, size+int64(newN)) - - _, err = fr.file.Seek(0, io.SeekStart) - if err != nil { - t.Fatalf("failed going to beginning of file: %v", err) - } - - b, err := io.ReadAll(fr.file) - if err != nil { - t.Fatalf("failed reading file: %v", err) - } - - corpus := string(b) - if strings.Contains(corpus, begS) { - t.Fatalf("file still contains beginning message: %v", corpus) - } - - if !strings.Contains(corpus, TrimMsg) { - t.Fatalf("file does not contain trim message: %v", corpus) - } -} |
