73 lines
3.0 KiB
Python
73 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
CLI tool to check a log line against policy error patterns.
|
|
"""
|
|
import argparse
|
|
import re
|
|
import sys
|
|
import yaml
|
|
import os
|
|
from .stress_policy.utils import load_policy
|
|
|
|
def add_check_log_pattern_parser(subparsers):
|
|
"""Adds the parser for the 'check-log-pattern' command."""
|
|
parser = subparsers.add_parser(
|
|
'check-log-pattern',
|
|
help='Check a log line against policy error patterns.',
|
|
description='Checks a given log line against the fatal and tolerated error patterns defined in a policy file to determine how it would be classified.'
|
|
)
|
|
parser.add_argument('--policy', required=True, help='Path to the YAML policy file.')
|
|
parser.add_argument('--policy-name', help='Name of the policy to use from a multi-policy file.')
|
|
parser.add_argument(
|
|
'--policy-section',
|
|
default='direct_docker_cli_policy',
|
|
help="The top-level key in the policy where error patterns are defined (e.g., 'direct_docker_cli_policy'). Default: direct_docker_cli_policy"
|
|
)
|
|
parser.add_argument('log_line', help='The log line to check.')
|
|
|
|
def main_check_log_pattern(args):
|
|
"""Main logic for the 'check-log-pattern' command."""
|
|
policy = load_policy(args.policy, args.policy_name)
|
|
if not policy:
|
|
return 1
|
|
|
|
policy_section = policy.get(args.policy_section, {})
|
|
if not policy_section:
|
|
print(f"Error: Policy section '{args.policy_section}' not found in the policy.", file=sys.stderr)
|
|
return 1
|
|
|
|
fatal_patterns = policy_section.get('fatal_error_patterns', [])
|
|
tolerated_patterns = policy_section.get('tolerated_error_patterns', [])
|
|
|
|
print(f"--- Checking Log Line ---")
|
|
print(f"Policy: {args.policy}" + (f" (name: {args.policy_name})" if args.policy_name else ""))
|
|
print(f"Policy Section: {args.policy_section}")
|
|
print(f"Log Line: '{args.log_line}'")
|
|
print("-" * 25)
|
|
|
|
# 1. Check for fatal patterns. These take precedence.
|
|
for pattern in fatal_patterns:
|
|
if re.search(pattern, args.log_line, re.IGNORECASE):
|
|
print(f"Result: FATAL")
|
|
print(f"Reason: Matched fatal pattern: '{pattern}'")
|
|
return 0
|
|
|
|
# 2. Check for tolerated patterns. This is only relevant for lines that look like errors.
|
|
# The logic in stress_policy_tool checks for 'ERROR:' before checking tolerated patterns.
|
|
if 'ERROR:' in args.log_line:
|
|
for pattern in tolerated_patterns:
|
|
if re.search(pattern, args.log_line, re.IGNORECASE):
|
|
print(f"Result: TOLERATED")
|
|
print(f"Reason: Matched tolerated pattern: '{pattern}'")
|
|
return 0
|
|
|
|
# 3. If it's an ERROR line and not tolerated, it's a failure.
|
|
print(f"Result: FAILURE")
|
|
print(f"Reason: Contains 'ERROR:' but did not match any tolerated patterns.")
|
|
return 0
|
|
|
|
# 4. If it's not an error line and didn't match fatal, it's neutral.
|
|
print(f"Result: NEUTRAL")
|
|
print(f"Reason: Does not contain 'ERROR:' and did not match any fatal patterns.")
|
|
return 0
|