Skip to content

Commit

Permalink
introduce pkg structure (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
facundoolano committed Jul 30, 2024
1 parent a798228 commit edc6645
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 23 deletions.
19 changes: 10 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"github.com/alecthomas/kong"
"github.com/facundoolano/ngtop/ngtop"
)

type CommandArgs struct {
Expand Down Expand Up @@ -54,10 +55,10 @@ func main() {
logFormat = envLogFormat
}

parser := NewParser(logFormat)
parser := ngtop.NewParser(logFormat)

ctx, spec := querySpecFromCLI()
dbs, err := InitDB(dbPath, parser.Fields)
dbs, err := ngtop.InitDB(dbPath, parser.Fields)
ctx.FatalIfErrorf(err)
defer dbs.Close()

Expand All @@ -70,10 +71,10 @@ func main() {
}

// Parse the command line arguments into a top requests query specification
func querySpecFromCLI() (*kong.Context, *RequestCountSpec) {
func querySpecFromCLI() (*kong.Context, *ngtop.RequestCountSpec) {
// Parse query spec first, i.e. don't bother with db updates if the command is invalid
fieldNames := make([]string, 0, len(CLI_NAME_TO_FIELD))
for k := range CLI_NAME_TO_FIELD {
fieldNames := make([]string, 0, len(ngtop.CLI_NAME_TO_FIELD))
for k := range ngtop.CLI_NAME_TO_FIELD {
fieldNames = append(fieldNames, k)
}

Expand All @@ -96,13 +97,13 @@ func querySpecFromCLI() (*kong.Context, *RequestCountSpec) {
// translate field name aliases
columns := make([]string, len(cli.Fields))
for i, field := range cli.Fields {
columns[i] = CLI_NAME_TO_FIELD[field].ColumnName
columns[i] = ngtop.CLI_NAME_TO_FIELD[field].ColumnName
}

whereConditions, err := resolveWhereConditions(cli.Where)
ctx.FatalIfErrorf(err)

spec := &RequestCountSpec{
spec := &ngtop.RequestCountSpec{
GroupByMetrics: columns,
TimeSince: since,
TimeUntil: until,
Expand All @@ -129,7 +130,7 @@ func resolveWhereConditions(clauses []string) (map[string][]string, error) {
return nil, fmt.Errorf("invalid where expression %s", clause)
}

if field, found := CLI_NAME_TO_FIELD[keyvalue[0]]; found {
if field, found := ngtop.CLI_NAME_TO_FIELD[keyvalue[0]]; found {
conditions[field.ColumnName] = append(conditions[field.ColumnName], keyvalue[1])
} else {
return nil, fmt.Errorf("unknown field name %s", keyvalue[0])
Expand Down Expand Up @@ -172,7 +173,7 @@ func parseDuration(duration string) (time.Time, error) {
}

// Parse the most recent nginx access.logs and insert the ones not previously seen into the DB.
func loadLogs(parser *LogParser, logPathPattern string, dbs *dbSession) error {
func loadLogs(parser *ngtop.LogParser, logPathPattern string, dbs *ngtop.DBSession) error {
logFiles, err := filepath.Glob(logPathPattern)
if err != nil {
return err
Expand Down
6 changes: 4 additions & 2 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"reflect"
"testing"
"time"

"github.com/facundoolano/ngtop/ngtop"
)

func TestDurationParsing(t *testing.T) {
Expand Down Expand Up @@ -286,8 +288,8 @@ func runCommand(t *testing.T, format string, logs string, cliArgs []string) ([]s
os.Args = append([]string{"ngtop"}, cliArgs...)
_, spec := querySpecFromCLI()

parser := NewParser(format)
dbs, err := InitDB(dbFile.Name(), parser.Fields)
parser := ngtop.NewParser(format)
dbs, err := ngtop.InitDB(dbFile.Name(), parser.Fields)
assertEqual(t, err, nil)
defer dbs.Close()

Expand Down
18 changes: 9 additions & 9 deletions db.go → ngtop/db.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package ngtop

import (
"database/sql"
Expand All @@ -18,7 +18,7 @@ type RequestCountSpec struct {
Where map[string][]string
}

type dbSession struct {
type DBSession struct {
db *sql.DB
columns []string
insertTx *sql.Tx
Expand All @@ -28,7 +28,7 @@ type dbSession struct {
const DB_DATE_LAYOUT = "2006-01-02 15:04:05-07:00"

// Open or create the database at the given path.
func InitDB(dbPath string, fields []*LogField) (*dbSession, error) {
func InitDB(dbPath string, fields []*LogField) (*DBSession, error) {
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
return nil, err
Expand All @@ -55,15 +55,15 @@ func InitDB(dbPath string, fields []*LogField) (*dbSession, error) {
);`, columnSpecs)

_, err = db.Exec(sqlStmt)
return &dbSession{db: db, columns: columns}, err
return &DBSession{db: db, columns: columns}, err
}

func (dbs *dbSession) Close() {
func (dbs *DBSession) Close() {
dbs.db.Close()
}

// Prepare a transaction to insert a new batch of log entries, returning the time of the last seen log entry.
func (dbs *dbSession) PrepareForUpdate() (*time.Time, error) {
func (dbs *DBSession) PrepareForUpdate() (*time.Time, error) {
// we want to avoid processed files that were already processed in the past. but we still want to add new log entries
// from the most recent files, which may have been extended since we last saw them.
// Since there is no "uniqueness" in logs (even the same ip can make the same request at the same second ---I checked),
Expand Down Expand Up @@ -99,14 +99,14 @@ func (dbs *dbSession) PrepareForUpdate() (*time.Time, error) {
return lastSeemTime, nil
}

func (dbs *dbSession) AddLogEntry(values []any) error {
func (dbs *DBSession) AddLogEntry(values []any) error {
_, err := dbs.insertStmt.Exec(values...)
return err
}

// If the given processing `err` is nil, commit the log insertion transaction,
// Otherwise roll it back and return the error.
func (dbs *dbSession) FinishUpdate(err error) error {
func (dbs *DBSession) FinishUpdate(err error) error {
tx := dbs.insertTx
dbs.insertTx = nil
dbs.insertStmt = nil
Expand All @@ -118,7 +118,7 @@ func (dbs *dbSession) FinishUpdate(err error) error {
}

// Build a query from the spec and execute it, returning the results as stringified values.
func (dbs *dbSession) QueryTop(spec *RequestCountSpec) ([]string, [][]string, error) {
func (dbs *DBSession) QueryTop(spec *RequestCountSpec) ([]string, [][]string, error) {
queryString, queryArgs := spec.buildQuery()

rows, err := dbs.db.Query(queryString, queryArgs...)
Expand Down
2 changes: 1 addition & 1 deletion fields.go → ngtop/fields.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package ngtop

import (
"github.com/mileusna/useragent"
Expand Down
2 changes: 1 addition & 1 deletion parser.go → ngtop/parser.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package ngtop

import (
"bufio"
Expand Down
12 changes: 11 additions & 1 deletion parser_test.go → ngtop/parser_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package main
package ngtop

import (
"reflect"
"testing"
)

const DEFAULT_LOG_FORMAT = `$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"`

func TestFormatRegex(t *testing.T) {
line := `xx.xx.xx.xx - - [24/Jul/2024:00:00:28 +0000] "GET /feed HTTP/1.1" 301 169 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"`

Expand Down Expand Up @@ -52,3 +55,10 @@ func TestRefererOverride(t *testing.T) {
assertEqual(t, err, nil)
assertEqual(t, result["referer"], "olano.dev/feed.xml")
}

func assertEqual(t *testing.T, a interface{}, b interface{}) {
t.Helper()
if !reflect.DeepEqual(a, b) {
t.Fatalf("%v != %v", a, b)
}
}

0 comments on commit edc6645

Please sign in to comment.