Merge pull request #653 from darko-poljak/improve_error_reporting

Improve error reporting
This commit is contained in:
Darko Poljak 2018-04-19 17:53:30 +02:00 committed by GitHub
commit 0d15e1aae0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 29 deletions

View file

@ -83,41 +83,72 @@ class CdistBetaRequired(cdist.Error):
class CdistEntityError(Error): class CdistEntityError(Error):
"""Something went wrong while executing cdist entity""" """Something went wrong while executing cdist entity"""
def __init__(self, entity_name, entity_params, stderr_paths, subject=''): def __init__(self, entity_name, entity_params, stdout_paths,
stderr_paths, subject=''):
self.entity_name = entity_name self.entity_name = entity_name
self.entity_params = entity_params self.entity_params = entity_params
self.stderr_paths = stderr_paths self.stderr_paths = stderr_paths
self.stdout_paths = stdout_paths
if isinstance(subject, Error): if isinstance(subject, Error):
self.original_error = subject self.original_error = subject
else: else:
self.original_error = None self.original_error = None
self.message = str(subject) self.message = str(subject)
@property def _stdpath(self, stdpaths, header_name):
def stderr(self): result = {}
for name, path in stdpaths:
if name not in result:
result[name] = []
if os.path.exists(path) and os.path.getsize(path) > 0:
output = [] output = []
for stderr_name, stderr_path in self.stderr_paths: label_begin = name + ":" + header_name
if (os.path.exists(stderr_path) and output.append(label_begin)
os.path.getsize(stderr_path) > 0): output.append('\n')
label_begin = '---- BEGIN ' + stderr_name + ':stderr ----' output.append('-' * len(label_begin))
label_end = '---- END ' + stderr_name + ':stderr ----' output.append('\n')
output.append('\n' + label_begin) with open(path, 'r') as fd:
with open(stderr_path, 'r') as fd:
output.append(fd.read()) output.append(fd.read())
output.append(label_end) output.append('\n')
return '\n'.join(output) result[name].append(''.join(output))
return result
def _stderr(self):
return self._stdpath(self.stderr_paths, 'stderr')
def _stdout(self):
return self._stdpath(self.stdout_paths, 'stdout')
def _update_dict_list(self, target, source):
for x in source:
if x not in target:
target[x] = []
target[x].extend(source[x])
@property
def std_streams(self):
std_dict = {}
self._update_dict_list(std_dict, self._stdout())
self._update_dict_list(std_dict, self._stderr())
return std_dict
def __str__(self): def __str__(self):
output = [] output = []
output.append(self.message) output.append(self.message)
header = "\nError processing " + self.entity_name output.append('\n\n')
header = "Error processing " + self.entity_name
under_header = '=' * len(header) under_header = '=' * len(header)
output.append(header) output.append(header)
output.append('\n')
output.append(under_header) output.append(under_header)
output.append('\n')
for param_name, param_value in self.entity_params: for param_name, param_value in self.entity_params:
output.append(param_name + ': ' + str(param_value)) output.append(param_name + ': ' + str(param_value))
output.append(self.stderr + '\n') output.append('\n')
return '\n'.join(output) output.append('\n')
for x in self.std_streams:
output.append(''.join(self.std_streams[x]))
return ''.join(output)
class CdistObjectError(CdistEntityError): class CdistObjectError(CdistEntityError):
@ -127,28 +158,38 @@ class CdistObjectError(CdistEntityError):
('name', cdist_object.name, ), ('name', cdist_object.name, ),
('path', cdist_object.absolute_path, ), ('path', cdist_object.absolute_path, ),
('source', " ".join(cdist_object.source), ), ('source', " ".join(cdist_object.source), ),
('type', cdist_object.cdist_type.absolute_path, ), ('type', os.path.realpath(cdist_object.cdist_type.absolute_path), ),
] ]
stderr_paths = [] stderr_paths = []
for stderr_name in os.listdir(cdist_object.stderr_path): for stderr_name in os.listdir(cdist_object.stderr_path):
stderr_path = os.path.join(cdist_object.stderr_path, stderr_path = os.path.join(cdist_object.stderr_path,
stderr_name) stderr_name)
stderr_paths.append((stderr_name, stderr_path, )) stderr_paths.append((stderr_name, stderr_path, ))
stdout_paths = []
for stdout_name in os.listdir(cdist_object.stdout_path):
stdout_path = os.path.join(cdist_object.stdout_path,
stdout_name)
stdout_paths.append((stdout_name, stdout_path, ))
super().__init__("object '{}'".format(cdist_object.name), super().__init__("object '{}'".format(cdist_object.name),
params, stderr_paths, subject) params, stdout_paths, stderr_paths, subject)
class InitialManifestError(CdistEntityError): class InitialManifestError(CdistEntityError):
"""Something went wrong while executing initial manifest""" """Something went wrong while executing initial manifest"""
def __init__(self, initial_manifest, stderr_path, subject=''): def __init__(self, initial_manifest, stdout_path, stderr_path, subject=''):
params = [ params = [
('path', initial_manifest, ), ('path', initial_manifest, ),
] ]
stdout_paths = []
stdout_paths = [
('init', stdout_path, ),
]
stderr_paths = [] stderr_paths = []
stderr_paths = [ stderr_paths = [
('init', stderr_path, ), ('init', stderr_path, ),
] ]
super().__init__('initial manifest', params, stderr_paths, subject) super().__init__('initial manifest', params, stdout_paths,
stderr_paths, subject)
def file_to_list(filename): def file_to_list(filename):

