aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sos/report/plugins/__init__.py17
-rw-r--r--sos/utilities.py19
-rw-r--r--tests/report_tests/plugin_tests/logs.py4
3 files changed, 35 insertions, 5 deletions
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
index 4720bad3..0fabbbd0 100644
--- a/sos/report/plugins/__init__.py
+++ b/sos/report/plugins/__init__.py
@@ -1935,6 +1935,7 @@ class Plugin(object):
'parameters': cmd.split(' ')[1:],
'exec': cmd,
'filepath': None,
+ 'truncated': result['truncated'],
'return_code': result['status'],
'run_time': time() - start,
'tags': _tags
@@ -1966,6 +1967,10 @@ class Plugin(object):
self._log_debug("collected output of '%s' in %s (changes=%s)"
% (cmd.split()[0], run_time, changes))
+ if result['truncated']:
+ self._log_info("collected output of '%s' was truncated"
+ % cmd.split()[0])
+
if suggest_filename:
outfn = self._make_command_filename(suggest_filename, subdir)
else:
@@ -1973,10 +1978,22 @@ class Plugin(object):
outfn_strip = outfn[len(self.commons['cmddir'])+1:]
+ if result['truncated']:
+ linkfn = outfn
+ outfn = outfn.replace('sos_commands', 'sos_strings') + '.tailed'
+
if binary:
self.archive.add_binary(result['output'], outfn)
else:
self.archive.add_string(result['output'], outfn)
+ if result['truncated']:
+ # we need to manually build the relative path from the paths that
+ # exist within the build dir to properly drop these symlinks
+ _outfn_path = os.path.join(self.archive.get_archive_path(), outfn)
+ _link_path = os.path.join(self.archive.get_archive_path(), linkfn)
+ rpath = os.path.relpath(_outfn_path, _link_path)
+ rpath = rpath.replace('../', '', 1)
+ self.archive.add_link(rpath, linkfn)
if root_symlink:
self.archive.add_link(outfn, root_symlink)
diff --git a/sos/utilities.py b/sos/utilities.py
index 8c36b27a..fb13979a 100644
--- a/sos/utilities.py
+++ b/sos/utilities.py
@@ -159,12 +159,13 @@ def sos_get_command_output(command, timeout=300, stderr=False,
raise SoSTimeoutError
time.sleep(0.01)
stdout = reader.get_contents()
+ truncated = reader.is_full
while p.poll() is None:
pass
except OSError as e:
if e.errno == errno.ENOENT:
- return {'status': 127, 'output': ""}
+ return {'status': 127, 'output': "", 'truncated': ''}
else:
raise e
@@ -173,7 +174,8 @@ def sos_get_command_output(command, timeout=300, stderr=False,
return {
'status': p.returncode,
- 'output': stdout
+ 'output': stdout,
+ 'truncated': truncated
}
@@ -224,11 +226,11 @@ class AsyncReader(threading.Thread):
self.chan = channel
self.binary = binary
self.chunksize = 2048
- slots = None
+ self.slots = None
if sizelimit:
sizelimit = sizelimit * 1048576 # convert to bytes
- slots = int(sizelimit / self.chunksize)
- self.deque = deque(maxlen=slots)
+ self.slots = int(sizelimit / self.chunksize)
+ self.deque = deque(maxlen=self.slots)
self.running = True
self.start()
@@ -264,6 +266,13 @@ class AsyncReader(threading.Thread):
else:
return b''.join(ln for ln in self.deque)
+ @property
+ def is_full(self):
+ """Checks if the deque is full, implying that output was truncated"""
+ if not self.slots:
+ return False
+ return len(self.deque) == self.slots
+
class ImporterHelper(object):
"""Provides a list of modules that can be imported in a package.
diff --git a/tests/report_tests/plugin_tests/logs.py b/tests/report_tests/plugin_tests/logs.py
index 9148bbff..cc6a8365 100644
--- a/tests/report_tests/plugin_tests/logs.py
+++ b/tests/report_tests/plugin_tests/logs.py
@@ -67,3 +67,7 @@ class LogsSizeLimitTest(StageTwoReportTest):
assert jsize <= 105906176, "Collected journal is larger than 100MB"
assert jsize > 27262976, "Collected journal limited by --log-size"
+ def test_journal_tailed_and_linked(self):
+ self.assertFileCollected('sos_strings/logs/journalctl_--no-pager_--catalog_--boot.tailed')
+ journ = self.get_name_in_archive('sos_commands/logs/journalctl_--no-pager_--catalog_--boot')
+ assert os.path.islink(journ), "Journal in sos_commands/logs is not a symlink"