From 09a5ed818b00c0dcb2b3727c6326a2ff20dd83d3 Mon Sep 17 00:00:00 2001 From: Will Vedder Date: Fri, 8 Dec 2023 08:31:07 -0500 Subject: [PATCH] Adding request pagination to `auth0 logs list` (#939) * Adding validation, updating docs to reflect validation * Simplifying logic * Adding tests * Fixing test YAML * stdout=>stderr in test * Correcting exit codes --------- Co-authored-by: Will Vedder --- docs/auth0_logs_list.md | 4 +- docs/auth0_logs_tail.md | 4 +- internal/cli/logs.go | 51 +++++++++++++++------ test/integration/logs-test-cases.yaml | 66 ++++++++++++++++++--------- 4 files changed, 85 insertions(+), 40 deletions(-) diff --git a/docs/auth0_logs_list.md b/docs/auth0_logs_list.md index 06ebbdd69..88d8d134d 100644 --- a/docs/auth0_logs_list.md +++ b/docs/auth0_logs_list.md @@ -22,7 +22,7 @@ auth0 logs list [flags] auth0 logs list --filter "user_name:" auth0 logs list --filter "ip:" auth0 logs list --filter "type:f" # See the full list of type codes at https://auth0.com/docs/logs/log-event-type-codes - auth0 logs ls -n 100 + auth0 logs ls -n 250 ``` @@ -31,7 +31,7 @@ auth0 logs list [flags] ``` -f, --filter string Filter in Lucene query syntax. See https://auth0.com/docs/logs/log-search-query-syntax for more details. --json Output in json format. - -n, --number int Number of log entries to show. (default 100) + -n, --number int Number of log entries to show. Minimum 1, maximum 1000. (default 100) ``` diff --git a/docs/auth0_logs_tail.md b/docs/auth0_logs_tail.md index b5cde23d1..a804d93a6 100644 --- a/docs/auth0_logs_tail.md +++ b/docs/auth0_logs_tail.md @@ -22,7 +22,7 @@ auth0 logs tail [flags] auth0 logs tail --filter "user_name:" auth0 logs tail --filter "ip:" auth0 logs tail --filter "type:f" # See the full list of type codes at https://auth0.com/docs/logs/log-event-type-codes - auth0 logs tail -n 100 + auth0 logs tail -n 10 ``` @@ -30,7 +30,7 @@ auth0 logs tail [flags] ``` -f, --filter string Filter in Lucene query syntax. See https://auth0.com/docs/logs/log-search-query-syntax for more details. - -n, --number int Number of log entries to show. (default 100) + -n, --number int Number of log entries to show. Minimum 1, maximum 1000. (default 100) ``` diff --git a/internal/cli/logs.go b/internal/cli/logs.go index d971c3842..7792f95c8 100644 --- a/internal/cli/logs.go +++ b/internal/cli/logs.go @@ -27,7 +27,7 @@ var ( Name: "Number of Entries", LongForm: "number", ShortForm: "n", - Help: "Number of log entries to show.", + Help: "Number of log entries to show. Minimum 1, maximum 1000.", } ) @@ -65,8 +65,11 @@ func listLogsCmd(cli *cli) *cobra.Command { auth0 logs list --filter "user_name:" auth0 logs list --filter "ip:" auth0 logs list --filter "type:f" # See the full list of type codes at https://auth0.com/docs/logs/log-event-type-codes - auth0 logs ls -n 100`, + auth0 logs ls -n 250`, RunE: func(cmd *cobra.Command, args []string) error { + if inputs.Num < 1 || inputs.Num > 1000 { + return fmt.Errorf("number flag invalid, please pass a number between 1 and 1000") + } list, err := getLatestLogs(cmd.Context(), cli, inputs.Num, inputs.Filter) if err != nil { return fmt.Errorf("failed to get logs: %w", err) @@ -104,8 +107,11 @@ func tailLogsCmd(cli *cli) *cobra.Command { auth0 logs tail --filter "user_name:" auth0 logs tail --filter "ip:" auth0 logs tail --filter "type:f" # See the full list of type codes at https://auth0.com/docs/logs/log-event-type-codes - auth0 logs tail -n 100`, + auth0 logs tail -n 10`, RunE: func(cmd *cobra.Command, args []string) error { + if inputs.Num < 1 || inputs.Num > 1000 { + return fmt.Errorf("number flag invalid, please pass a number between 1 and 1000") + } list, err := getLatestLogs(cmd.Context(), cli, inputs.Num, inputs.Filter) if err != nil { return fmt.Errorf("failed to get logs: %w", err) @@ -169,23 +175,38 @@ func tailLogsCmd(cli *cli) *cobra.Command { return cmd } -func getLatestLogs(ctx context.Context, cli *cli, n int, filter string) ([]*management.Log, error) { +func getLatestLogs(ctx context.Context, cli *cli, numRequested int, filter string) ([]*management.Log, error) { page := 0 - perPage := n - if perPage > logsPerPageLimit { - perPage = logsPerPageLimit - } + logs := []*management.Log{} + + for { + perPage := logsPerPageLimit + if numRequested < (page+1)*logsPerPageLimit { + perPage = numRequested % logsPerPageLimit + } - queryParams := []management.RequestOption{ - management.Parameter("sort", "date:-1"), - management.Parameter("page", fmt.Sprintf("%d", page)), - management.Parameter("per_page", fmt.Sprintf("%d", perPage))} + queryParams := []management.RequestOption{ + management.Parameter("sort", "date:-1"), + management.Parameter("page", fmt.Sprintf("%d", page)), + management.Parameter("per_page", fmt.Sprintf("%d", perPage))} - if filter != "" { - queryParams = append(queryParams, management.Query(filter)) + if filter != "" { + queryParams = append(queryParams, management.Query(filter)) + } + + res, err := cli.api.Log.List(ctx, queryParams...) + if err != nil { + return nil, err + } + logs = append(logs, res...) + + page++ + if page == 10 || (page*logsPerPageLimit) >= numRequested { + break + } } - return cli.api.Log.List(ctx, queryParams...) + return logs, nil } func dedupeLogs(list []*management.Log, set map[string]struct{}) []*management.Log { diff --git a/test/integration/logs-test-cases.yaml b/test/integration/logs-test-cases.yaml index 4210cdbe1..64408610b 100644 --- a/test/integration/logs-test-cases.yaml +++ b/test/integration/logs-test-cases.yaml @@ -14,24 +14,48 @@ tests: - CONNECTION - CLIENT - 002 - it successfully lists all log streams with no data: + 002 - it successfully lists a specific number of logs: + command: auth0 logs list --number 3 --json | jq length + exit-code: 0 + stdout: + exactly: "3" + + 003 - it successfully lists as many logs as possible: + command: auth0 logs list --number 1000 + exit-code: 0 + + 004 - it errors because of invalid number arg: + command: auth0 logs list --number 0 --json + exit-code: 1 + stderr: + contains: + - "number flag invalid, please pass a number between 1 and 1000" + + 005 - it errors because of invalid number arg: + command: auth0 logs list --number 1001 --json + exit-code: 1 + stderr: + contains: + - "number flag invalid, please pass a number between 1 and 1000" + + 006 - it successfully lists all log streams with no data: command: auth0 logs streams list exit-code: 0 stderr: contains: - Use 'auth0 logs streams create' to add one - 003 - it successfully lists all log streams with no data (json): + 007 - it successfully lists all log streams with no data (json): command: auth0 logs streams list --json exit-code: 0 stdout: exactly: "[]" - 004 - it successfully creates a datadog log stream: + 008 - it successfully creates a datadog log stream: command: ./test/integration/scripts/create-log-stream-datadog-id.sh exit-code: 0 - 005 - it successfully lists all log streams with data: + 009 - it successfully lists all log streams with data: command: auth0 logs streams list exit-code: 0 stdout: @@ -41,7 +65,7 @@ tests: - TYPE - STATUS - 006 - given a datadog log stream, it successfully gets the log stream's details: + 010 - given a datadog log stream, it successfully gets the log stream's details: command: auth0 logs streams show $(cat ./test/integration/identifiers/log-stream-datadog-id) exit-code: 0 stdout: @@ -50,7 +74,7 @@ tests: - TYPE datadog - STATUS active - 007 - given a datadog log stream, it successfully gets the log stream's details and outputs in json: + 011 - given a datadog log stream, it successfully gets the log stream's details and outputs in json: command: auth0 logs streams show $(cat ./test/integration/identifiers/log-stream-datadog-id) --json exit-code: 0 stdout: @@ -60,7 +84,7 @@ tests: status: "active" sink.datadogRegion: "eu" - 008 - given a datadog log stream, it successfully updates the log stream's details: + 012 - given a datadog log stream, it successfully updates the log stream's details: command: auth0 logs streams update datadog $(cat ./test/integration/identifiers/log-stream-datadog-id) --name integration-test-updated-datadog --region us --api-key 123123123123123 --json exit-code: 0 stdout: @@ -70,22 +94,22 @@ tests: status: "active" sink.datadogRegion: "us" - 009 - given a datadog log stream, it successfully opens the log stream's settings page: + 013 - given a datadog log stream, it successfully opens the log stream's settings page: command: auth0 logs streams open $(cat ./test/integration/identifiers/log-stream-datadog-id) --no-input exit-code: 0 stderr: contains: - "Open the following URL in a browser" - 010 - given a datadog log stream, it successfully deletes the log stream: + 014 - given a datadog log stream, it successfully deletes the log stream: command: auth0 logs streams delete $(cat ./test/integration/identifiers/log-stream-datadog-id) --force --no-input exit-code: 0 - 011 - it successfully creates an eventbridge log stream: + 015 - it successfully creates an eventbridge log stream: command: ./test/integration/scripts/create-log-stream-eventbridge-id.sh exit-code: 0 - 012 - given an eventbridge log stream, it successfully updates the log stream's details: + 016 - given an eventbridge log stream, it successfully updates the log stream's details: command: auth0 logs streams update eventbridge $(cat ./test/integration/identifiers/log-stream-eventbridge-id) --name integration-test-updated-eventbridge --json exit-code: 0 stdout: @@ -94,15 +118,15 @@ tests: type: "eventbridge" status: "active" - 013 - given an eventbridge log stream, it successfully deletes the log stream: + 017 - given an eventbridge log stream, it successfully deletes the log stream: command: auth0 logs streams delete $(cat ./test/integration/identifiers/log-stream-eventbridge-id) --force --no-input exit-code: 0 - 014 - it successfully creates an http log stream: + 018 - it successfully creates an http log stream: command: ./test/integration/scripts/create-log-stream-http-id.sh exit-code: 0 - 015 - given an http log stream, it successfully updates the log stream's details: + 019 - given an http log stream, it successfully updates the log stream's details: command: auth0 logs streams update http $(cat ./test/integration/identifiers/log-stream-http-id) --name integration-test-updated-http --endpoint "https://example.com/webhook/logs/v2" --format "JSONOBJECT" --type "application/xml" --authorization "KHEWXXXXXXXXXXXXXXXX" --json --no-input exit-code: 0 stdout: @@ -115,15 +139,15 @@ tests: sink.httpEndpoint: "https://example.com/webhook/logs/v2" sink.httpAuthorization: "KHEWXXXXXXXXXXXXXXXX" - 016 - given an http log stream, it successfully deletes the log stream: + 020 - given an http log stream, it successfully deletes the log stream: command: auth0 logs streams delete $(cat ./test/integration/identifiers/log-stream-http-id) --force --no-input exit-code: 0 - 017 - it successfully creates a splunk log stream: + 021 - it successfully creates a splunk log stream: command: ./test/integration/scripts/create-log-stream-splunk-id.sh exit-code: 0 - 018 - given a splunk log stream, it successfully updates the log stream's details: + 022 - given a splunk log stream, it successfully updates the log stream's details: command: auth0 logs streams update splunk $(cat ./test/integration/identifiers/log-stream-splunk-id) --name integration-test-updated-splunk --domain "example.splunk.com" --token "92a34ab5-c6d7-8901-23ef-456b7c89d0c1" --port 8000 --secure --json --no-input exit-code: 0 stdout: @@ -136,15 +160,15 @@ tests: sink.splunkPort: "8000" sink.splunkSecure: "true" - 019 - given a splunk log stream, it successfully deletes the log stream: + 023 - given a splunk log stream, it successfully deletes the log stream: command: auth0 logs streams delete $(cat ./test/integration/identifiers/log-stream-splunk-id) --force --no-input exit-code: 0 - 020 - it successfully creates a sumo log stream: + 024 - it successfully creates a sumo log stream: command: ./test/integration/scripts/create-log-stream-sumo-id.sh exit-code: 0 - 021 - given a sumo log stream, it successfully updates the log stream's details: + 025 - given a sumo log stream, it successfully updates the log stream's details: command: auth0 logs streams update sumo $(cat ./test/integration/identifiers/log-stream-sumo-id) --name integration-test-updated-sumo --source "example.sumo.com" --json --no-input exit-code: 0 stdout: @@ -154,6 +178,6 @@ tests: status: "active" sink.sumoSourceAddress: "example.sumo.com" - 022 - given a sumo log stream, it successfully deletes the log stream: + 026 - given a sumo log stream, it successfully deletes the log stream: command: auth0 logs streams delete $(cat ./test/integration/identifiers/log-stream-sumo-id) --force --no-input exit-code: 0