Skip to content

Commit 6ba2558

Browse files
Add grep functionality to workflow error script
This commit introduces a grep-like feature to the `print_workflow_run_errors.py` script. New features: - Added `--grep-pattern` (`-g`) argument to specify an Extended Regular Expression (ERE) for searching within fetched logs. - Added `--grep-context` (`-C`) argument to specify the number of lines of context to show around matches (default is 5). Behavior: - If a grep pattern is provided, the script will use the system `grep` command to filter the logs of failed steps (or the full job log if a specific step's log cannot be isolated). - Output clearly indicates when grep results are shown, the pattern used, and the context lines. - Handles cases where `grep` finds no matches or if the `grep` command itself fails (e.g., not found, bad pattern). - If no grep pattern is provided, the script defaults to its previous behavior of printing the last N lines of the log.
1 parent bcdf292 commit 6ba2558

File tree

1 file changed

+53
-7
lines changed

1 file changed

+53
-7
lines changed

scripts/print_workflow_run_errors.py

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,18 @@ def parse_repo_url_arg(url_string):
156156
default=False,
157157
help="If set, print logs for all failed steps in a job. Default is to print logs only for the first failed step."
158158
)
159+
parser.add_argument(
160+
"--grep-pattern", "-g",
161+
type=str,
162+
default=None,
163+
help="Extended Regular Expression (ERE) to search for in logs. If provided, log output will be filtered by grep."
164+
)
165+
parser.add_argument(
166+
"--grep-context", "-C",
167+
type=int,
168+
default=5,
169+
help="Number of lines of leading and trailing context to print for grep matches. Default: 5."
170+
)
159171

160172
args = parser.parse_args()
161173
error_suffix = " (use --help for more details)"
@@ -320,15 +332,49 @@ def parse_repo_url_arg(url_string):
320332
# Found the end of the targeted step's log
321333
break # Stop processing lines for this step (within this job's logs)
322334

335+
log_to_process = ""
336+
log_source_message = ""
337+
323338
if current_step_log_segment:
324-
print(f"Log for failed step '{step_name}' (last {args.log_lines} lines of its segment):")
325-
for log_line in current_step_log_segment[-args.log_lines:]:
326-
print(log_line)
339+
log_to_process = "\n".join(current_step_log_segment)
340+
log_source_message = f"Log for failed step '{step_name}'"
327341
else:
328-
# Fallback if specific step log segment couldn't be reliably identified
329-
print(f"Could not isolate log for step '{step_name}'. Printing last {args.log_lines} lines of the entire job log as context:")
330-
for log_line in log_lines_for_job[-args.log_lines:]: # Use the job's split lines
331-
print(log_line)
342+
log_to_process = "\n".join(log_lines_for_job) # Use the full job log as fallback
343+
log_source_message = f"Could not isolate log for step '{step_name}'. Using entire job log"
344+
345+
if args.grep_pattern:
346+
print(f"{log_source_message} (grep results for pattern '{args.grep_pattern}' with context {args.grep_context}):")
347+
try:
348+
# Using subprocess to call grep
349+
# Pass log_to_process as stdin to grep
350+
process = subprocess.run(
351+
['grep', '-E', f"-C{args.grep_context}", args.grep_pattern],
352+
input=log_to_process,
353+
text=True,
354+
capture_output=True,
355+
check=False # Do not throw exception on non-zero exit (e.g. no match)
356+
)
357+
if process.returncode == 0: # Match found
358+
print(process.stdout.strip())
359+
elif process.returncode == 1: # No match found
360+
print(f"No matches found for pattern '{args.grep_pattern}' in this log segment.")
361+
else: # Grep error
362+
sys.stderr.write(f"Grep command failed with error code {process.returncode}:\n{process.stderr}\n")
363+
except FileNotFoundError:
364+
sys.stderr.write("Error: 'grep' command not found. Please ensure it is installed and in your PATH to use --grep-pattern.\n")
365+
# Fallback to printing last N lines if grep is not found? Or just skip log? For now, skip.
366+
print("Skipping log display for this step as grep is unavailable.")
367+
except Exception as e:
368+
sys.stderr.write(f"An unexpected error occurred while running grep: {e}\n")
369+
print("Skipping log display due to an error with grep.")
370+
else:
371+
# Default behavior: print last N lines
372+
print(f"{log_source_message} (last {args.log_lines} lines):")
373+
# current_step_log_segment is a list of lines, log_lines_for_job is also a list of lines
374+
lines_to_print_from = current_step_log_segment if current_step_log_segment else log_lines_for_job
375+
for log_line in lines_to_print_from[-args.log_lines:]:
376+
print(log_line)
377+
332378
print(f"--- End of log for step: {step_name} ---")
333379
first_failed_step_logged = True # Mark that we've logged at least one step
334380

0 commit comments

Comments
 (0)