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))