Skip to content

Commit

Permalink
Finalize
Browse files Browse the repository at this point in the history
  • Loading branch information
cyx committed Jan 26, 2021
1 parent 3fa4cc5 commit b94717b
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 69 deletions.
2 changes: 1 addition & 1 deletion internal/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/olekukonko/tablewriter"
"github.com/jsanda/tablewriter"
)

// TODO(cyx): think about whether we should extract this function in the
Expand Down
118 changes: 64 additions & 54 deletions internal/cli/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,27 @@ package cli

import (
"fmt"
"sort"
"time"

"github.com/auth0/auth0-cli/internal/ansi"
"github.com/spf13/cobra"
"gopkg.in/auth0.v5/management"
)

func getLatestLogs(cli *cli, n int) (result []*management.Log, err error) {
var list []*management.Log
func getLatestLogs(cli *cli, n int) ([]*management.Log, error) {
page := 0
perPage := 100
var count int
if count = n; n > 1000 {
perPage := n

if perPage > 1000 {
// Pagination max out at 1000 entries in total
// https://auth0.com/docs/logs/retrieve-log-events-using-mgmt-api#limitations
count = 1000
}
if perPage > count {
perPage = count
perPage = 1000
}

err = ansi.Spinner("Getting logs", func() error {
for count > len(result) {
var err error
list, err = cli.api.Log.List(
management.Parameter("sort", "date:-1"),
management.Parameter("page", fmt.Sprintf("%d", page)),
management.Parameter("per_page", fmt.Sprintf("%d", perPage)),
)
if err != nil {
return err
}

sort.Slice(list, func(i, j int) bool {
return list[i].GetDate().Before(list[j].GetDate())
})
result = append(list, result...)
if len(list) < perPage {
// We've got all
break
}
page++
}
return err
})

return
return cli.api.Log.List(
management.Parameter("sort", "date:-1"),
management.Parameter("page", fmt.Sprintf("%d", page)),
management.Parameter("per_page", fmt.Sprintf("%d", perPage)),
)
}

func logsCmd(cli *cli) *cobra.Command {
Expand All @@ -68,29 +41,52 @@ Show the tenant logs.
if err != nil {
return err
}

// TODO(cyx): This is a hack for now to make the
// streaming work faster.
//
// Create a `set` to detect duplicates clientside.
set := make(map[string]struct{})
list = dedupLogs(list, set)

if len(list) > 0 {
lastLogID = list[len(list)-1].GetLogID()
cli.renderer.LogList(list, noColor)
}

var logsCh chan []*management.Log
if follow {
for {
list, err = cli.api.Log.List(
management.Parameter("from", lastLogID),
management.Parameter("take", "100"),
)
if err != nil {
return err
}
if len(list) > 0 {
cli.renderer.LogList(list, noColor)
lastLogID = list[len(list)-1].GetLogID()
}
if len(list) < 90 {
// Not a lot is happening, sleep on it
time.Sleep(1 * time.Second)
logsCh = make(chan []*management.Log)

go func() {
// This is pretty important and allows
// us to close / terminate the command.
defer close(logsCh)

for {
list, err = cli.api.Log.List(
management.Query(fmt.Sprintf("log_id:[%s TO *]", lastLogID)),
management.Parameter("sort", "date:-1"),
management.Parameter("take", "100"),
)
if err != nil {
return
}

if len(list) > 0 {
logsCh <- dedupLogs(list, set)
lastLogID = list[len(list)-1].GetLogID()
}

if len(list) < 90 {
// Not a lot is happening, sleep on it
time.Sleep(1 * time.Second)
}
}
}

}()
}

cli.renderer.LogList(list, logsCh, noColor)
return nil
},
}
Expand All @@ -101,3 +97,17 @@ Show the tenant logs.

return cmd
}

func dedupLogs(list []*management.Log, set map[string]struct{}) []*management.Log {
res := make([]*management.Log, 0, len(list))

for _, l := range list {
if _, ok := set[l.GetID()]; !ok {
// It's not a duplicate, track it, and take it.
set[l.GetID()] = struct{}{}
res = append(res, l)
}
}

return res
}
2 changes: 1 addition & 1 deletion internal/display/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (r *Renderer) ActionList(actions []*management.Action) {

func (r *Renderer) ActionTest(payload management.Object) {
r.Heading(ansi.Bold(r.Tenant), "Actions test result\n")
r.JSONResult(payload)
r.JSONResult(payload, nil)
}

func (r *Renderer) ActionCreate(action *management.Action) {
Expand Down
45 changes: 35 additions & 10 deletions internal/display/display.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ type View interface {
AsTableRow() []string
}

func (r *Renderer) JSONResult(data interface{}) {
func (r *Renderer) JSONResult(data interface{}, ch <-chan View) {
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
r.Errorf("couldn't marshal results as JSON: %v", err)
Expand All @@ -73,24 +73,28 @@ func (r *Renderer) JSONResult(data interface{}) {
}

func (r *Renderer) Results(data []View) {
r.Stream(data, nil)
}

func (r *Renderer) Stream(data []View, ch <-chan View) {
if len(data) > 0 {
switch r.Format {
case OutputFormatJSON:
r.JSONResult(data)
r.JSONResult(data, ch)

default:
rows := make([][]string, len(data))
for i, d := range data {
rows[i] = d.AsTableRow()
}
writeTable(r.ResultWriter, data[0].AsTableHeader(), rows)
writeTable(r.ResultWriter, data[0].AsTableHeader(), rows, ch)
}
}
}

func writeTable(w io.Writer, header []string, data [][]string) {
tableString := &strings.Builder{}
table := tablewriter.NewWriter(tableString)
func writeTable(w io.Writer, header []string, data [][]string, ch <-chan View) {
// tableString := &strings.Builder{}
table := tablewriter.NewWriter(w)
table.SetHeader(header)

table.SetAutoWrapText(false)
Expand All @@ -103,12 +107,33 @@ func writeTable(w io.Writer, header []string, data [][]string) {
table.SetHeaderLine(false)
table.SetBorder(false)

for _, v := range data {
table.Append(v)
if ch == nil {
for _, v := range data {
table.Append(v)
}
table.Render()
return
}

table.Render()
fmt.Fprint(w, tableString.String())
done := make(chan struct{})
strCh := make(chan []string)
go func() {
defer close(done)

for _, v := range data {
strCh <- v
}

for v := range ch {
strCh <- v.AsTableRow()
}
}()

go func() {
table.ContinuousRender(strCh)
}()

<-done
}

func timeAgo(ts time.Time) string {
Expand Down
22 changes: 20 additions & 2 deletions internal/display/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,29 @@ func typeDescFor(l *management.Log, noColor bool) (typ, desc string) {
return typ, desc
}

func (r *Renderer) LogList(logs []*management.Log, noColor bool) {
func (r *Renderer) LogList(logs []*management.Log, ch <-chan []*management.Log, noColor bool) {
r.Heading(ansi.Bold(r.Tenant), "logs\n")

var res []View
for _, l := range logs {
res = append(res, &logView{Log: l})
}

r.Results(res)
var viewChan chan View

if ch != nil {
viewChan = make(chan View)

go func() {
defer close(viewChan)

for list := range ch {
for _, l := range list {
viewChan <- &logView{Log: l}
}
}
}()
}

r.Stream(res, viewChan)
}
2 changes: 1 addition & 1 deletion internal/display/try_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,6 @@ func (r *Renderer) TryLogin(u *auth.UserInfo, t *auth.TokenResponse, reveal bool
}

tableHeader := []string{"Field", "Value"}
writeTable(r.ResultWriter, tableHeader, rows)
writeTable(r.ResultWriter, tableHeader, rows, nil)
}
}

0 comments on commit b94717b

Please sign in to comment.