Skip to content

Commit

Permalink
Add logfile rotation and size limit
Browse files Browse the repository at this point in the history
  • Loading branch information
marema31 committed Feb 25, 2019
1 parent 63bb99d commit a9ff16f
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# tests files
testdata/*log*

4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type Config struct {
// Params type for characteristics of a stream
type Params struct {
File string
Maxsize uint
Maxsize int
Backups int
}

Expand Down Expand Up @@ -113,7 +113,7 @@ func (c *Config) GetParams(stream string) (*Params, error) {
return nil, err
}
p := &Params{
Maxsize: maxsize,
Maxsize: int(maxsize),
Backups: backups,
File: file,
}
Expand Down
2 changes: 1 addition & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func TestErrFromFile(t *testing.T) {

func TestParams(t *testing.T) {
defaultFile := "/tmp/correct_err.log"
var defaultSize uint = 2 * 1024 * 1024
defaultSize := 2 * 1024 * 1024
defaultBackups := 3

c, err := New("testdata", "correct", "dummy")
Expand Down
42 changes: 42 additions & 0 deletions logwriter/logwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ func (l *LogWriter) Write(p []byte) (int, error) {

n := 0
for n < len(p) {

// Manage the limitation
if l.params.Backups > 0 && l.currentsize > l.params.Maxsize {
err := l.rotation()
if err != nil {
return n, err
}
l.currentsize = 0
} else if l.params.Backups < 1 {
l.currentsize = 0
}

// Write line by line
i := bytes.IndexByte(p[n:], byte('\n'))
if i == -1 {
l.file.Write(p[n:])
Expand All @@ -52,6 +65,7 @@ func (l *LogWriter) Write(p []byte) (int, error) {
n += i + 1
l.currentsize += i + 1
}

}
return n, nil
}
Expand All @@ -61,3 +75,31 @@ func (l *LogWriter) Write(p []byte) (int, error) {
func (l *LogWriter) Close() error {
return l.file.Close()
}

func (l *LogWriter) rotation() error {
err := l.file.Close()
if err != nil {
return err
}

for copy := l.params.Backups - 1; copy > 0; copy-- {
src := fmt.Sprintf("%s.%d", l.params.File, copy)
dst := fmt.Sprintf("%s.%d", l.params.File, copy+1)
if _, err := os.Stat(src); err == nil {
os.Rename(src, dst)
if err != nil {
return err
}
}
}
err = os.Rename(l.params.File, l.params.File+".1")
if err != nil {
return err
}

l.file, err = os.Create(l.params.File)
if err != nil {
return err
}
return nil
}
147 changes: 147 additions & 0 deletions logwriter/logwriter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package logwriter

import (
"bytes"
"fmt"
"io/ioutil"
"os"
"testing"

"github.com/marema31/jocasta/config"
)

func TestWriteWithoutRotation(t *testing.T) {
f, err := os.Create("testdata/test.log")
if err != nil {
t.Errorf("Can not open log file. err=%v", err)
}

l := LogWriter{
params: &config.Params{
Backups: 0,
Maxsize: 0,
File: "testdata/test.log",
},
currentsize: 0,
file: f,
}
defer l.Close()

err = writeTestData(&l)
if err != nil {
t.Errorf("Can't create test log file. err=%v", err)
}

// Verify the file content
b, err := ioutil.ReadFile("testdata/test.log")
if err != nil {
t.Errorf("Can read log file. err=%v", err)
}
if !bytes.Equal(b, []byte("12\n34\n56\n78\n90\nab\ncd\n")) {
t.Errorf("The content of log file not correct. b=%v", b)
}
clean()
}

func TestWriteWithRotation(t *testing.T) {
f, err := os.Create("testdata/test.log")
if err != nil {
t.Errorf("Can not open log file. err=%v", err)
}

l := LogWriter{
params: &config.Params{
Backups: 2,
Maxsize: 4,
File: "testdata/test.log",
},
currentsize: 0,
file: f,
}
defer l.Close()

err = writeTestData(&l)
if err != nil {
t.Errorf("Can't create test log file. err=%v", err)
}

// Verify the file content
b, err := ioutil.ReadFile("testdata/test.log")
if err != nil {
t.Errorf("Can read first log file. err=%v", err)
}
if !bytes.Equal(b, []byte("cd\n")) {
t.Errorf("The content of log file not correct. b=%v", b)
}
// Verify the file content
b, err = ioutil.ReadFile("testdata/test.log.1")
if err != nil {
t.Errorf("Can read first backup log file. err=%v", err)
}
if !bytes.Equal(b, []byte("90\nab\n")) {
t.Errorf("The content of first backup log file not correct. b=%v", b)
}

// Verify the file content
b, err = ioutil.ReadFile("testdata/test.log.2")
if err != nil {
t.Errorf("Can read second backup log file. err=%v", err)
}
if !bytes.Equal(b, []byte("56\n78\n")) {
t.Errorf("The content of second backup log file not correct. b=%v", b)
}

// Verify the file content
if _, err := os.Stat("testdata/test.log.3"); !os.IsNotExist(err) {
t.Errorf("A third backup file should not been created.")
}
clean()
}

func writeTestData(l *LogWriter) error {
n, err := l.Write([]byte("12\n"))
if err != nil {
return fmt.Errorf("Can not write the first line. err=%v", err)
}
if n != 3 {
return fmt.Errorf("Wrong number of byte written. n=%d", n)
}

n, err = l.Write([]byte("34\n"))
if err != nil {
return fmt.Errorf("Can not write the second line. err=%v", err)
}

n, err = l.Write([]byte("56\n"))
if err != nil {
return fmt.Errorf("Can not write the third line. err=%v", err)
}

n, err = l.Write([]byte("78\n"))
if err != nil {
return fmt.Errorf("Can not write the fourth line. err=%v", err)
}

n, err = l.Write([]byte("90\n"))
if err != nil {
return fmt.Errorf("Can not write the fifth line. err=%v", err)
}

n, err = l.Write([]byte("ab\n"))
if err != nil {
return fmt.Errorf("Can not write the sixth line. err=%v", err)
}
n, err = l.Write([]byte("cd\n"))
if err != nil {
return fmt.Errorf("Can not write the seventh line. err=%v", err)
}
return nil
}

func clean() {
for _, ext := range []string{"log", "log.1", "log.2", "log.3"} {
if _, err := os.Stat("testdata/test." + ext); !os.IsNotExist(err) {
os.Remove("testdata/test." + ext)
}
}
}

0 comments on commit a9ff16f

Please sign in to comment.