From 3d5ec2a8ea02e6b895b0d581fb41db37024b5280 Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Fri, 26 Sep 2025 11:18:17 +0200 Subject: [PATCH 1/3] Add auditlog example - how to paginate the data of auditlog - how to detect reached rate limit --- examples/auditlog/auditlog.go | 70 +++++++++++++++++++++++++++++++++++ examples/auditlog/go.mod | 13 +++++++ go.work | 1 + 3 files changed, 84 insertions(+) create mode 100644 examples/auditlog/auditlog.go create mode 100644 examples/auditlog/go.mod diff --git a/examples/auditlog/auditlog.go b/examples/auditlog/auditlog.go new file mode 100644 index 000000000..b24a5ec18 --- /dev/null +++ b/examples/auditlog/auditlog.go @@ -0,0 +1,70 @@ +package main + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "time" + + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" + "github.com/stackitcloud/stackit-sdk-go/services/auditlog" +) + +func main() { + // Specify the project ID, startTime and endTIme + projectId := "PROJECT_ID" + startTime := time.Now().Add(-time.Hour * 24) + endTime := time.Now() + limit := float32(100) // set pagination limit to avoid rate limit + + // Create a new API client, that uses default authentication and configuration + auditlogClient, err := auditlog.NewAPIClient() + if err != nil { + fmt.Fprintf(os.Stderr, "[Auditlog API] Creating API client: %v\n", err) + os.Exit(1) + } + + // List all audit logs of a project + listProjectLogsReq := auditlogClient.ListProjectAuditLogEntries(context.Background(), projectId). + StartTimeRange(startTime). + EndTimeRange(endTime). + Limit(limit) + result, err := listProjectLogsReq.Execute() + + var allItems []auditlog.AuditLogEntryResponse + for { + if err != nil { + var oapiErr *oapierror.GenericOpenAPIError + if errors.As(err, &oapiErr) { + // reached rate limit + if oapiErr.StatusCode == http.StatusTooManyRequests { + fmt.Fprintf(os.Stderr, "[Auditlog API] Too Many Requests: %v\n", string(oapiErr.Body)) + break + } + } + fmt.Fprintf(os.Stderr, "[Auditlog API] List project audit log entries: %v\n", err) + os.Exit(1) + } + // Break loop when response has no items + if result == nil || result.Items == nil || len(*result.Items) == 0 { + break + } + + // Append items to allItems + allItems = append(allItems, *result.Items...) + + // If cursor is not set, end of logs is reached + if result.Cursor == nil { + fmt.Printf("[Auditlog API] Successfully all items.\n") + break + } + + // Paginate to the next set of items + listProjectLogsReq = listProjectLogsReq.Cursor(*result.Cursor) + result, err = listProjectLogsReq.Execute() + } + + fmt.Printf("[Auditlog API] Number of project audit log entries: %v\n", len(allItems)) +} diff --git a/examples/auditlog/go.mod b/examples/auditlog/go.mod new file mode 100644 index 000000000..8a6a12ccf --- /dev/null +++ b/examples/auditlog/go.mod @@ -0,0 +1,13 @@ +module auditlog + +go 1.21 + +require ( + github.com/stackitcloud/stackit-sdk-go/core v0.17.3 + github.com/stackitcloud/stackit-sdk-go/services/auditlog v0.1.0 +) + +require ( + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect +) diff --git a/go.work b/go.work index 91befe6ea..478149caf 100644 --- a/go.work +++ b/go.work @@ -2,6 +2,7 @@ go 1.21 use ( ./core + ./examples/auditlog ./examples/authentication ./examples/authorization ./examples/backgroundrefresh From 6da4058af6dcee2bf406dcc19d4dcc25bfd82e0c Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Fri, 26 Sep 2025 11:47:24 +0200 Subject: [PATCH 2/3] add go.sum for auditlog example --- examples/auditlog/go.sum | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/auditlog/go.sum diff --git a/examples/auditlog/go.sum b/examples/auditlog/go.sum new file mode 100644 index 000000000..fd1a5fdcc --- /dev/null +++ b/examples/auditlog/go.sum @@ -0,0 +1,10 @@ +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/stackitcloud/stackit-sdk-go/core v0.17.3 h1:GsZGmRRc/3GJLmCUnsZswirr5wfLRrwavbnL/renOqg= +github.com/stackitcloud/stackit-sdk-go/core v0.17.3/go.mod h1:HBCXJGPgdRulplDzhrmwC+Dak9B/x0nzNtmOpu+1Ahg= +github.com/stackitcloud/stackit-sdk-go/services/auditlog v0.1.0 h1:Y8qhIcp5gWlA0Tj58lSrS48lEB3gH2x56XCpCyHSVfc= +github.com/stackitcloud/stackit-sdk-go/services/auditlog v0.1.0/go.mod h1:vwP9edf2elr3SLz3lH7y5vqhgKIdtfS/xN7wsPTxcwM= From 9ab6b32eb614317a61858a160419c08150d90d0b Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Mon, 6 Oct 2025 10:40:17 +0200 Subject: [PATCH 3/3] review feedback --- examples/auditlog/auditlog.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/auditlog/auditlog.go b/examples/auditlog/auditlog.go index b24a5ec18..11246b33b 100644 --- a/examples/auditlog/auditlog.go +++ b/examples/auditlog/auditlog.go @@ -13,7 +13,7 @@ import ( ) func main() { - // Specify the project ID, startTime and endTIme + // Specify the project ID, startTime and endTime projectId := "PROJECT_ID" startTime := time.Now().Add(-time.Hour * 24) endTime := time.Now() @@ -33,13 +33,20 @@ func main() { Limit(limit) result, err := listProjectLogsReq.Execute() + // To fetch all audit log items within a specified time range, we must implement pagination, because the api returns only + // up to 100 elements per request. We store the result of each request in `allItems`. The response includes a cursor, + // if more elements are available. This cursor must be used to get the next set of elements. + // The api has a rate limit, which can be reached when all elements will be fetched with pagination or if you do multiple request. + // The rate limit should be taken care in this case. var allItems []auditlog.AuditLogEntryResponse for { if err != nil { var oapiErr *oapierror.GenericOpenAPIError if errors.As(err, &oapiErr) { - // reached rate limit + // Check if rate limit is reached if oapiErr.StatusCode == http.StatusTooManyRequests { + // In case you want to fetch all items, you may want to wait some time and retry the request. + // In this example we just stop here the pagination. fmt.Fprintf(os.Stderr, "[Auditlog API] Too Many Requests: %v\n", string(oapiErr.Body)) break } @@ -57,7 +64,7 @@ func main() { // If cursor is not set, end of logs is reached if result.Cursor == nil { - fmt.Printf("[Auditlog API] Successfully all items.\n") + fmt.Printf("[Auditlog API] Successfully fetched all items.\n") break }