add: logparser funcs to the methods for baseline

This commit is contained in:
Inanc Gumus
2019-07-27 18:16:02 +03:00
parent 9b396b501f
commit e191567e1f
9 changed files with 253 additions and 0 deletions

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org 4
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org -100
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,6 @@
learngoprogramming.com 10
learngoprogramming.com 10
golang.org FOUR
golang.org 6
blog.golang.org 20
blog.golang.org 10

View File

@ -0,0 +1,26 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"bufio"
"os"
)
func main() {
p := newParser()
in := bufio.NewScanner(os.Stdin)
for in.Scan() {
res := parse(p, in.Text())
updateSummary(p.summary, res)
}
summarize(summarizeParse(p))
dumpErrs(errParse(p), in.Err())
}

View File

@ -0,0 +1,70 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"strconv"
"strings"
)
// parser parses the log file and generates a summary report.
type parser struct {
summary *summary // summarizes the parsing results
lines int // number of parsed lines (for the error messages)
lerr error // the last error occurred
}
// new returns a new parsing state.
func newParser() *parser {
return &parser{summary: newSummary()}
}
// parse parses a log line and adds it to the summary.
func parse(p *parser, line string) (r result) {
// if there was an error do not continue
if p.lerr != nil {
return
}
// chain the parser's error to the result's
r = parseLine(p, line)
if p.lines++; p.lerr != nil {
p.lerr = fmt.Errorf("line #%d: %s", p.lines, p.lerr)
}
return
}
// parse parses a single log line
func parseLine(p *parser, line string) (r result) {
fields := strings.Fields(line)
if len(fields) != 2 {
// p.lerr = fmt.Errorf("wrong input: %v (line #%d)", fields, p.lines)
p.lerr = fmt.Errorf("missing fields: %v", fields)
return
}
r.domain = fields[0]
r.visits, p.lerr = strconv.Atoi(fields[1])
if r.visits < 0 || p.lerr != nil {
p.lerr = fmt.Errorf("incorrect visits: %q", fields[1])
}
return
}
// summarizeParse summarizes the parsing results.
// Only use it after the parsing is done.
func summarizeParse(p *parser) *summary {
return p.summary
}
// errParse returns the last error encountered
func errParse(p *parser) error {
return p.lerr
}

View File

@ -0,0 +1,27 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
// always put all the related things together as in here
// result stores metrics for a domain
// it uses the value mechanics,
// because it doesn't have to update anything
type result struct {
domain string
visits int
// add more metrics if needed
}
// add adds the metrics of another result to itself and returns a new Result
func addResult(r result, other result) result {
return result{
domain: r.domain,
visits: r.visits + other.visits,
}
}

View File

@ -0,0 +1,36 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"strings"
)
// summarize prints the parsing results.
func summarize(s *summary) {
fmt.Printf("%-30s %10s\n", "DOMAIN", "VISITS")
fmt.Println(strings.Repeat("-", 45))
for next, cur := iteratorSummary(s); next(); {
r := cur()
fmt.Printf("%-30s %10d\n", r.domain, r.visits)
}
t := totalsSummary(s)
fmt.Printf("\n"+"%-30s %10d\n", "TOTAL", t.visits)
}
// this variadic func simplifies the multiple error handling
func dumpErrs(errs ...error) {
for _, err := range errs {
if err != nil {
fmt.Printf("> Err: %s\n", err)
}
}
}

View File

@ -0,0 +1,70 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"sort"
)
// summary aggregates the parsing results
type summary struct {
sum map[string]result // metrics per domain
domains []string // unique domain names
total result // total visits for all domains
}
// newSummary constructs and initializes a new summary
// You can't use its methods without pointer mechanics
func newSummary() *summary {
return &summary{sum: make(map[string]result)}
}
// updateSummary updates the report for the given parsing result
func updateSummary(s *summary, r result) {
domain := r.domain
if _, ok := s.sum[domain]; !ok {
s.domains = append(s.domains, domain)
}
// let the result handle the addition
// this allows us to manage the result in once place
// and this way it becomes easily extendable
s.total = addResult(s.total, r)
s.sum[domain] = addResult(r, s.sum[domain])
}
// iteratorSummary returns `next()` to detect when the iteration ends,
// and a `cur()` to return the current result.
// iterator iterates sorted by domains.
func iteratorSummary(s *summary) (next func() bool, cur func() result) {
sort.Strings(s.domains)
// remember the last iterated result
var last int
next = func() bool {
// done := len(s.domains) > last
// last++
// return done
defer func() { last++ }()
return len(s.domains) > last
}
cur = func() result {
// returns a copy so the caller cannot change it
name := s.domains[last-1]
return s.sum[name]
}
return
}
// totalsSummary returns the total metrics
func totalsSummary(s *summary) result {
return s.total
}