-
Notifications
You must be signed in to change notification settings - Fork 38
[gce_testing] Create findMatchingLogs to return all found logs and create QueryAllLogs.
#485
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: master
Are you sure you want to change the base?
Changes from all commits
0aa8ad9
0d8d6a9
a4efd07
986d47c
fa81069
e35609d
1cdfdb8
32b459e
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 |
|---|---|---|
|
|
@@ -604,11 +604,10 @@ func AssertMetricMissing(ctx context.Context, logger *log.Logger, vm *VM, metric | |
| return nil | ||
| } | ||
|
|
||
| // hasMatchingLog looks in the logging backend for a log matching the given query, | ||
| // findMatchingLogs looks in the logging backend for logs matching the given query, | ||
| // over the trailing time interval specified by the given window. | ||
| // Returns a boolean indicating whether the log was present in the backend, | ||
| // plus the first log entry found, or an error if the lookup failed. | ||
| func hasMatchingLog(ctx context.Context, logger *log.Logger, vm *VM, logNameRegex string, window time.Duration, query string) (bool, *cloudlogging.Entry, error) { | ||
| // Returns all the matching log entries found, or an error if the lookup failed. | ||
| func findMatchingLogs(ctx context.Context, logger *log.Logger, vm *VM, logNameRegex string, window time.Duration, query string) ([]*cloudlogging.Entry, error) { | ||
| start := time.Now().Add(-window) | ||
|
|
||
| t := start.Format(time.RFC3339) | ||
|
|
@@ -620,29 +619,25 @@ func hasMatchingLog(ctx context.Context, logger *log.Logger, vm *VM, logNameRege | |
|
|
||
| logClient, err := logClients.new(vm.Project) | ||
| if err != nil { | ||
| return false, nil, fmt.Errorf("hasMatchingLog() failed to obtain logClient for project %v: %v", vm.Project, err) | ||
| return nil, fmt.Errorf("findMatchingLogs() failed to obtain logClient for project %v: %v", vm.Project, err) | ||
| } | ||
| it := logClient.Entries(ctx, logadmin.Filter(filter)) | ||
| found := false | ||
|
|
||
| var first *cloudlogging.Entry | ||
| // Loop through the iterator printing out each matching log entry. We could return true on the | ||
| // first match, but it's nice for debugging to print out all matches into the logs. | ||
| var matchingLogs []*cloudlogging.Entry | ||
| // Loop through the iterator printing out each matching log entry. | ||
| // It is helpful for debugging to print out all matches into the logs. | ||
| for { | ||
| entry, err := it.Next() | ||
| if err == iterator.Done { | ||
| break | ||
| } | ||
| if err != nil { | ||
| return false, nil, err | ||
| return nil, err | ||
| } | ||
| logger.Printf("Found matching log entry: %v", entry) | ||
| found = true | ||
| if first == nil { | ||
| first = entry | ||
| } | ||
| matchingLogs = append(matchingLogs, entry) | ||
| } | ||
| return found, first, nil | ||
| return matchingLogs, nil | ||
| } | ||
|
|
||
| // WaitForLog looks in the logging backend for a log matching the given query, | ||
|
|
@@ -660,42 +655,59 @@ func shouldRetryHasMatchingLog(err error) bool { | |
| strings.Contains(err.Error(), "Internal error encountered") | ||
| } | ||
|
|
||
| // QueryLog looks in the logging backend for a log matching the given query, | ||
| // QueryLog looks in the logging backend a log matching the given query, | ||
| // over the trailing time interval specified by the given window. | ||
| // Returns the first log entry found, or an error if the log could not be | ||
| // found after some retries. | ||
| func QueryLog(ctx context.Context, logger *log.Logger, vm *VM, logNameRegex string, window time.Duration, query string, maxAttempts int) (*cloudlogging.Entry, error) { | ||
| matchingLogs, err := QueryAllLogs(ctx, logger, vm, logNameRegex, window, query, maxAttempts) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if len(matchingLogs) > 0 { | ||
| return matchingLogs[0], nil | ||
| } | ||
| return nil, fmt.Errorf("QueryLog() failed: %s not found, exhausted retries", logNameRegex) | ||
| } | ||
|
|
||
| // QueryAllLog looks in the logging backend for logs matching the given query, | ||
| // over the trailing time interval specified by the given window. | ||
| // Returns all the log entries found, or an error if no log could not be | ||
| // found after some retries. | ||
| func QueryAllLogs(ctx context.Context, logger *log.Logger, vm *VM, logNameRegex string, window time.Duration, query string, maxAttempts int) ([]*cloudlogging.Entry, error) { | ||
|
Member
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.
Contributor
Author
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. I don't see how to remove "retry until at least one log is found" from @jefferbrecht Could you add more details in the expected solution here ?
I think it could also be thought as "return query result if you find any data". It has the additional value of shorter tests.
Yes, Alternatives :
Contributor
Author
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. On further thought, i still think stopping the query at To expect |
||
| for attempt := 1; attempt <= maxAttempts; attempt++ { | ||
| found, first, err := hasMatchingLog(ctx, logger, vm, logNameRegex, window, query) | ||
| if found { | ||
| // Success. | ||
| return first, nil | ||
| matchingLogs, err := findMatchingLogs(ctx, logger, vm, logNameRegex, window, query) | ||
| if err == nil { | ||
| if len(matchingLogs) > 0 { | ||
| // Success. | ||
| return matchingLogs, nil | ||
| } | ||
| } | ||
| logger.Printf("Query returned found=%v, err=%v, attempt=%d", found, err, attempt) | ||
| logger.Printf("Query returned matchingLogs=%v, err=%v, attempt=%d", matchingLogs, err, attempt) | ||
| if err != nil && !shouldRetryHasMatchingLog(err) { | ||
| // A non-retryable error. | ||
| return nil, fmt.Errorf("QueryLog() failed: %v", err) | ||
| } | ||
| // found was false, or we hit a retryable error. | ||
| time.Sleep(logQueryBackoffDuration) | ||
| } | ||
| return nil, fmt.Errorf("QueryLog() failed: %s not found, exhausted retries", logNameRegex) | ||
| return nil, fmt.Errorf("QueryAllLogs() failed: %s not found, exhausted retries", logNameRegex) | ||
| } | ||
|
|
||
| // AssertLogMissing looks in the logging backend for a log matching the given query | ||
| // and returns success if no data is found. To consider possible transient errors | ||
| // while querying the backend we make queryMaxAttemptsLogMissing query attempts. | ||
| func AssertLogMissing(ctx context.Context, logger *log.Logger, vm *VM, logNameRegex string, window time.Duration, query string) error { | ||
| for attempt := 1; attempt <= queryMaxAttemptsLogMissing; attempt++ { | ||
| found, _, err := hasMatchingLog(ctx, logger, vm, logNameRegex, window, query) | ||
| matchingLogs, err := findMatchingLogs(ctx, logger, vm, logNameRegex, window, query) | ||
| if err == nil { | ||
| if found { | ||
| if len(matchingLogs) > 0 { | ||
| return fmt.Errorf("AssertLogMissing(log=%q): %v failed: unexpectedly found data for log", query, err) | ||
| } | ||
| // Success | ||
| return nil | ||
| } | ||
| logger.Printf("Query returned found=%v, err=%v, attempt=%d", found, err, attempt) | ||
| logger.Printf("Query returned matchingLogs=%v, err=%v, attempt=%d", matchingLogs, err, attempt) | ||
| if err != nil && !shouldRetryHasMatchingLog(err) { | ||
| // A non-retryable error. | ||
| return fmt.Errorf("AssertLogMissing() failed: %v", err) | ||
|
|
||
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.
We should be able to implement
QueryLogby just callingQueryAllLogsinternally and returning the first element of the slice.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.
Done!