From b39a9ea117a4f8d4dff201792ed7b965e57bcf00 Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Mon, 19 Aug 2019 20:00:27 +0300 Subject: [PATCH] refactor: logparser --- interfaces/05-log-parser/oop/analysis.go | 25 +++++---- interfaces/05-log-parser/oop/chartsummary.go | 3 ++ interfaces/05-log-parser/oop/filters.go | 2 + interfaces/05-log-parser/oop/groupers.go | 2 + interfaces/05-log-parser/oop/jsonparser.go | 20 +++----- interfaces/05-log-parser/oop/main.go | 34 ++++++------- interfaces/05-log-parser/oop/report.go | 53 ++++++++++++++------ interfaces/05-log-parser/oop/result.go | 2 + interfaces/05-log-parser/oop/textparser.go | 32 +++--------- interfaces/05-log-parser/oop/textsummary.go | 15 ++---- 10 files changed, 94 insertions(+), 94 deletions(-) diff --git a/interfaces/05-log-parser/oop/analysis.go b/interfaces/05-log-parser/oop/analysis.go index 45e5edd..84cc24b 100644 --- a/interfaces/05-log-parser/oop/analysis.go +++ b/interfaces/05-log-parser/oop/analysis.go @@ -9,11 +9,6 @@ package main import "sort" -type ( - groupFunc func(result) string - filterFunc func(result) bool -) - type analysis struct { sum map[string]result // metrics per domain keys []string // unique keys @@ -29,9 +24,19 @@ func newAnalysis() *analysis { } } -func (a *analysis) groupBy(g groupFunc) { a.groupKey = g } -func (a *analysis) filterBy(f filterFunc) { a.filter = f } +func (a *analysis) groupBy(g groupFunc) { + if g != nil { + a.groupKey = g + } +} +func (a *analysis) filterBy(f filterFunc) { + if f != nil { + a.filter = f + } +} + +// analyse the given result func (a *analysis) analyse(r result) { if !a.filter(r) { return @@ -45,11 +50,11 @@ func (a *analysis) analyse(r result) { a.sum[key] = r.add(a.sum[key]) } -// each analysed result will be sent by the given func -func (a *analysis) each(f func(r result)) { +// each sends an analysis result to `handle` +func (a *analysis) each(handle resultFn) { sort.Strings(a.keys) for _, domain := range a.keys { - f(a.sum[domain]) + handle(a.sum[domain]) } } diff --git a/interfaces/05-log-parser/oop/chartsummary.go b/interfaces/05-log-parser/oop/chartsummary.go index 0064236..2e6a6de 100644 --- a/interfaces/05-log-parser/oop/chartsummary.go +++ b/interfaces/05-log-parser/oop/chartsummary.go @@ -7,6 +7,9 @@ import ( c "github.com/wcharczuk/go-chart" ) +// You need to run: +// go get -u github.com/wcharczuk/go-chart + type chartSummary struct { title string width, height int diff --git a/interfaces/05-log-parser/oop/filters.go b/interfaces/05-log-parser/oop/filters.go index c5032ef..1087847 100644 --- a/interfaces/05-log-parser/oop/filters.go +++ b/interfaces/05-log-parser/oop/filters.go @@ -2,6 +2,8 @@ package main import "strings" +type filterFunc func(result) bool + func noopFilter(r result) bool { return true } diff --git a/interfaces/05-log-parser/oop/groupers.go b/interfaces/05-log-parser/oop/groupers.go index 5bf2a17..967e565 100644 --- a/interfaces/05-log-parser/oop/groupers.go +++ b/interfaces/05-log-parser/oop/groupers.go @@ -1,5 +1,7 @@ package main +type groupFunc func(result) string + // domainGrouper groups by domain. // but it keeps the other fields. // for example: it returns pages as well, but you shouldn't use them. diff --git a/interfaces/05-log-parser/oop/jsonparser.go b/interfaces/05-log-parser/oop/jsonparser.go index c08c393..97dc04f 100644 --- a/interfaces/05-log-parser/oop/jsonparser.go +++ b/interfaces/05-log-parser/oop/jsonparser.go @@ -15,18 +15,14 @@ import ( ) type jsonParser struct { - r io.Reader - update func(r result) + r io.Reader } func newJSONParser(r io.Reader) *jsonParser { - return &jsonParser{ - r: r, - update: func(result) {}, - } + return &jsonParser{r: r} } -func (p *jsonParser) parse() error { +func (p *jsonParser) parse(handle resultFn) error { defer readClose(p.r) bytes, err := ioutil.ReadAll(p.r) @@ -34,10 +30,10 @@ func (p *jsonParser) parse() error { return err } - return p.parseJSON(bytes) + return parseJSON(bytes, handle) } -func (p *jsonParser) parseJSON(bytes []byte) error { +func parseJSON(bytes []byte, handle resultFn) error { var rs []struct { Domain string Page string @@ -53,7 +49,7 @@ func (p *jsonParser) parseJSON(bytes []byte) error { } for _, r := range rs { - p.update(result{ + handle(result{ domain: r.Domain, page: r.Page, visits: r.Visits, @@ -63,7 +59,3 @@ func (p *jsonParser) parseJSON(bytes []byte) error { return nil } - -func (p *jsonParser) notify(f func(r result)) { - p.update = f -} diff --git a/interfaces/05-log-parser/oop/main.go b/interfaces/05-log-parser/oop/main.go index 10f09d0..c8a9b16 100644 --- a/interfaces/05-log-parser/oop/main.go +++ b/interfaces/05-log-parser/oop/main.go @@ -9,31 +9,29 @@ package main import ( "log" + // "fmt" "os" ) func main() { - an := newAnalysis() - an.filterBy(notUsing(domainExtFilter("io", "com"))) - an.groupBy(domainGrouper) + a := newAnalysis() + // a.filterBy(notUsing(domainExtFilter("io", "com"))) + // a.groupBy(domainGrouper) - // pars, err := parseTextFile("log.txt") - // if err != nil { - // log.Fatalln(err) - // } + p := newTextParser(os.Stdin) + s := newTextSummary() - err := report(an, newTextParser(os.Stdin), summarizeFunc(textSummary)) - // err := report(an, newJSONParser(os.Stdin), newTextSummary()) + // s := &chartSummary{ + // title: "visits per domain", + // width: 1920, + // height: 800, + // } - // chart := &chartSummary{ - // title: "visits per domain", - // width: 1920, - // height: 800, - // } - - // err := report(an, newTextParser(os.Stdin), chart) - - if err != nil { + if err := report(p, a, s); err != nil { log.Fatalln(err) } + + // if err := reportFromFile(os.Args[1]); err != nil { + // log.Fatalln(err) + // } } diff --git a/interfaces/05-log-parser/oop/report.go b/interfaces/05-log-parser/oop/report.go index 46367ef..4375b3b 100644 --- a/interfaces/05-log-parser/oop/report.go +++ b/interfaces/05-log-parser/oop/report.go @@ -7,34 +7,57 @@ package main -type notifier interface { - notify(func(r result)) -} +import ( + "errors" + "os" + "strings" +) + +type resultFn func(result) type parser interface { - parse() error - notifier -} - -type iterator interface { - each(func(result)) + parse(resultFn) error } type analyser interface { analyse(result) - iterator +} + +type iterator interface { + each(resultFn) } type summarizer interface { summarize(iterator) error } -func report(a analyser, p parser, s summarizer) error { - p.notify(a.analyse) - - if err := p.parse(); err != nil { +func report(p parser, a analyser, s summarizer) error { + if err := p.parse(a.analyse); err != nil { return err } - return s.summarize(a) + it, ok := a.(iterator) + if !ok { + return errors.New("cannot iterate on analyser") + } + + return s.summarize(it) +} + +// reportFromFile generates a default report +func reportFromFile(path string) (err error) { + f, err := os.Open(path) + if err != nil { + return err + } + + var p parser + switch { + case strings.HasSuffix(path, ".txt"): + p = newTextParser(f) + case strings.HasSuffix(path, ".json"): + p = newJSONParser(f) + } + + return report(p, newAnalysis(), newTextSummary()) } diff --git a/interfaces/05-log-parser/oop/result.go b/interfaces/05-log-parser/oop/result.go index 9906822..65c22bf 100644 --- a/interfaces/05-log-parser/oop/result.go +++ b/interfaces/05-log-parser/oop/result.go @@ -1,5 +1,7 @@ package main +const fieldsLength = 4 + type result struct { domain string page string diff --git a/interfaces/05-log-parser/oop/textparser.go b/interfaces/05-log-parser/oop/textparser.go index 4f3c2a5..9894494 100644 --- a/interfaces/05-log-parser/oop/textparser.go +++ b/interfaces/05-log-parser/oop/textparser.go @@ -11,39 +11,19 @@ import ( "bufio" "fmt" "io" - "os" "strconv" "strings" ) -const fieldsLength = 4 - type textParser struct { - r io.Reader - update func(r result) + r io.Reader } func newTextParser(r io.Reader) *textParser { - return &textParser{ - r: r, - update: func(result) {}, - } + return &textParser{r: r} } -func parseTextFile(path string) (*textParser, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - - return newTextParser(f), nil -} - -func (p *textParser) notify(f func(r result)) { - p.update = f -} - -func (p *textParser) parse() error { +func (p *textParser) parse(handle resultFn) error { defer readClose(p.r) var ( @@ -52,19 +32,19 @@ func (p *textParser) parse() error { ) for in.Scan() { - r, err := p.parseFields(in.Text()) + r, err := parseFields(in.Text()) if err != nil { return fmt.Errorf("line %d: %v", l, err) } - p.update(r) + handle(r) l++ } return in.Err() } -func (p *textParser) parseFields(s string) (r result, err error) { +func parseFields(s string) (r result, err error) { fields := strings.Fields(s) if len(fields) != fieldsLength { return r, fmt.Errorf("wrong number of fields %q", fields) diff --git a/interfaces/05-log-parser/oop/textsummary.go b/interfaces/05-log-parser/oop/textsummary.go index fec1fcc..e20376e 100644 --- a/interfaces/05-log-parser/oop/textsummary.go +++ b/interfaces/05-log-parser/oop/textsummary.go @@ -21,20 +21,13 @@ const ( flags = 0 ) -type summarizeFunc func(iterator) error +type textSummary struct{} -func (f summarizeFunc) summarize(results iterator) error { - return f(results) +func newTextSummary() *textSummary { + return new(textSummary) } -// type textSummary struct{} - -// func newTextSummary() *textSummary { -// return new(textSummary) -// } - -// func (s *textSummary) summarize(results iterator) error { -func textSummary(results iterator) error { +func (s *textSummary) summarize(results iterator) error { w := tabwriter.NewWriter(os.Stdout, minWidth, tabWidth, padding, ' ', flags) write := fmt.Fprintf