github.com/noironetworks/cilium-net@v1.6.12/contrib/scripts/consolidate_go_stacktrace.py (about)

     1  #!/usr/bin/env python
     2  
     3  # consolidate_go_stacktrace.py collapses a go stacktrace by uniqueing each
     4  # stack. Addresses, goroutine ID and goroutine ages are ignored when determining
     5  # uniqeness. A sample of each unique trace is printed
     6  
     7  import re,sys,collections
     8  
     9  def get_stacks(f):
    10      """
    11      get_stacks parses file f and yields all lines in go stackrace as one array
    12      """
    13      accum = []
    14      for line in f:
    15          line = line.rstrip()
    16          if line.startswith("goroutine"):
    17              yield accum
    18              accum = []
    19          else:
    20              accum.append(line)
    21  
    22  # Regexes used to find and remove addresses, ids and age
    23  strip_addresses = re.compile(r"0x[0-9a-fA-F]+")
    24  strip_goroutine_id = re.compile(r"goroutine [0-9]+")
    25  strip_goroutine_time = re.compile(r", [0-9]+ minutes")
    26  def strip_stack(stack):
    27      """
    28      strip_stack replaces addresses, goroutine IDs and ages with a fixed sentinel
    29      """
    30      stack = [strip_addresses.sub("0x?", l) for l in stack]
    31      stack = [strip_goroutine_id.sub("?", l) for l in stack]
    32      stack = [strip_goroutine_time.sub("", l) for l in stack]
    33      return stack
    34  
    35  def get_hashable_stack_value(stack):
    36      """
    37      get_hashable_stack_value transforms stack (and array of strings) into
    38      something that can be used as a map key
    39      """
    40      return "".join(strip_stack(stack))
    41  
    42  def print_usage():
    43      print """usage: {} [-h | path/to/file]
    44          -h:         This help.
    45          path/to/file:   Read and parse file with go stacktraces
    46          "-" or no params: Read and parse stdin""".format(sys.argv[0])
    47  
    48  if __name__ == "__main__":
    49      # Handle arguments. We only support a file path, or stdin on "-" or no
    50      # parameter
    51      infile = sys.argv[1] if len(sys.argv) > 1 else ""
    52      if infile in ["-h", "help"]:
    53          print_usage()
    54          sys.exit(0)
    55      elif infile in ["-", "", None]:
    56          f = sys.stdin
    57      else:
    58          f = open(infile)
    59  
    60      # collect stacktraces into groups, each keyed by a version of the stack
    61      # where unwanted fields have been made into sentinels
    62      consolidated = collections.defaultdict(list)
    63      for stack in get_stacks(f):
    64          h = get_hashable_stack_value(stack)
    65          consolidated[h].append(stack)
    66  
    67      # print count of each unique stack, and a sample, sorted by frequency
    68      print "{} unique stack traces".format(len(consolidated))
    69      for stack in sorted(consolidated.values(), cmp=lambda a,b: len(a)-len(b), reverse=True):
    70          print "{} occurences. Sample stack trace:".format(len(stack))
    71          print "\n".join(stack[0])
    72  
    73      if f != sys.stdin:
    74          f.close()