-
Notifications
You must be signed in to change notification settings - Fork 46
Migrate to Structured Logging with zerolog and Improve Logging for Manifest Purge Logic #473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
8910185
f1a3997
009bb50
6fcf423
12c3f19
42e878c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,5 @@ | |
coverage.txt | ||
*.test | ||
*.out | ||
*.html | ||
*.html | ||
acr-bin |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import ( | |
|
||
"github.com/Azure/acr-cli/cmd/common" | ||
"github.com/Azure/acr-cli/internal/api" | ||
"github.com/Azure/acr-cli/internal/logger" | ||
"github.com/Azure/acr-cli/internal/worker" | ||
"github.com/dlclark/regexp2" | ||
"github.com/spf13/cobra" | ||
|
@@ -163,8 +164,17 @@ func annotateTags(ctx context.Context, | |
dryRun bool) (int, error) { | ||
|
||
if !dryRun { | ||
log := logger.Get() | ||
log.Info(). | ||
Str("repository", repoName). | ||
Msg("Starting tag annotation for repository") | ||
fmt.Printf("\nAnnotating tags for repository: %s\n", repoName) | ||
} else { | ||
log := logger.Get() | ||
log.Info(). | ||
Str("repository", repoName). | ||
Bool("dry_run", true). | ||
Msg("Dry run: would annotate tags for repository") | ||
fmt.Printf("\nTags for this repository would be annotated: %s\n", repoName) | ||
} | ||
|
||
|
@@ -225,6 +235,11 @@ func getManifestsToAnnotate(ctx context.Context, | |
resultTags, err := acrClient.GetAcrTags(ctx, repoName, "timedesc", lastTag) | ||
if err != nil { | ||
if resultTags != nil && resultTags.Response.Response != nil && resultTags.StatusCode == http.StatusNotFound { | ||
log := logger.Get() | ||
log.Warn(). | ||
Str("repository", repoName). | ||
Int("status_code", resultTags.StatusCode). | ||
Msg("Repository not found during annotation operation") | ||
fmt.Printf("%s repository not found\n", repoName) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all fmt.Printf messages should be removed as they are being replaced by the new structured logger There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed fmt.Printf statements from annotate.go as requested. Replaced with structured logging where appropriate. Changes in commit 42e878c. |
||
return nil, "", nil | ||
} | ||
|
@@ -257,6 +272,12 @@ func getManifestsToAnnotate(ctx context.Context, | |
// Only print what would be annotated during a dry-run. Successfully annotated manifests | ||
// will be logged after the annotation. | ||
if dryRun { | ||
log := logger.Get() | ||
log.Debug(). | ||
Str("repository", repoName). | ||
Str("tag", *tag.Name). | ||
Str("manifest", *tag.Digest). | ||
Msg("Tag marked for annotation in dry run") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use Bool("dry_run", true) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed to use Bool("dry_run", true) instead of string format. Changes in commit 42e878c. |
||
fmt.Printf("%s/%s:%s\n", loginURL, repoName, *tag.Name) | ||
} | ||
manifestsToAnnotate = append(manifestsToAnnotate, *tag.Digest) | ||
|
@@ -280,8 +301,17 @@ func annotateUntaggedManifests(ctx context.Context, | |
annotations []string, | ||
dryRun bool) (int, error) { | ||
if !dryRun { | ||
log := logger.Get() | ||
log.Info(). | ||
Str("repository", repoName). | ||
Msg("Starting manifest annotation for repository") | ||
fmt.Printf("Annotating manifests for repository: %s\n", repoName) | ||
} else { | ||
log := logger.Get() | ||
log.Info(). | ||
Str("repository", repoName). | ||
Bool("dry_run", true). | ||
Msg("Dry run: would annotate manifests for repository") | ||
fmt.Printf("Manifests for this repository would be annotated: %s\n", repoName) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
"fmt" | ||
|
||
"github.com/Azure/acr-cli/internal/api" | ||
"github.com/Azure/acr-cli/internal/logger" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
) | ||
|
@@ -83,29 +84,56 @@ func newManifestListCmd(manifestParams *manifestParameters) *cobra.Command { | |
|
||
// listManifests will do the http requests and print the digest of all the manifest in the selected repository. | ||
func listManifests(ctx context.Context, acrClient api.AcrCLIClientInterface, loginURL string, repoName string) error { | ||
log := logger.Get() | ||
|
||
log.Debug(). | ||
Str("repository", repoName). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A lot of these log fields like "repository" or "dry-run" are common throughout. Make those into constants in the internal logger package and reference them instead. Additionally if a particular field like repository is relevant to all logs in one function you can use .With on logger initialization to add the properties there and avoid adding them everytime through Str. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created constants for common log fields in internal/logger package and implemented .With() pattern for repository context to avoid repetition. Changes in commit 42e878c. |
||
Msg("Starting manifest listing") | ||
|
||
lastManifestDigest := "" | ||
resultManifests, err := acrClient.GetAcrManifests(ctx, repoName, "", lastManifestDigest) | ||
if err != nil { | ||
log.Error(). | ||
Err(err). | ||
Str("repository", repoName). | ||
Msg("Failed to get manifests for listing") | ||
return errors.Wrap(err, "failed to list manifests") | ||
} | ||
|
||
fmt.Printf("Listing manifests for the %q repository:\n", repoName) | ||
|
||
totalManifests := 0 | ||
// A for loop is used because the GetAcrManifests method returns by default only 100 manifests and their attributes. | ||
for resultManifests != nil && resultManifests.ManifestsAttributes != nil { | ||
manifests := *resultManifests.ManifestsAttributes | ||
for _, manifest := range manifests { | ||
manifestDigest := *manifest.Digest | ||
fmt.Printf("%s/%s@%s\n", loginURL, repoName, manifestDigest) | ||
|
||
log.Debug(). | ||
Str("repository", repoName). | ||
Str("manifest", manifestDigest). | ||
Msg("Listed manifest") | ||
totalManifests++ | ||
} | ||
// Since the GetAcrManifests supports pagination when supplied with the last digest that was returned the last manifest | ||
// digest is saved, the manifest array contains at least one element because if it was empty the API would return | ||
// a nil pointer instead of a pointer to a length 0 array. | ||
lastManifestDigest = *manifests[len(manifests)-1].Digest | ||
resultManifests, err = acrClient.GetAcrManifests(ctx, repoName, "", lastManifestDigest) | ||
if err != nil { | ||
log.Error(). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Errors are propagated through the errors.Wrap. There is no no need to log the error at every level. Additionally, where seen errors.wrap should be replaced with fmt.Errorf(%w). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replaced errors.Wrap with fmt.Errorf(%w) and removed redundant error logging at every level. Changes in commit 42e878c. |
||
Err(err). | ||
Str("repository", repoName). | ||
Msg("Failed to get next page of manifests") | ||
return errors.Wrap(err, "failed to list manifests") | ||
} | ||
} | ||
|
||
log.Info(). | ||
Str("repository", repoName). | ||
Int("total_manifests", totalManifests). | ||
Msg("Completed manifest listing") | ||
return nil | ||
} | ||
|
||
|
@@ -140,13 +168,41 @@ func newManifestDeleteCmd(manifestParams *manifestParameters) *cobra.Command { | |
|
||
// deleteManifests receives an array of manifests digest and deletes them using the supplied acrClient. | ||
func deleteManifests(ctx context.Context, acrClient api.AcrCLIClientInterface, loginURL string, repoName string, args []string) error { | ||
log := logger.Get() | ||
|
||
log.Info(). | ||
Str("repository", repoName). | ||
Int("manifest_count", len(args)). | ||
Msg("Starting manifest deletion") | ||
|
||
for i := 0; i < len(args); i++ { | ||
_, err := acrClient.DeleteManifest(ctx, repoName, args[i]) | ||
if err != nil { | ||
log.Error(). | ||
Err(err). | ||
Str("repository", repoName). | ||
Str("manifest", args[i]). | ||
Int("position", i+1). | ||
Int("total", len(args)). | ||
Msg("Failed to delete manifest") | ||
// If there is an error (this includes not found and not allowed operations) the deletion of the images is stopped and an error is returned. | ||
return errors.Wrap(err, "failed to delete manifests") | ||
} | ||
|
||
fmt.Printf("%s/%s@%s\n", loginURL, repoName, args[i]) | ||
|
||
log.Info(). | ||
Str("repository", repoName). | ||
Str("manifest", args[i]). | ||
Str("ref", fmt.Sprintf("%s/%s@%s", loginURL, repoName, args[i])). | ||
Int("position", i+1). | ||
Int("total", len(args)). | ||
Msg("Successfully deleted manifest") | ||
} | ||
|
||
log.Info(). | ||
Str("repository", repoName). | ||
Int("deleted_count", len(args)). | ||
Msg("Completed manifest deletion") | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this constant logger.Get() . The logger should be acquired once at the top of the function and then used as required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed logger.Get() usage pattern - now acquiring logger once at function top instead of repeated calls. Changes in commit 42e878c.