new: added log rotation (closes #374)

This commit is contained in:
evilsocket 2018-10-28 12:43:38 +01:00
commit fc7d8d22b4
No known key found for this signature in database
GPG key ID: 1564D7F30393A456
5 changed files with 161 additions and 7 deletions

6
Gopkg.lock generated
View file

@ -59,7 +59,7 @@
revision = "f58a169a71a51037728990b2d3597a14f56b525b" revision = "f58a169a71a51037728990b2d3597a14f56b525b"
[[projects]] [[projects]]
digest = "1:bfbb93ae71a839764d94c1ba50f3868ecc576871274cf29db1903bf32efce620" digest = "1:b44604e0c8da17e780203bfd9388d65db31d4ee039347ea92788412e7737a08c"
name = "github.com/evilsocket/islazy" name = "github.com/evilsocket/islazy"
packages = [ packages = [
"data", "data",
@ -71,8 +71,8 @@
"zip", "zip",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "e86063a516840e32de87d39c214a6937b4d22e04" revision = "be7e564817af1379a350998577006745039f599f"
version = "v1.8.0" version = "v1.9.0"
[[projects]] [[projects]]
branch = "master" branch = "master"

View file

@ -25,7 +25,7 @@
# unused-packages = true # unused-packages = true
[[constraint]] [[constraint]]
name = "github.com/evilsocket/islazy" name = "github.com/evilsocket/islazy"
version = "1.8.0" version = "1.9.0"
[[constraint]] [[constraint]]
branch = "master" branch = "master"

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"strconv" "strconv"
"sync"
"time" "time"
"github.com/bettercap/bettercap/log" "github.com/bettercap/bettercap/log"
@ -14,9 +15,20 @@ import (
"github.com/evilsocket/islazy/tui" "github.com/evilsocket/islazy/tui"
) )
type rotation struct {
sync.Mutex
Enabled bool
Compress bool
Format string
How string
Period int
}
type EventsStream struct { type EventsStream struct {
session.SessionModule session.SessionModule
outputName string
output *os.File output *os.File
rotation rotation
ignoreList *IgnoreList ignoreList *IgnoreList
waitFor string waitFor string
waitChan chan *session.Event waitChan chan *session.Event
@ -117,6 +129,28 @@ func NewEventsStream(s *session.Session) *EventsStream {
"", "",
"If not empty, events will be written to this file instead of the standard output.")) "If not empty, events will be written to this file instead of the standard output."))
stream.AddParam(session.NewBoolParameter("events.stream.output.rotate",
"true",
"If true will enable log rotation."))
stream.AddParam(session.NewBoolParameter("events.stream.output.rotate.compress",
"true",
"If true will enable log rotation compression."))
stream.AddParam(session.NewStringParameter("events.stream.output.rotate.how",
"size",
"(size|time)",
"Rotate by 'size' or 'time'."))
stream.AddParam(session.NewStringParameter("events.stream.output.rotate.format",
"2006-01-02 15:04:05",
"",
"Datetime format to use for log rotation file names."))
stream.AddParam(session.NewIntParameter("events.stream.output.rotate.when",
"10485760",
"File size or time duration in seconds for log rotation."))
stream.AddParam(session.NewBoolParameter("events.stream.http.request.dump", stream.AddParam(session.NewBoolParameter("events.stream.http.request.dump",
"false", "false",
"If true all HTTP requests will be dumped.")) "If true all HTTP requests will be dumped."))
@ -146,10 +180,24 @@ func (s *EventsStream) Configure() (err error) {
if err, output = s.StringParam("events.stream.output"); err == nil { if err, output = s.StringParam("events.stream.output"); err == nil {
if output == "" { if output == "" {
s.output = os.Stdout s.output = os.Stdout
} else if output, err = fs.Expand(output); err == nil { } else if s.outputName, err = fs.Expand(output); err == nil {
s.output, err = os.OpenFile(output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) s.output, err = os.OpenFile(s.outputName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
} }
} else if err, s.dumpHttpReqs = s.BoolParam("events.stream.http.request.dump"); err != nil { }
if err, s.rotation.Enabled = s.BoolParam("events.stream.output.rotate"); err != nil {
return err
} else if err, s.rotation.Compress = s.BoolParam("events.stream.output.rotate.compress"); err != nil {
return err
} else if err, s.rotation.Format = s.StringParam("events.stream.output.rotate.format"); err != nil {
return err
} else if err, s.rotation.How = s.StringParam("events.stream.output.rotate.how"); err != nil {
return err
} else if err, s.rotation.Period = s.IntParam("events.stream.output.rotate.when"); err != nil {
return err
}
if err, s.dumpHttpReqs = s.BoolParam("events.stream.http.request.dump"); err != nil {
return err return err
} else if err, s.dumpHttpResp = s.BoolParam("events.stream.http.response.dump"); err != nil { } else if err, s.dumpHttpResp = s.BoolParam("events.stream.http.response.dump"); err != nil {
return err return err

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"time"
"github.com/bettercap/bettercap/network" "github.com/bettercap/bettercap/network"
"github.com/bettercap/bettercap/session" "github.com/bettercap/bettercap/session"
@ -11,6 +12,7 @@ import (
"github.com/google/go-github/github" "github.com/google/go-github/github"
"github.com/evilsocket/islazy/tui" "github.com/evilsocket/islazy/tui"
"github.com/evilsocket/islazy/zip"
) )
const eventTimeFormat = "15:04:05" const eventTimeFormat = "15:04:05"
@ -152,6 +154,53 @@ func (s *EventsStream) viewUpdateEvent(e session.Event) {
*update.HTMLURL) *update.HTMLURL)
} }
func (s *EventsStream) doRotation() {
if s.output == os.Stdout {
return
} else if !s.rotation.Enabled {
return
}
s.rotation.Lock()
defer s.rotation.Unlock()
doRotate := false
if info, err := s.output.Stat(); err == nil {
if s.rotation.How == "size" {
doRotate = info.Size() >= int64(s.rotation.Period)
} else if s.rotation.How == "time" {
doRotate = info.ModTime().Unix()%int64(s.rotation.Period) == 0
}
}
if doRotate {
var err error
name := fmt.Sprintf("%s-%s", s.outputName, time.Now().Format(s.rotation.Format))
if err := s.output.Close(); err != nil {
fmt.Printf("could not close log for rotation: %s\n", err)
return
}
if err := os.Rename(s.outputName, name); err != nil {
fmt.Printf("could not rename %s to %s: %s\n", s.outputName, name, err)
} else if s.rotation.Compress {
zipName := fmt.Sprintf("%s.zip", name)
if err = zip.Files(zipName, []string{name}); err != nil {
fmt.Printf("error creating %s: %s", zipName, err)
} else if err = os.Remove(name); err != nil {
fmt.Printf("error deleting %s: %s", name, err)
}
}
s.output, err = os.OpenFile(s.outputName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("could not open %s: %s", s.outputName, err)
}
}
}
func (s *EventsStream) View(e session.Event, refresh bool) { func (s *EventsStream) View(e session.Event, refresh bool) {
if e.Tag == "sys.log" { if e.Tag == "sys.log" {
s.viewLogEvent(e) s.viewLogEvent(e)
@ -176,4 +225,6 @@ func (s *EventsStream) View(e session.Event, refresh bool) {
if refresh && s.output == os.Stdout { if refresh && s.output == os.Stdout {
s.Session.Refresh() s.Session.Refresh()
} }
s.doRotation()
} }

55
vendor/github.com/evilsocket/islazy/zip/files.go generated vendored Normal file
View file

@ -0,0 +1,55 @@
package zip
import (
"archive/zip"
"io"
"os"
)
// Files compresses one or many files into a single zip archive file.
// Credits: https://golangcode.com/create-zip-files-in-go/
func Files(filename string, files []string) error {
arc, err := os.Create(filename)
if err != nil {
return err
}
defer arc.Close()
writer := zip.NewWriter(arc)
defer writer.Close()
for _, file := range files {
in, err := os.Open(file)
if err != nil {
return err
}
defer in.Close()
info, err := in.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// Using FileInfoHeader() above only uses the basename of the file. If we want
// to preserve the folder structure we can overwrite this with the full path.
header.Name = file
// Change to deflate to gain better compression
// see http://golang.org/pkg/archive/zip/#pkg-constants
header.Method = zip.Deflate
w, err := writer.CreateHeader(header)
if err != nil {
return err
}
if _, err = io.Copy(w, in); err != nil {
return err
}
}
return nil
}