github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/gubernator/view_logs.py (about)

     1  # Copyright 2016 The Kubernetes Authors.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #     http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  import os
    16  import re
    17  
    18  import gcs_async
    19  import log_parser
    20  import kubelet_parser
    21  import regex
    22  import view_base
    23  
    24  
    25  @view_base.memcache_memoize('log-file-junit://', expires=60*60*4)
    26  def find_log_junit(build_dir, junit, log_file):
    27      '''
    28      Looks in build_dir for log_file in a folder that
    29      also includes the junit file.
    30      '''
    31      tmps = [f.filename for f in view_base.gcs_ls('%s/artifacts' % build_dir)
    32              if '/tmp-node' in f.filename]
    33      for folder in tmps:
    34          filenames = [f.filename for f in view_base.gcs_ls(folder)]
    35          if folder + junit in filenames:
    36              path = folder + log_file
    37              if path in filenames:
    38                  return path
    39  
    40  
    41  def find_log_files(all_logs, log_file):
    42      '''
    43      Returns list of files named log_file from values in all_logs
    44      '''
    45      log_files = []
    46      for folder in all_logs.itervalues():
    47          for log in folder:
    48              if log_file in log:
    49                  log_files.append(log)
    50  
    51      return log_files
    52  
    53  
    54  @view_base.memcache_memoize('all-logs://', expires=60*60*4)
    55  def get_all_logs(directory, artifacts):
    56      '''
    57      returns dictionary given the artifacts folder with the keys being the
    58      folders, and the values being the log files within the corresponding folder
    59      '''
    60      log_files = {}
    61      if artifacts:
    62          dirs = [f.filename for f in view_base.gcs_ls('%s/artifacts' % directory)
    63                  if f.is_dir]
    64      else:
    65          dirs = [directory]
    66      for d in dirs:
    67          log_files[d] = []
    68          for f in view_base.gcs_ls(d):
    69              log_name = regex.log_re.search(f.filename)
    70              if log_name:
    71                  log_files[d].append(f.filename)
    72      return log_files
    73  
    74  
    75  def parse_log_file(log_filename, pod, filters=None, make_dict=False, objref_dict=None):
    76      """Based on make_dict, either returns the objref_dict or the parsed log file"""
    77      log = gcs_async.read(log_filename).get_result()
    78      if log is None:
    79          return {}, False if make_dict else None
    80      if pod:
    81          bold_re = regex.wordRE(pod)
    82      else:
    83          bold_re = regex.error_re
    84      if objref_dict is None:
    85          objref_dict = {}
    86      if make_dict and pod:
    87          return kubelet_parser.make_dict(log.decode('utf8', 'replace'), bold_re, objref_dict)
    88      else:
    89          return log_parser.digest(log.decode('utf8', 'replace'),
    90              error_re=bold_re, filters=filters, objref_dict=objref_dict)
    91  
    92  
    93  def get_logs_junit((log_files, pod_name, filters, objref_dict, apiserver_filename)):
    94      # Get the logs in the case where the junit file with the failure is in a specific folder
    95      all_logs = {}
    96      results = {}
    97      # default to filtering kube-apiserver log if user unchecks both checkboxes
    98      if log_files == []:
    99          log_files = [apiserver_filename]
   100  
   101      artifact_filename = os.path.dirname(apiserver_filename)
   102      all_logs = get_all_logs(artifact_filename, False)
   103      parsed_dict, _ = parse_log_file(os.path.join(artifact_filename, "kubelet.log"),
   104          pod_name, make_dict=True, objref_dict=objref_dict)
   105      objref_dict.update(parsed_dict)
   106      if log_files:
   107          for log_file in log_files:
   108              parsed_file = parse_log_file(log_file, pod_name, filters, objref_dict=objref_dict)
   109              if parsed_file:
   110                  results[log_file] = parsed_file
   111  
   112      return all_logs, results, objref_dict, log_files
   113  
   114  
   115  def get_logs_no_pod(apiserver_filename, kubelet_filenames, filters, objref_dict, all_logs):
   116      # Get results of parsing logs when no pod name is given
   117      results = {}
   118      if apiserver_filename:
   119          for apiserver_log in apiserver_filename:
   120              parsed_file = parse_log_file(apiserver_log, "", filters,
   121              objref_dict=objref_dict)
   122              if parsed_file:
   123                  results[apiserver_log] = parsed_file
   124          return all_logs, results, objref_dict, apiserver_filename
   125      else:
   126          for kubelet_log in kubelet_filenames:
   127              parsed_file = parse_log_file(kubelet_log, "", filters,
   128              objref_dict=objref_dict)
   129              if parsed_file:
   130                  results[kubelet_log] = parsed_file
   131          return all_logs, results, objref_dict, kubelet_filenames
   132  
   133  
   134  def get_logs(build_dir, log_files, pod_name, filters, objref_dict):
   135      """
   136      Get the logs in the case where all logs in artifacts folder may be relevant
   137      Returns:
   138          all_logs: dictionary of all logs that can be filtered
   139          results: dictionary of log file to the parsed text
   140          obref_dict: dictionary of name of filter to the string to be filtered
   141          log_files: list of files that are being displayed/filtered
   142      """
   143      all_logs = {}
   144      results = {}
   145      old_dict_len = len(objref_dict)
   146  
   147      all_logs = get_all_logs(build_dir, True)
   148      apiserver_filename = find_log_files(all_logs, "kube-apiserver.log")
   149      kubelet_filenames = find_log_files(all_logs, "kubelet.log")
   150      if not pod_name and not objref_dict:
   151          return get_logs_no_pod(apiserver_filename, kubelet_filenames, filters,
   152              objref_dict, all_logs)
   153      for kubelet_log in kubelet_filenames:
   154          if pod_name:
   155              parsed_dict, pod_in_file = parse_log_file(kubelet_log, pod_name, make_dict=True,
   156                  objref_dict=objref_dict)
   157              objref_dict.update(parsed_dict)
   158          if len(objref_dict) > old_dict_len or not pod_name or pod_in_file or not objref_dict:
   159              if log_files == []:
   160                  log_files = [kubelet_log]
   161                  if apiserver_filename:
   162                      log_files.extend(apiserver_filename)
   163              for log_file in log_files:
   164                  parsed_file = parse_log_file(log_file, pod_name, filters,
   165                      objref_dict=objref_dict)
   166                  if parsed_file:
   167                      results[log_file] = parsed_file
   168              break
   169  
   170      return all_logs, results, objref_dict, log_files
   171  
   172  
   173  def get_woven_logs(log_files, pod, filters, objref_dict):
   174      lines = []
   175      combined_lines = []
   176      first_combined = ""
   177      pod_re = regex.wordRE(pod)
   178  
   179      # Produce a list of lines of all the selected logs
   180      for log_file in log_files:
   181          log = gcs_async.read(log_file).get_result()
   182          log = log.decode('utf8', 'replace')
   183          lines.extend(log.split('\n'))
   184      # Combine lines without timestamp into previous line, except if it comes at the
   185      # beginning of the file, in which case add it to the line with the first timestamp
   186      for line in lines:
   187          timestamp_re = regex.timestamp(line)
   188          if timestamp_re and timestamp_re.group(0):
   189              if not combined_lines:
   190                  # add beginning of file to first timestamp line
   191                  line = first_combined + line
   192              combined_lines.append(line)
   193          else:
   194              if not combined_lines:
   195                  first_combined = first_combined + line
   196              else:
   197                  combined_lines[-1] = combined_lines[-1] + line
   198      lines = sorted(combined_lines, key=regex.sub_timestamp)
   199      data = '\n'.join(lines)
   200      woven_logs = log_parser.digest(data, error_re=pod_re,
   201          filters=filters, objref_dict=objref_dict)
   202      return woven_logs
   203  
   204  
   205  def parse_by_timestamp((build_dir, junit, log_files, pod, filters, objref_dict)):
   206      """
   207      Returns:
   208          woven_logs: HTML code of chosen logs woven together by timestamp
   209          all_logs: Dictionary of logs relevant for filtering
   210      """
   211      woven_logs = get_woven_logs(log_files, pod, filters, objref_dict)
   212  
   213      apiserver_filename = find_log_junit(build_dir, junit, "kube-apiserver.log")
   214      if apiserver_filename:
   215          artifact_filename = re.sub("/kube-apiserver.log", "", apiserver_filename)
   216          all_logs = get_all_logs(artifact_filename, False)
   217      if not apiserver_filename:
   218          all_logs = get_all_logs(build_dir, True)
   219      return woven_logs, all_logs
   220  
   221  
   222  class NodeLogHandler(view_base.BaseHandler):
   223      def get(self, prefix, job, build):
   224          """
   225          Examples of variables
   226          log_files: ["kubelet.log", "kube-apiserver.log"]
   227          pod_name: "pod-abcdef123"
   228          junit: "junit_01.xml"
   229          uid, namespace, wrap: "on"
   230          cID, poduid, ns: strings entered into textboxes
   231          results, logs: {"kubelet.log":"parsed kubelet log for html"}
   232          all_logs: {"folder_name":["a.log", "b.log"]}
   233          """
   234          # pylint: disable=too-many-locals
   235          job_dir = '/%s/%s/' % (prefix, job)
   236          build_dir = job_dir + build
   237          log_files = self.request.get_all("logfiles")
   238          others = self.request.get_all("others")
   239          pod_name = self.request.get("pod")
   240          junit = self.request.get("junit")
   241          cID = self.request.get("cID")
   242          poduid = self.request.get("poduid")
   243          ns = self.request.get("ns")
   244          uid = bool(self.request.get("UID"))
   245          namespace = bool(self.request.get("Namespace"))
   246          containerID = bool(self.request.get("ContainerID"))
   247          wrap = bool(self.request.get("wrap"))
   248          weave = bool(self.request.get("weave"))
   249          filters = {"UID":uid, "pod":pod_name, "Namespace":namespace, "ContainerID":containerID}
   250  
   251          objref_dict = {}
   252          results = {}
   253  
   254          woven_logs = ""
   255  
   256          for idx, filter_term in enumerate(others):
   257              filters["other%d" % idx] = filter_term
   258              objref_dict["other%d" % idx] = filter_term
   259          if cID:
   260              objref_dict["ContainerID"] = cID
   261          if poduid:
   262              objref_dict["UID"] = poduid
   263          if ns:
   264              objref_dict["Namespace"] = ns
   265  
   266          apiserver_filename = find_log_junit(build_dir, junit, "kube-apiserver.log")
   267  
   268          if not weave or len(log_files) == 1:
   269              weave = False
   270              if apiserver_filename and pod_name:
   271                  all_logs, results, objref_dict, log_files = get_logs_junit((log_files,
   272                      pod_name, filters, objref_dict, apiserver_filename))
   273              if not apiserver_filename:
   274                  all_logs, results, objref_dict, log_files = get_logs(build_dir, log_files,
   275                      pod_name, filters, objref_dict)
   276          else:
   277              woven_logs, all_logs = parse_by_timestamp((build_dir, junit, log_files, pod_name,
   278                  filters, objref_dict))
   279  
   280          if (not weave and results == {}) or (weave and woven_logs == ""):
   281              self.render('node_404.html', {"build_dir": build_dir, "log_files": log_files,
   282                  "pod_name":pod_name, "junit":junit})
   283              self.response.set_status(404)
   284              return
   285  
   286          self.render('filtered_log.html', dict(
   287              job_dir=job_dir, build_dir=build_dir, logs=results, job=job,
   288              build=build, log_files=log_files, containerID=containerID, others=others,
   289              pod=pod_name, junit=junit, uid=uid, namespace=namespace, weave=weave,
   290              wrap=wrap, objref_dict=objref_dict, all_logs=all_logs, woven_logs=woven_logs))