From f8e44643c1b29a31a80077bf1b122944f6f45a1b Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Fri, 12 Mar 2021 16:04:54 -0500 Subject: [PATCH 1/4] Split out logs into subcommmands --- internal/cli/logs.go | 183 +++++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 59 deletions(-) diff --git a/internal/cli/logs.go b/internal/cli/logs.go index 0ae9a090e..a1c1df714 100644 --- a/internal/cli/logs.go +++ b/internal/cli/logs.go @@ -10,32 +10,79 @@ import ( "gopkg.in/auth0.v5/management" ) -func getLatestLogs(cli *cli, n int, clientID string) ([]*management.Log, error) { - page := 0 - perPage := n +func logsCmd(cli *cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "logs", + Short: "View tenant logs", + } - if perPage > 1000 { - // Pagination max out at 1000 entries in total - // https://auth0.com/docs/logs/retrieve-log-events-using-mgmt-api#limitations - perPage = 1000 + cmd.SetUsageTemplate(resourceUsageTemplate()) + cmd.AddCommand(listLogsCmd(cli)) + cmd.AddCommand(tailLogsCmd(cli)) + + return cmd +} + +func listLogsCmd(cli *cli) *cobra.Command { + var flags struct { + Num int + NoColor bool } - queryParams := []management.RequestOption{ - management.Parameter("sort", "date:-1"), - management.Parameter("page", fmt.Sprintf("%d", page)), - management.Parameter("per_page", fmt.Sprintf("%d", perPage))} + var inputs struct { + ClientID string + } - if clientID != "" { - queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, clientID))) + cmd := &cobra.Command{ + Use: "list [client-id]", + Args: cobra.MaximumNArgs(1), + Short: "Show the tenant logs", + Long: `Show the tenant logs: + +auth0 logs list [client-id] +`, + RunE: func(cmd *cobra.Command, args []string) error { + inputs.ClientID = "" + if len(args) == 1 { + inputs.ClientID = args[0] + } + + list, err := getLatestLogs(cli, flags.Num, inputs.ClientID) + if err != nil { + return fmt.Errorf("An unexpected error occurred while getting logs: %v", 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) + + var logsCh chan []*management.Log + + // We create an execution API decorator which provides + // a leaky bucket implementation for Read. This + // protects us from being rate limited since we + // potentially have an N+1 querying situation. + actionExecutionAPI := actions.NewSampledExecutionAPI( + cli.api.ActionExecution, time.Second, + ) + + cli.renderer.LogList(list, logsCh, actionExecutionAPI, flags.NoColor, !cli.debug) + return nil + }, } - return cli.api.Log.List(queryParams...) + cmd.Flags().IntVarP(&flags.Num, "num-entries", "n", 100, "the number of log entries to print") + cmd.Flags().BoolVar(&flags.NoColor, "no-color", false, "turn off colored print") + + return cmd } -func logsCmd(cli *cli) *cobra.Command { +func tailLogsCmd(cli *cli) *cobra.Command { var flags struct { Num int - Follow bool NoColor bool } @@ -44,12 +91,12 @@ func logsCmd(cli *cli) *cobra.Command { } cmd := &cobra.Command{ - Use: "logs [client-id]", + Use: "tail [client-id]", Args: cobra.MaximumNArgs(1), - Short: "Show the tenant logs", - Long: `Show the tenant logs: + Short: "Tail the tenant logs", + Long: `Tail the tenant logs: -auth0 logs [client-id] +auth0 logs tail [client-id] `, RunE: func(cmd *cobra.Command, args []string) error { inputs.ClientID = "" @@ -73,46 +120,43 @@ auth0 logs [client-id] lastLogID = list[len(list)-1].GetLogID() } - var logsCh chan []*management.Log - if flags.Follow && lastLogID != "" { - logsCh = make(chan []*management.Log) - - go func() { - // This is pretty important and allows - // us to close / terminate the command. - defer close(logsCh) - - for { - queryParams := []management.RequestOption{ - management.Query(fmt.Sprintf("log_id:[%s TO *]", lastLogID)), - management.Parameter("page", "0"), - management.Parameter("per_page", "100"), - management.Parameter("sort", "date:-1"), - } - - if inputs.ClientID != "" { - queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, inputs.ClientID))) - } - - list, err = cli.api.Log.List(queryParams...) - if err != nil { - cli.renderer.Errorf("An unexpected error occurred while getting logs: %v", err) - 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) - } + logsCh := make(chan []*management.Log) + + go func() { + // This is pretty important and allows + // us to close / terminate the command. + defer close(logsCh) + + for { + queryParams := []management.RequestOption{ + management.Query(fmt.Sprintf("log_id:[%s TO *]", lastLogID)), + management.Parameter("page", "0"), + management.Parameter("per_page", "100"), + management.Parameter("sort", "date:-1"), } - }() - } + if inputs.ClientID != "" { + queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, inputs.ClientID))) + } + + list, err = cli.api.Log.List(queryParams...) + if err != nil { + cli.renderer.Errorf("An unexpected error occurred while getting logs: %v", err) + 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) + } + } + + }() // We create an execution API decorator which provides // a leaky bucket implementation for Read. This @@ -128,12 +172,33 @@ auth0 logs [client-id] } cmd.Flags().IntVarP(&flags.Num, "num-entries", "n", 100, "the number of log entries to print") - cmd.Flags().BoolVarP(&flags.Follow, "follow", "f", false, "Specify if the logs should be streamed") cmd.Flags().BoolVar(&flags.NoColor, "no-color", false, "turn off colored print") return cmd } +func getLatestLogs(cli *cli, n int, ClientID string) ([]*management.Log, error) { + page := 0 + 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 + perPage = 1000 + } + + queryParams := []management.RequestOption{ + management.Parameter("sort", "date:-1"), + management.Parameter("page", fmt.Sprintf("%d", page)), + management.Parameter("per_page", fmt.Sprintf("%d", perPage))} + + if ClientID != "" { + queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, ClientID))) + } + + return cli.api.Log.List(queryParams...) +} + func dedupLogs(list []*management.Log, set map[string]struct{}) []*management.Log { res := make([]*management.Log, 0, len(list)) From 961768a4b0d400f41033cb4914d082981652ef6a Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Fri, 12 Mar 2021 16:04:54 -0500 Subject: [PATCH 2/4] Split out logs into subcommmands --- internal/cli/logs.go | 183 +++++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 59 deletions(-) diff --git a/internal/cli/logs.go b/internal/cli/logs.go index 0ae9a090e..a1c1df714 100644 --- a/internal/cli/logs.go +++ b/internal/cli/logs.go @@ -10,32 +10,79 @@ import ( "gopkg.in/auth0.v5/management" ) -func getLatestLogs(cli *cli, n int, clientID string) ([]*management.Log, error) { - page := 0 - perPage := n +func logsCmd(cli *cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "logs", + Short: "View tenant logs", + } - if perPage > 1000 { - // Pagination max out at 1000 entries in total - // https://auth0.com/docs/logs/retrieve-log-events-using-mgmt-api#limitations - perPage = 1000 + cmd.SetUsageTemplate(resourceUsageTemplate()) + cmd.AddCommand(listLogsCmd(cli)) + cmd.AddCommand(tailLogsCmd(cli)) + + return cmd +} + +func listLogsCmd(cli *cli) *cobra.Command { + var flags struct { + Num int + NoColor bool } - queryParams := []management.RequestOption{ - management.Parameter("sort", "date:-1"), - management.Parameter("page", fmt.Sprintf("%d", page)), - management.Parameter("per_page", fmt.Sprintf("%d", perPage))} + var inputs struct { + ClientID string + } - if clientID != "" { - queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, clientID))) + cmd := &cobra.Command{ + Use: "list [client-id]", + Args: cobra.MaximumNArgs(1), + Short: "Show the tenant logs", + Long: `Show the tenant logs: + +auth0 logs list [client-id] +`, + RunE: func(cmd *cobra.Command, args []string) error { + inputs.ClientID = "" + if len(args) == 1 { + inputs.ClientID = args[0] + } + + list, err := getLatestLogs(cli, flags.Num, inputs.ClientID) + if err != nil { + return fmt.Errorf("An unexpected error occurred while getting logs: %v", 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) + + var logsCh chan []*management.Log + + // We create an execution API decorator which provides + // a leaky bucket implementation for Read. This + // protects us from being rate limited since we + // potentially have an N+1 querying situation. + actionExecutionAPI := actions.NewSampledExecutionAPI( + cli.api.ActionExecution, time.Second, + ) + + cli.renderer.LogList(list, logsCh, actionExecutionAPI, flags.NoColor, !cli.debug) + return nil + }, } - return cli.api.Log.List(queryParams...) + cmd.Flags().IntVarP(&flags.Num, "num-entries", "n", 100, "the number of log entries to print") + cmd.Flags().BoolVar(&flags.NoColor, "no-color", false, "turn off colored print") + + return cmd } -func logsCmd(cli *cli) *cobra.Command { +func tailLogsCmd(cli *cli) *cobra.Command { var flags struct { Num int - Follow bool NoColor bool } @@ -44,12 +91,12 @@ func logsCmd(cli *cli) *cobra.Command { } cmd := &cobra.Command{ - Use: "logs [client-id]", + Use: "tail [client-id]", Args: cobra.MaximumNArgs(1), - Short: "Show the tenant logs", - Long: `Show the tenant logs: + Short: "Tail the tenant logs", + Long: `Tail the tenant logs: -auth0 logs [client-id] +auth0 logs tail [client-id] `, RunE: func(cmd *cobra.Command, args []string) error { inputs.ClientID = "" @@ -73,46 +120,43 @@ auth0 logs [client-id] lastLogID = list[len(list)-1].GetLogID() } - var logsCh chan []*management.Log - if flags.Follow && lastLogID != "" { - logsCh = make(chan []*management.Log) - - go func() { - // This is pretty important and allows - // us to close / terminate the command. - defer close(logsCh) - - for { - queryParams := []management.RequestOption{ - management.Query(fmt.Sprintf("log_id:[%s TO *]", lastLogID)), - management.Parameter("page", "0"), - management.Parameter("per_page", "100"), - management.Parameter("sort", "date:-1"), - } - - if inputs.ClientID != "" { - queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, inputs.ClientID))) - } - - list, err = cli.api.Log.List(queryParams...) - if err != nil { - cli.renderer.Errorf("An unexpected error occurred while getting logs: %v", err) - 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) - } + logsCh := make(chan []*management.Log) + + go func() { + // This is pretty important and allows + // us to close / terminate the command. + defer close(logsCh) + + for { + queryParams := []management.RequestOption{ + management.Query(fmt.Sprintf("log_id:[%s TO *]", lastLogID)), + management.Parameter("page", "0"), + management.Parameter("per_page", "100"), + management.Parameter("sort", "date:-1"), } - }() - } + if inputs.ClientID != "" { + queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, inputs.ClientID))) + } + + list, err = cli.api.Log.List(queryParams...) + if err != nil { + cli.renderer.Errorf("An unexpected error occurred while getting logs: %v", err) + 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) + } + } + + }() // We create an execution API decorator which provides // a leaky bucket implementation for Read. This @@ -128,12 +172,33 @@ auth0 logs [client-id] } cmd.Flags().IntVarP(&flags.Num, "num-entries", "n", 100, "the number of log entries to print") - cmd.Flags().BoolVarP(&flags.Follow, "follow", "f", false, "Specify if the logs should be streamed") cmd.Flags().BoolVar(&flags.NoColor, "no-color", false, "turn off colored print") return cmd } +func getLatestLogs(cli *cli, n int, ClientID string) ([]*management.Log, error) { + page := 0 + 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 + perPage = 1000 + } + + queryParams := []management.RequestOption{ + management.Parameter("sort", "date:-1"), + management.Parameter("page", fmt.Sprintf("%d", page)), + management.Parameter("per_page", fmt.Sprintf("%d", perPage))} + + if ClientID != "" { + queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, ClientID))) + } + + return cli.api.Log.List(queryParams...) +} + func dedupLogs(list []*management.Log, set map[string]struct{}) []*management.Log { res := make([]*management.Log, 0, len(list)) From 26e920b240021c2ac0866f5a6bb1758e7d407b3d Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Mon, 15 Mar 2021 10:17:25 -0400 Subject: [PATCH 3/4] Fix casing. --- internal/cli/logs.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/cli/logs.go b/internal/cli/logs.go index a1c1df714..8da76480a 100644 --- a/internal/cli/logs.go +++ b/internal/cli/logs.go @@ -177,7 +177,7 @@ auth0 logs tail [client-id] return cmd } -func getLatestLogs(cli *cli, n int, ClientID string) ([]*management.Log, error) { +func getLatestLogs(cli *cli, n int, clientID string) ([]*management.Log, error) { page := 0 perPage := n @@ -192,8 +192,8 @@ func getLatestLogs(cli *cli, n int, ClientID string) ([]*management.Log, error) management.Parameter("page", fmt.Sprintf("%d", page)), management.Parameter("per_page", fmt.Sprintf("%d", perPage))} - if ClientID != "" { - queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, ClientID))) + if clientID != "" { + queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, clientID))) } return cli.api.Log.List(queryParams...) From 9f2506f3c0b4ace15dbf660c1cdb96f9e3b11ba7 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Mon, 15 Mar 2021 10:23:14 -0400 Subject: [PATCH 4/4] Fix merge error. --- internal/cli/logs.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/internal/cli/logs.go b/internal/cli/logs.go index bc527de0b..8da76480a 100644 --- a/internal/cli/logs.go +++ b/internal/cli/logs.go @@ -177,11 +177,7 @@ auth0 logs tail [client-id] return cmd } -<<<<<<< HEAD func getLatestLogs(cli *cli, n int, clientID string) ([]*management.Log, error) { -======= -func getLatestLogs(cli *cli, n int, ClientID string) ([]*management.Log, error) { ->>>>>>> f8e44643c1b29a31a80077bf1b122944f6f45a1b page := 0 perPage := n @@ -196,13 +192,8 @@ func getLatestLogs(cli *cli, n int, ClientID string) ([]*management.Log, error) management.Parameter("page", fmt.Sprintf("%d", page)), management.Parameter("per_page", fmt.Sprintf("%d", perPage))} -<<<<<<< HEAD if clientID != "" { queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, clientID))) -======= - if ClientID != "" { - queryParams = append(queryParams, management.Query(fmt.Sprintf(`client_id:"%s"`, ClientID))) ->>>>>>> f8e44643c1b29a31a80077bf1b122944f6f45a1b } return cli.api.Log.List(queryParams...)