refactor: logparser v6
This commit is contained in:
		| @@ -21,11 +21,6 @@ func CountRecords(p Parser) *Count { | |||||||
| 	return &Count{Parser: p} | 	return &Count{Parser: p} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Last counted record number. |  | ||||||
| func (c *Count) Last() int { |  | ||||||
| 	return c.count - 1 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Parse increments the counter. | // Parse increments the counter. | ||||||
| func (c *Count) Parse() bool { | func (c *Count) Parse() bool { | ||||||
| 	c.count++ | 	c.count++ | ||||||
| @@ -34,8 +29,9 @@ func (c *Count) Parse() bool { | |||||||
| 
 | 
 | ||||||
| // Err returns the first error that was encountered by the Log. | // Err returns the first error that was encountered by the Log. | ||||||
| func (c *Count) Err() (err error) { | func (c *Count) Err() (err error) { | ||||||
| 	if err = c.Parser.Err(); err != nil { | 	err = c.Parser.Err() | ||||||
| 		err = fmt.Errorf("record #%d: %v", c.Last()+1, err) | 	if err != nil { | ||||||
|  | 		err = fmt.Errorf("record #%d: %v", c.count, err) | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @@ -10,20 +10,22 @@ package parse | |||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"io" | 	"io" | ||||||
|  | 
 | ||||||
|  | 	"github.com/inancgumus/learngo/logparser/v6/logly/record" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // JSONParser parses json records. | // JSONParser parses json records. | ||||||
| type JSONParser struct { | type JSONParser struct { | ||||||
| 	in   *json.Decoder | 	in   *json.Decoder | ||||||
| 	err  error   // last error | 	err  error          // last error | ||||||
| 	last *Record // last parsed record | 	last *record.Record // last parsed record | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // JSON creates a json parser. | // JSON creates a json parser. | ||||||
| func JSON(r io.Reader) *JSONParser { | func JSON(r io.Reader) *JSONParser { | ||||||
| 	return &JSONParser{ | 	return &JSONParser{ | ||||||
| 		in:   json.NewDecoder(r), | 		in:   json.NewDecoder(r), | ||||||
| 		last: new(Record), | 		last: new(record.Record), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -34,6 +36,7 @@ func (p *JSONParser) Parse() bool { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	p.last.Reset() | 	p.last.Reset() | ||||||
|  | 
 | ||||||
| 	err := p.in.Decode(&p.last) | 	err := p.in.Decode(&p.last) | ||||||
| 	if err == io.EOF { | 	if err == io.EOF { | ||||||
| 		return false | 		return false | ||||||
| @@ -45,7 +48,7 @@ func (p *JSONParser) Parse() bool { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Value returns the most recent record parsed by a call to Parse. | // Value returns the most recent record parsed by a call to Parse. | ||||||
| func (p *JSONParser) Value() Record { | func (p *JSONParser) Value() record.Record { | ||||||
| 	return *p.last | 	return *p.last | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -7,13 +7,15 @@ | |||||||
| 
 | 
 | ||||||
| package parse | package parse | ||||||
| 
 | 
 | ||||||
|  | import "github.com/inancgumus/learngo/logparser/v6/logly/record" | ||||||
|  | 
 | ||||||
| // Parser is an interface for the parsers. | // Parser is an interface for the parsers. | ||||||
| type Parser interface { | type Parser interface { | ||||||
| 	// Parse the next record from the source. | 	// Parse the next record from the source. | ||||||
| 	Parse() bool | 	Parse() bool | ||||||
| 
 | 
 | ||||||
| 	// Value returns the last parsed record by a call to Parse. | 	// Value returns the last parsed record by a call to Parse. | ||||||
| 	Value() Record | 	Value() record.Record | ||||||
| 
 | 
 | ||||||
| 	// Err returns the first error that was encountered. | 	// Err returns the first error that was encountered. | ||||||
| 	Err() error | 	Err() error | ||||||
| @@ -10,35 +10,41 @@ package parse | |||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
| 	"io" | 	"io" | ||||||
|  | 
 | ||||||
|  | 	"github.com/inancgumus/learngo/logparser/v6/logly/record" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // TextParser parses text based log lines. | // TextParser parses text based log lines. | ||||||
| type TextParser struct { | type TextParser struct { | ||||||
| 	in   *bufio.Scanner | 	in   *bufio.Scanner | ||||||
| 	err  error   // last error | 	err  error          // last error | ||||||
| 	last *Record // last parsed record | 	last *record.Record // last parsed record | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Text creates a text parser. | // Text creates a text parser. | ||||||
| func Text(r io.Reader) *TextParser { | func Text(r io.Reader) *TextParser { | ||||||
| 	return &TextParser{ | 	return &TextParser{ | ||||||
| 		in:   bufio.NewScanner(r), | 		in:   bufio.NewScanner(r), | ||||||
| 		last: new(Record), | 		last: new(record.Record), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Parse the next line. | // Parse the next line. | ||||||
| func (p *TextParser) Parse() bool { | func (p *TextParser) Parse() bool { | ||||||
| 	if p.err != nil || !p.in.Scan() { | 	if p.err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if !p.in.Scan() { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	p.err = p.last.FromText(p.in.Bytes()) | 	p.err = p.last.FromText(p.in.Bytes()) | ||||||
|  | 
 | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Value returns the most recent record parsed by a call to Parse. | // Value returns the most recent record parsed by a call to Parse. | ||||||
| func (p *TextParser) Value() Record { | func (p *TextParser) Value() record.Record { | ||||||
| 	return *p.last | 	return *p.last | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
							
								
								
									
										22
									
								
								logparser/v6/logly/record/json.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								logparser/v6/logly/record/json.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | // 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 record | ||||||
|  |  | ||||||
|  | import "encoding/json" | ||||||
|  |  | ||||||
|  | // UnmarshalJSON to a record. | ||||||
|  | func (r *Record) UnmarshalJSON(data []byte) error { | ||||||
|  | 	type rjson Record | ||||||
|  |  | ||||||
|  | 	err := json.Unmarshal(data, (*rjson)(r)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r.validate() | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								logparser/v6/logly/record/record.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								logparser/v6/logly/record/record.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | package record | ||||||
|  |  | ||||||
|  | const fieldsLength = 4 | ||||||
|  |  | ||||||
|  | // Record stores fields of a log line. | ||||||
|  | type Record struct { | ||||||
|  | 	Domain  string | ||||||
|  | 	Page    string | ||||||
|  | 	Visits  int | ||||||
|  | 	Uniques int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sum the numeric fields with another record. | ||||||
|  | func (r *Record) Sum(other Record) { | ||||||
|  | 	r.Visits += other.Visits | ||||||
|  | 	r.Uniques += other.Uniques | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Reset all the fields of this record. | ||||||
|  | func (r *Record) Reset() { | ||||||
|  | 	r.Domain = "" | ||||||
|  | 	r.Page = "" | ||||||
|  | 	r.Visits = 0 | ||||||
|  | 	r.Uniques = 0 | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								logparser/v6/logly/record/sum.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								logparser/v6/logly/record/sum.go
									
									
									
									
									
										Normal 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 record | ||||||
|  |  | ||||||
|  | // Sum groups the records by summing their numeric fields. | ||||||
|  | type Sum struct { | ||||||
|  | 	sum map[string]Record | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SumGroup the records by domain. | ||||||
|  | func SumGroup() *Sum { | ||||||
|  | 	return &Sum{ | ||||||
|  | 		sum: make(map[string]Record), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Group the record. | ||||||
|  | func (s *Sum) Group(r Record) { | ||||||
|  | 	k := r.Domain | ||||||
|  | 	r.Sum(s.sum[k]) | ||||||
|  | 	s.sum[k] = r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Records returns the grouped records. | ||||||
|  | func (s *Sum) Records() []Record { | ||||||
|  | 	var out []Record | ||||||
|  | 	for _, res := range s.sum { | ||||||
|  | 		out = append(out, res) | ||||||
|  | 	} | ||||||
|  | 	return out | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								logparser/v6/logly/record/text.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								logparser/v6/logly/record/text.go
									
									
									
									
									
										Normal 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 record | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // FromText unmarshals the log line into this record. | ||||||
|  | func (r *Record) FromText(p []byte) (err error) { | ||||||
|  | 	fields := strings.Fields(string(p)) | ||||||
|  |  | ||||||
|  | 	if len(fields) != fieldsLength { | ||||||
|  | 		return fmt.Errorf("wrong number of fields %q", fields) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.Domain = fields[0] | ||||||
|  | 	r.Page = fields[1] | ||||||
|  |  | ||||||
|  | 	const msg = "record.UnmarshalText %q: %v" | ||||||
|  | 	if r.Visits, err = strconv.Atoi(fields[2]); err != nil { | ||||||
|  | 		return fmt.Errorf(msg, "visits", err) | ||||||
|  | 	} | ||||||
|  | 	if r.Uniques, err = strconv.Atoi(fields[3]); err != nil { | ||||||
|  | 		return fmt.Errorf(msg, "uniques", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r.validate() | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								logparser/v6/logly/record/validate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								logparser/v6/logly/record/validate.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | // 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 record | ||||||
|  |  | ||||||
|  | import "errors" | ||||||
|  |  | ||||||
|  | // validate whether the current record is valid or not. | ||||||
|  | func (r *Record) validate() error { | ||||||
|  | 	var msg string | ||||||
|  |  | ||||||
|  | 	switch { | ||||||
|  | 	case r.Domain == "": | ||||||
|  | 		msg = "record.domain cannot be empty" | ||||||
|  | 	case r.Page == "": | ||||||
|  | 		msg = "record.page cannot be empty" | ||||||
|  | 	case r.Visits < 0: | ||||||
|  | 		msg = "record.visits cannot be negative" | ||||||
|  | 	case r.Uniques < 0: | ||||||
|  | 		msg = "record.uniques cannot be negative" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if msg != "" { | ||||||
|  | 		return errors.New(msg) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								logparser/v6/logly/report/json.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								logparser/v6/logly/report/json.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // 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 report | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"io" | ||||||
|  |  | ||||||
|  | 	"github.com/inancgumus/learngo/logparser/v6/logly/record" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // JSON generates a json report. | ||||||
|  | func JSON(w io.Writer, rs []record.Record) error { | ||||||
|  | 	enc := json.NewEncoder(w) | ||||||
|  |  | ||||||
|  | 	for _, r := range rs { | ||||||
|  | 		err := enc.Encode(&r) | ||||||
|  |  | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								logparser/v6/logly/report/text.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								logparser/v6/logly/report/text.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | // For more tutorials: https://brecord.learngoprogramming.com | ||||||
|  | // | ||||||
|  | // Copyright © 2018 Inanc Gumus | ||||||
|  | // Learn Go Programming Course | ||||||
|  | // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ | ||||||
|  | // | ||||||
|  |  | ||||||
|  | package report | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"text/tabwriter" | ||||||
|  |  | ||||||
|  | 	"github.com/inancgumus/learngo/logparser/v6/logly/record" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Text generates a text report. | ||||||
|  | func Text(w io.Writer, rs []record.Record) error { | ||||||
|  | 	tw := tabwriter.NewWriter( | ||||||
|  | 		w, | ||||||
|  | 		0,   // minWidth | ||||||
|  | 		4,   // tabWidth | ||||||
|  | 		4,   // padding | ||||||
|  | 		' ', // padChar | ||||||
|  | 		0,   // flags | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	fmt.Fprintf(tw, "DOMAINS\tPAGES\tVISITS\tUNIQUES\n") | ||||||
|  | 	fmt.Fprintf(tw, "-------\t-----\t------\t-------\n") | ||||||
|  |  | ||||||
|  | 	var total record.Record | ||||||
|  | 	for _, r := range rs { | ||||||
|  | 		total.Sum(r) | ||||||
|  |  | ||||||
|  | 		fmt.Fprintf(tw, "%s\t%s\t%d\t%d\n", | ||||||
|  | 			r.Domain, r.Page, | ||||||
|  | 			r.Visits, r.Uniques, | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fmt.Fprintf(tw, "\t\t\t\n") | ||||||
|  | 	fmt.Fprintf(tw, "%s\t%s\t%d\t%d\n", | ||||||
|  | 		"TOTAL", "", | ||||||
|  | 		total.Visits, total.Uniques, | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	return tw.Flush() | ||||||
|  | } | ||||||
| @@ -8,49 +8,28 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" |  | ||||||
| 	"log" | 	"log" | ||||||
| 	"os" | 	"os" | ||||||
|  |  | ||||||
| 	"github.com/inancgumus/learngo/logparser/v6/parse" | 	"github.com/inancgumus/learngo/logparser/v6/logly/parse" | ||||||
| 	"github.com/inancgumus/learngo/logparser/v6/report" | 	"github.com/inancgumus/learngo/logparser/v6/logly/record" | ||||||
|  | 	"github.com/inancgumus/learngo/logparser/v6/logly/report" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| 	// trace.Start(os.Stderr) | 	var ( | ||||||
| 	// defer trace.Stop() | 		p = parse.CountRecords(parse.Text(os.Stdin)) | ||||||
|  | 		g = record.SumGroup() | ||||||
|  | 	) | ||||||
|  |  | ||||||
| 	var p parse.Parser |  | ||||||
| 	// p = parse.Text(os.Stdin) |  | ||||||
| 	p = parse.JSON(os.Stdin) |  | ||||||
| 	p = parse.CountRecords(p) |  | ||||||
|  |  | ||||||
| 	r := report.Text(os.Stdout) |  | ||||||
|  |  | ||||||
| 	var out []parse.Record |  | ||||||
| 	for p.Parse() { | 	for p.Parse() { | ||||||
| 		r := p.Value() | 		g.Group(p.Value()) | ||||||
|  |  | ||||||
| 		// if !parse.Filter(r) { |  | ||||||
| 		// 	continue |  | ||||||
| 		// } |  | ||||||
|  |  | ||||||
| 		// sum.group(r) |  | ||||||
| 		out = append(out, r) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := p.Err(); err != nil { | 	if err := p.Err(); err != nil { | ||||||
| 		log.Fatalln(err) | 		log.Fatalln(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// var out []parse.Record | 	if err := report.Text(os.Stdout, g.Records()); err != nil { | ||||||
| 	// for sum.More() { |  | ||||||
|  |  | ||||||
| 	// } |  | ||||||
|  |  | ||||||
| 	if err := r.Generate(out); err != nil { |  | ||||||
| 		log.Fatalln(err) | 		log.Fatalln(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fmt.Println(p.(*parse.Count).Last(), "records are processed.") |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,88 +0,0 @@ | |||||||
| package parse |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const fieldsLength = 4 |  | ||||||
|  |  | ||||||
| // Record stores fields of a log line. |  | ||||||
| type Record struct { |  | ||||||
| 	Domain  string |  | ||||||
| 	Page    string |  | ||||||
| 	Visits  int |  | ||||||
| 	Uniques int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Sum the numeric fields with another record. |  | ||||||
| func (r *Record) Sum(other Record) { |  | ||||||
| 	r.Visits += other.Visits |  | ||||||
| 	r.Uniques += other.Uniques |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Reset all the fields of this record. |  | ||||||
| func (r *Record) Reset() { |  | ||||||
| 	r.Domain = "" |  | ||||||
| 	r.Page = "" |  | ||||||
| 	r.Visits = 0 |  | ||||||
| 	r.Uniques = 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // FromText unmarshals the log line into this record. |  | ||||||
| func (r *Record) FromText(p []byte) (err error) { |  | ||||||
| 	fields := strings.Fields(string(p)) |  | ||||||
|  |  | ||||||
| 	if len(fields) != fieldsLength { |  | ||||||
| 		return fmt.Errorf("wrong number of fields %q", fields) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.Domain = fields[0] |  | ||||||
| 	r.Page = fields[1] |  | ||||||
|  |  | ||||||
| 	const msg = "record.UnmarshalText %q: %v" |  | ||||||
| 	if r.Visits, err = strconv.Atoi(fields[2]); err != nil { |  | ||||||
| 		return fmt.Errorf(msg, "visits", err) |  | ||||||
| 	} |  | ||||||
| 	if r.Uniques, err = strconv.Atoi(fields[3]); err != nil { |  | ||||||
| 		return fmt.Errorf(msg, "uniques", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return r.validate() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // UnmarshalJSON to a record. |  | ||||||
| func (r *Record) UnmarshalJSON(data []byte) error { |  | ||||||
| 	type rjson Record |  | ||||||
|  |  | ||||||
| 	err := json.Unmarshal(data, (*rjson)(r)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return r.validate() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // validate whether the current record is valid or not. |  | ||||||
| func (r *Record) validate() error { |  | ||||||
| 	var msg string |  | ||||||
|  |  | ||||||
| 	switch { |  | ||||||
| 	case r.Domain == "": |  | ||||||
| 		msg = "record.domain cannot be empty" |  | ||||||
| 	case r.Page == "": |  | ||||||
| 		msg = "record.page cannot be empty" |  | ||||||
| 	case r.Visits < 0: |  | ||||||
| 		msg = "record.visits cannot be negative" |  | ||||||
| 	case r.Uniques < 0: |  | ||||||
| 		msg = "record.uniques cannot be negative" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if msg != "" { |  | ||||||
| 		return errors.New(msg) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| // 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 report |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"io" |  | ||||||
|  |  | ||||||
| 	"github.com/inancgumus/learngo/logparser/v6/parse" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // JSONReport generates a JSON report. |  | ||||||
| type JSONReport struct { |  | ||||||
| 	w *json.Encoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // JSON returns a JSON report generator. |  | ||||||
| func JSON(w io.Writer) *JSONReport { |  | ||||||
| 	return &JSONReport{ |  | ||||||
| 		w: json.NewEncoder(w), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Generate the report from the records. |  | ||||||
| func (jr *JSONReport) Generate(rs []parse.Record) error { |  | ||||||
| 	for _, r := range rs { |  | ||||||
| 		if err := jr.w.Encode(&r); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,60 +0,0 @@ | |||||||
| // 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 report |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"text/tabwriter" |  | ||||||
|  |  | ||||||
| 	"github.com/inancgumus/learngo/logparser/v6/parse" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // TextReport report generator. |  | ||||||
| type TextReport struct { |  | ||||||
| 	w     *tabwriter.Writer |  | ||||||
| 	total parse.Record |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Text creates a report generator. |  | ||||||
| func Text(w io.Writer) *TextReport { |  | ||||||
| 	tw := tabwriter.NewWriter(w, |  | ||||||
| 		0,   // minWidth |  | ||||||
| 		4,   // tabWidth |  | ||||||
| 		4,   // padding |  | ||||||
| 		' ', // padChar |  | ||||||
| 		0,   // flags |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	return &TextReport{w: tw} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Generate the report from the records. |  | ||||||
| // tabwriter caches, the memory usage will be high |  | ||||||
| // if you send a large number of records to Generate. |  | ||||||
| func (tr *TextReport) Generate(rs []parse.Record) error { |  | ||||||
| 	fmt.Fprintf(tr.w, "DOMAINS\tPAGES\tVISITS\tUNIQUES\n") |  | ||||||
| 	fmt.Fprintf(tr.w, "-------\t-----\t------\t-------\n") |  | ||||||
|  |  | ||||||
| 	for _, r := range rs { |  | ||||||
| 		tr.total.Sum(r) |  | ||||||
|  |  | ||||||
| 		fmt.Fprintf(tr.w, "%s\t%s\t%d\t%d\n", |  | ||||||
| 			r.Domain, r.Page, |  | ||||||
| 			r.Visits, r.Uniques, |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fmt.Fprintf(tr.w, "\t\t\t\n") |  | ||||||
| 	fmt.Fprintf(tr.w, "%s\t%s\t%d\t%d\n", |  | ||||||
| 		"TOTAL", "", |  | ||||||
| 		tr.total.Visits, tr.total.Uniques, |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	return tr.w.Flush() |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user