Skip to content

Commit

Permalink
Feature/error handling (#18)
Browse files Browse the repository at this point in the history
* Error handling refactoring

* Bug fixes and performance enhancements
  • Loading branch information
aurc authored Jul 29, 2022
1 parent 23e8828 commit 8ceaaa8
Show file tree
Hide file tree
Showing 30 changed files with 208 additions and 107 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
main
.idea
loggo
testdata/log.txt
internal/testdata/log.txt
dist/
# Test binary, built with `go test -c`
*.test
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ Stack Driver ([Google Logs](https://cloud.google.com/logging), see [GCP-Stream C
<tr>
<td>
<p>Without l`oGGo</p>
<img src="mov/term.gif">
<img src="img/mov/term.gif">
</td>
<td>
<p>With l`oGGo</p>
<img src="mov/loggo.gif">
<img src="img/mov/loggo.gif">
</td>
</tr>
</table>
Expand Down Expand Up @@ -131,12 +131,12 @@ Note that you can pipe to anything that produces an output to the `stdin`.
- Navigate Left-Right-Up-Down on Large Grids
- Select a Line
- Use the arrow keys (`↓ ↑ ← →`)
![](mov/nav_right_left.gif)
![](img/mov/nav_right_left.gif)
- Select on screen text
- Horizontally based selection (`Alt` + Mouse `Click/Drag`)
- Block/Vertical based selection (`Cmd`+`Opt`+ Mouse `Click/Drag` - macOS)
- Copy the selected text to clipboard (`Cmd`+`C` - macOS/`Ctrl`+`C` - other systems)
![](mov/selection.gif)
![](img/mov/selection.gif)
- Configure Rendering Templates:
![](img/render_template.png)
- Fine Tune how columns are displayed (Template):
Expand Down Expand Up @@ -223,7 +223,7 @@ templates prior using the loggo command.

**Blank Canvas:**

![](mov/template.gif)
![](img/mov/template.gif)
````
loggo template
````
Expand Down
11 changes: 3 additions & 8 deletions cmd/gcpstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ from a given selected project and GCP logging filters:
`,
Run: func(cmd *cobra.Command, args []string) {
projectName := cmd.Flag("project").Value.String()
from := reader.ParseFrom(cmd.Flag("from").Value.String())
from := cmd.Flag("from").Value.String()
filter := cmd.Flag("filter").Value.String()
templateFile := cmd.Flag("template").Value.String()
saveParams := cmd.Flag("params-save").Value.String()
Expand Down Expand Up @@ -91,13 +91,8 @@ from a given selected project and GCP logging filters:
if len(projectName) == 0 {
log.Fatal("--project flag is required.")
}
inputChan := make(chan string, 1000)
reader := reader.MakeGCPReader(projectName, filter, from)

if err := reader.StreamInto(inputChan); err != nil {
log.Fatalf("unable to start app %v", err)
}
app := loggo.NewLoggoApp(inputChan, templateFile)
reader := reader.MakeGCPReader(projectName, filter, reader.ParseFrom(from), nil)
app := loggo.NewLoggoApp(reader, templateFile)
app.Run()
}
},
Expand Down
10 changes: 2 additions & 8 deletions cmd/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/aurc/loggo/internal/loggo"
"github.com/aurc/loggo/internal/reader"
"github.com/spf13/cobra"
"log"
)

// streamCmd represents the stream command
Expand All @@ -43,13 +42,8 @@ rotation and continue to stream. For example:
Run: func(cmd *cobra.Command, args []string) {
fileName := cmd.Flag("file").Value.String()
templateFile := cmd.Flag("template").Value.String()
inputChan := make(chan string, 1000)
reader := reader.MakeReader(fileName)

if err := reader.StreamInto(inputChan); err != nil {
log.Fatalf("unable to start app %v", err)
}
app := loggo.NewLoggoApp(inputChan, templateFile)
reader := reader.MakeReader(fileName, nil)
app := loggo.NewLoggoApp(reader, templateFile)
app.Run()
},
}
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions internal/config/log_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestMakeConfig(t *testing.T) {
},
{
name: "Valid value supplied",
givenFile: "../../config-sample/gcp.yaml",
givenFile: "../config-sample/gcp.yaml",
wants: defConfig,
},
{
Expand All @@ -54,7 +54,7 @@ func TestMakeConfig(t *testing.T) {
},
{
name: "Bad format file",
givenFile: "../../testdata/test3.txt",
givenFile: "../testdata/test3.txt",
wants: defConfig,
wantsError: true,
},
Expand Down
21 changes: 19 additions & 2 deletions internal/filter/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ THE SOFTWARE.
package filter

import (
"encoding/json"
"fmt"
"strings"

Expand Down Expand Up @@ -108,8 +109,13 @@ type Expression struct {
}

type ConditionElement struct {
Condition *Condition ` @@`
Subexpression *Expression `| "(" @@ ")"`
Condition *Condition ` @@`
GlobalToken *GlobalToken `| @@ `
Subexpression *Expression `| "(" @@ ")"`
}

type GlobalToken struct {
String *string `@String`
}

type Condition struct {
Expand Down Expand Up @@ -161,11 +167,22 @@ func (c *ConditionElement) Apply(row map[string]interface{}, key map[string]*con
switch {
case c.Condition != nil:
return c.Condition.Apply(row, key)
case c.GlobalToken != nil:
return c.GlobalToken.Apply(row)
default:
return c.Subexpression.Apply(row, key)
}
}

func (g *GlobalToken) Apply(row map[string]interface{}) (bool, error) {
b, err := json.Marshal(row)
if err != nil {
return false, err
}
str := strings.ToLower(string(b))
return strings.Contains(str, strings.ToLower(*g.String)), nil
}

func (c *Condition) Apply(row map[string]interface{}, key map[string]*config.Key) (bool, error) {
var op Operation
switch strings.ToUpper(c.Operator) {
Expand Down
27 changes: 27 additions & 0 deletions internal/filter/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,33 @@ func TestParseFilterExpression(t *testing.T) {
givenExpression: `((a/b = "x" OR a/b = "y") AND (c between 1 AND 3 OR c > 5))`,
wantsResult: true,
},
{
name: `wants true - global token`,
whenJsonRow: `
{
"a": {
"b": "y",
"z": "Something different"
},
"c": "2"
}`,
keySet: map[string]*config.Key{
"a/b": {
Name: "a/b",
Type: config.TypeString,
},
"a/z": {
Name: "a/z",
Type: config.TypeString,
},
"c": {
Name: "c",
Type: config.TypeNumber,
},
},
givenExpression: `((a/b = "x" OR a/b = "y") AND "ME")`,
wantsResult: true,
},
{
name: `wants true - 7 is greater than 5`,
whenJsonRow: `
Expand Down
11 changes: 6 additions & 5 deletions internal/loggo/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ package loggo

import (
"github.com/aurc/loggo/internal/config"
"github.com/aurc/loggo/internal/reader"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

type LoggoApp struct {
appScaffold
input <-chan string
logView *LogView
chanReader reader.Reader
logView *LogView
}

type Loggo interface {
Expand All @@ -48,14 +49,14 @@ type Loggo interface {
PopView()
}

func NewLoggoApp(input <-chan string, configFile string) *LoggoApp {
func NewLoggoApp(reader reader.Reader, configFile string) *LoggoApp {
app := NewApp(configFile)
lapp := &LoggoApp{
appScaffold: *app,
input: input,
chanReader: reader,
}

lapp.logView = NewLogReader(lapp, input)
lapp.logView = NewLogReader(lapp, reader)

lapp.pages = tview.NewPages().
AddPage("background", lapp.logView, true, true)
Expand Down
72 changes: 45 additions & 27 deletions internal/loggo/log_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package loggo
import (
"encoding/json"
"fmt"
"github.com/aurc/loggo/internal/reader"
"regexp"
"strings"
"time"
Expand All @@ -38,7 +39,7 @@ import (
type LogView struct {
tview.Flex
app *LoggoApp
input <-chan string
chanReader reader.Reader
table *tview.Table
jsonView *JsonView
data *LogData
Expand All @@ -56,16 +57,26 @@ type LogView struct {
isFollowing bool
}

func NewLogReader(app *LoggoApp, input <-chan string) *LogView {
func NewLogReader(app *LoggoApp, reader reader.Reader) *LogView {
lv := &LogView{
Flex: *tview.NewFlex(),
app: app,
config: app.Config(),
input: input,
chanReader: reader,
isFollowing: true,
}
lv.makeUIComponents()
lv.makeLayouts()
reader.ErrorNotifier(func(err error) {
lv.app.ShowPrefabModal(fmt.Sprintf("An error occurred with the input stream: %v "+
"\nYou can continue browsing the buffered logs or close the app.", err), 50, 20,
tview.NewButton("Quit").SetSelectedFunc(func() {
lv.app.Stop()
}),
tview.NewButton("Continue").SetSelectedFunc(func() {

}))
})
lv.read()
go func() {
lv.app.ShowModal(NewSplashScreen(lv.app), 71, 16, tcell.ColorBlack)
Expand All @@ -83,31 +94,38 @@ func NewLogReader(app *LoggoApp, input <-chan string) *LogView {

func (l *LogView) read() {
go func() {
lastUpdate := time.Now().Add(-time.Minute)
for {
t := <-l.input
if len(t) > 0 {
l.globalCount++
m := make(map[string]interface{})
err := json.Unmarshal([]byte(t), &m)
if err != nil {
m[config.ParseErr] = err.Error()
m[config.TextPayload] = t
}
l.inSlice = append(l.inSlice, m)
if len(l.config.LastSavedName) == 0 {
if len(l.inSlice) > 20 {
l.processSampleForConfig(l.inSlice[len(l.inSlice)-20:])
} else {
l.processSampleForConfig(l.inSlice)
if err := l.chanReader.StreamInto(); err != nil {
l.app.ShowPrefabModal(fmt.Sprintf("Unable to start stream: %v", err), 40, 10,
tview.NewButton("Quit").SetSelectedFunc(func() {
l.app.Stop()
}))
} else {
lastUpdate := time.Now().Add(-time.Minute)
for {
t := <-l.chanReader.ChanReader()
if len(t) > 0 {
l.globalCount++
m := make(map[string]interface{})
err := json.Unmarshal([]byte(t), &m)
if err != nil {
m[config.ParseErr] = err.Error()
m[config.TextPayload] = t
}
l.inSlice = append(l.inSlice, m)
if len(l.config.LastSavedName) == 0 {
if len(l.inSlice) > 20 {
l.processSampleForConfig(l.inSlice[len(l.inSlice)-20:])
} else {
l.processSampleForConfig(l.inSlice)
}
}
l.updateLineView()
now := time.Now()
if now.Sub(lastUpdate)*time.Millisecond > 500 && l.isFollowing {
lastUpdate = now
l.app.Draw()
l.table.ScrollToEnd()
}
}
l.updateLineView()
now := time.Now()
if now.Sub(lastUpdate)*time.Millisecond > 500 && l.isFollowing {
lastUpdate = now
l.app.Draw()
l.table.ScrollToEnd()
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions internal/reader/file_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ type fileStream struct {
tail *tail.Tail
}

func (s *fileStream) StreamInto(strChan chan<- string) error {
s.strChan = strChan
func (s *fileStream) StreamInto() error {
var err error
s.tail, err = tail.TailFile(s.fileName, tail.Config{Follow: true})
if err != nil {
Expand All @@ -44,7 +43,7 @@ func (s *fileStream) StreamInto(strChan chan<- string) error {

go func() {
for line := range s.tail.Lines {
strChan <- line.Text
s.strChan <- line.Text
}
}()
return nil
Expand Down
6 changes: 3 additions & 3 deletions internal/reader/file_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ func TestFileStream_StreamInto(t *testing.T) {

// Routine to write file lines
before := time.Now().UnixMilli()
reader := MakeReader(filePath)
streamReceiver := make(chan string, 1)
reader := MakeReader(filePath, streamReceiver)
go func() {
for i := 0; i < 10; i++ {
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)
Expand All @@ -61,9 +62,8 @@ func TestFileStream_StreamInto(t *testing.T) {
}
reader.Close()
}()
streamReceiver := make(chan string, 1)
var lines []string
_ = reader.StreamInto(streamReceiver)
_ = reader.StreamInto()
for {
line, ok := <-streamReceiver
if !ok {
Expand Down
Loading

0 comments on commit 8ceaaa8

Please sign in to comment.