View file

@ -440,9 +440,10 @@ class Config(object):
self.manifest.run_initial_manifest(self.local.initial_manifest) self.manifest.run_initial_manifest(self.local.initial_manifest)
except cdist.Error as e: except cdist.Error as e:
which = "init" which = "init"
stdout_path = os.path.join(self.local.stdout_base_path, which)
stderr_path = os.path.join(self.local.stderr_base_path, which) stderr_path = os.path.join(self.local.stderr_base_path, which)
raise cdist.InitialManifestError(self.local.initial_manifest, raise cdist.InitialManifestError(self.local.initial_manifest,
stderr_path, e) stdout_path, stderr_path, e)
self.iterate_until_finished() self.iterate_until_finished()
self.cleanup() self.cleanup()
self._remove_files_dirs() self._remove_files_dirs()

View file

@ -259,10 +259,8 @@ class Local(object):
util.log_std_fd(self.log, command, stderr, 'Local stderr') util.log_std_fd(self.log, command, stderr, 'Local stderr')
util.log_std_fd(self.log, command, stdout, 'Local stdout') util.log_std_fd(self.log, command, stdout, 'Local stdout')
return output return output
except subprocess.CalledProcessError as e: except (OSError, subprocess.CalledProcessError) as error:
util.handle_called_process_error(e, command) raise cdist.Error(" ".join(command) + ": " + str(error.args[1]))
except OSError as error:
raise cdist.Error(" ".join(command) + ": " + error.args[1])
finally: finally:
if message_prefix: if message_prefix:
message.merge_messages() message.merge_messages()

View file

@ -343,10 +343,8 @@ class Remote(object):
util.log_std_fd(self.log, command, stdout, 'Remote stdout') util.log_std_fd(self.log, command, stdout, 'Remote stdout')
return output return output
except subprocess.CalledProcessError as e: except (OSError, subprocess.CalledProcessError) as error:
util.handle_called_process_error(e, command) raise cdist.Error(" ".join(command) + ": " + str(error.args[1]))
except OSError as error:
raise cdist.Error(" ".join(command) + ": " + error.args[1])
except UnicodeDecodeError: except UnicodeDecodeError:
raise DecodeError(command) raise DecodeError(command)
finally: finally:

View file

@ -127,6 +127,7 @@ def call_get_output(command, env=None, stderr=None):
return (_call_get_stdout(command, env, stderr), None) return (_call_get_stdout(command, env, stderr), None)
# Currently not used.
def handle_called_process_error(err, command): def handle_called_process_error(err, command):
# Currently, stderr is not captured. # Currently, stderr is not captured.
# errout = None # errout = None