diff --git a/app/collector.go b/app/collector.go index 51cce7092..659fe242a 100644 --- a/app/collector.go +++ b/app/collector.go @@ -1,9 +1,7 @@ package app import ( - "compress/gzip" "fmt" - "io/ioutil" "os" "path/filepath" "strconv" @@ -11,7 +9,6 @@ import ( "sync" "time" - "github.com/ugorji/go/codec" "golang.org/x/net/context" "github.com/weaveworks/common/mtime" @@ -234,7 +231,7 @@ func NewFileCollector(path string, window time.Duration) (Collector, error) { } timestamps = append(timestamps, t) - rpt, err := readReport(p) + rpt, err := report.MakeFromFile(p) if err != nil { return err } @@ -267,49 +264,6 @@ func timestampFromFilepath(path string) (time.Time, error) { return time.Unix(0, nanosecondsSinceEpoch), nil } -func readReport(path string) (rpt report.Report, _ error) { - f, err := os.Open(path) - if err != nil { - return rpt, err - } - defer f.Close() - - var ( - handle codec.Handle - gzipped bool - ) - fileType := filepath.Ext(path) - if fileType == ".gz" { - gzipped = true - fileType = filepath.Ext(strings.TrimSuffix(path, fileType)) - } - switch fileType { - case ".json": - handle = &codec.JsonHandle{} - case ".msgpack": - handle = &codec.MsgpackHandle{} - default: - return rpt, fmt.Errorf("Unsupported file extension: %v", fileType) - } - - var buf []byte - if gzipped { - r, err := gzip.NewReader(f) - if err != nil { - return rpt, err - } - buf, err = ioutil.ReadAll(r) - } else { - buf, err = ioutil.ReadAll(f) - } - if err != nil { - return rpt, err - } - err = rpt.ReadBytes(buf, handle) - - return rpt, err -} - func replay(a Adder, timestamps []time.Time, reports []report.Report) { // calculate delays between report n and n+1 l := len(timestamps) diff --git a/extras/copyreport/Makefile b/extras/copyreport/Makefile new file mode 100644 index 000000000..70334ba49 --- /dev/null +++ b/extras/copyreport/Makefile @@ -0,0 +1,19 @@ +.PHONY: all vet lint build test clean + +all: build test vet lint + +vet: + go vet ./... + +lint: + golint . + +build: + go build + +test: + go test + +clean: + go clean + diff --git a/extras/copyreport/main.go b/extras/copyreport/main.go new file mode 100644 index 000000000..07e47d067 --- /dev/null +++ b/extras/copyreport/main.go @@ -0,0 +1,26 @@ +// Copy a report, decoding and re-encoding it. +package main + +import ( + "compress/gzip" + "flag" + "log" + + "github.com/weaveworks/scope/report" +) + +func main() { + flag.Parse() + + if len(flag.Args()) != 2 { + log.Fatal("usage: copyreport src.(json|msgpack)[.gz] dst.(json|msgpack)[.gz]") + } + + rpt, err := report.MakeFromFile(flag.Arg(0)) + if err != nil { + log.Fatal(err) + } + if err = rpt.WriteToFile(flag.Arg(1), gzip.DefaultCompression); err != nil { + log.Fatal(err) + } +} diff --git a/report/marshal.go b/report/marshal.go index f5e2e776a..36c7d2d0d 100644 --- a/report/marshal.go +++ b/report/marshal.go @@ -1,10 +1,15 @@ package report import ( + "bufio" "bytes" "compress/gzip" + "fmt" "io" "io/ioutil" + "os" + "path/filepath" + "strings" log "github.com/Sirupsen/logrus" "github.com/ugorji/go/codec" @@ -118,3 +123,89 @@ func MakeFromBytes(buf []byte) (*Report, error) { } return &rep, nil } + +// MakeFromFile construct a Report from a file, with the encoding +// determined by the extension (".msgpack" or ".json", with an +// optional ".gz"). +func MakeFromFile(path string) (rpt Report, _ error) { + f, err := os.Open(path) + if err != nil { + return rpt, err + } + defer f.Close() + + handle, gzipped, err := handlerFromFileType(path) + if err != nil { + return rpt, err + } + + var buf []byte + if gzipped { + r, err := gzip.NewReader(f) + if err != nil { + return rpt, err + } + buf, err = ioutil.ReadAll(r) + } else { + buf, err = ioutil.ReadAll(f) + } + if err != nil { + return rpt, err + } + err = rpt.ReadBytes(buf, handle) + + return rpt, err +} + +// WriteToFile writes a Report to a file. The encoding is determined +// by the file extension (".msgpack" or ".json", with an optional +// ".gz"). +func (rep *Report) WriteToFile(path string, compressionLevel int) error { + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + + handle, gzipped, err := handlerFromFileType(path) + if err != nil { + return err + } + + var w io.Writer + bufwriter := bufio.NewWriter(f) + defer bufwriter.Flush() + w = bufwriter + if gzipped { + gzwriter, err := gzip.NewWriterLevel(w, compressionLevel) + if err != nil { + return err + } + defer gzwriter.Close() + w = gzwriter + } + + if err = codec.NewEncoder(w, handle).Encode(rep); err != nil { + return err + } + + return nil + +} + +func handlerFromFileType(path string) (codec.Handle, bool, error) { + fileType := filepath.Ext(path) + gzipped := false + if fileType == ".gz" { + gzipped = true + fileType = filepath.Ext(strings.TrimSuffix(path, fileType)) + } + switch fileType { + case ".json": + return &codec.JsonHandle{}, gzipped, nil + case ".msgpack": + return &codec.MsgpackHandle{}, gzipped, nil + default: + return nil, false, fmt.Errorf("Unsupported file extension: %v", fileType) + } +}