From 3c58c8a6b03a45e12d5c309c2570172bacf400b0 Mon Sep 17 00:00:00 2001 From: Patrick Cockwell Date: Wed, 9 Jan 2013 19:19:19 -0500 Subject: [PATCH 1/2] Tracebacks are now available by doing -v or --verbose, also modified the usages of get_parsed_args() #329 --- agent.py | 7 +++---- checks/__init__.py | 4 +++- checks/check_status.py | 24 ++++++++++++++++++++++-- config.py | 6 +++--- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/agent.py b/agent.py index 8f0d04ef34..33427e7879 100755 --- a/agent.py +++ b/agent.py @@ -73,7 +73,7 @@ def run(self): CollectorStatus().persist() # Intialize the collector. - agentConfig = self._set_agent_config_hostname(get_config()) + agentConfig = self._set_agent_config_hostname(get_config(parse_args=true)) systemStats = get_system_stats() emitters = self._get_emitters(agentConfig) self.collector = Collector(agentConfig, emitters, systemStats) @@ -168,7 +168,7 @@ def setup_logging(agentConfig): def main(): options, args = get_parsed_args() - agentConfig = get_config() + agentConfig = get_config(options=options, args=args) # Logging setup_logging(agentConfig) @@ -188,7 +188,6 @@ def main(): return 2 command = args[0] - if command not in COMMANDS: sys.stderr.write("Unknown command: %s\n" % command) return 3 @@ -229,7 +228,7 @@ def main(): sys.stdout.write('dd-agent is not running.\n') elif 'info' == command: - return CollectorStatus.print_latest_status() + return CollectorStatus.print_latest_status(verbose=options.verbose) return 0 diff --git a/checks/__init__.py b/checks/__init__.py index c094cae91f..d1e3ca983b 100644 --- a/checks/__init__.py +++ b/checks/__init__.py @@ -10,6 +10,7 @@ import time import types import os +import sys from util import LaconicFilter from checks import check_status @@ -417,7 +418,8 @@ def run(self): instance_status = check_status.InstanceStatus(i, check_status.STATUS_OK) except Exception, e: self.log.exception("Check '%s' instance #%s failed" % (self.name, i)) - instance_status = check_status.InstanceStatus(i, check_status.STATUS_ERROR, e) + # Send the traceback (located at sys.exc_info()[2]) into the InstanceStatus otherwise a traceback won't be able to be printed + instance_status = check_status.InstanceStatus(i, check_status.STATUS_ERROR, e, sys.exc_info()[2]) instance_statuses.append(instance_status) return instance_statuses diff --git a/checks/check_status.py b/checks/check_status.py index af7c1ee5b2..fc00722dfa 100644 --- a/checks/check_status.py +++ b/checks/check_status.py @@ -11,6 +11,7 @@ import platform import sys import tempfile +import traceback # project import config @@ -162,7 +163,8 @@ def load_latest_status(cls): return None @classmethod - def print_latest_status(cls): + def print_latest_status(cls, verbose=False): + cls.verbose = verbose Stylizer.ENABLED = False try: if sys.stdout.isatty(): @@ -190,11 +192,16 @@ def _get_pickle_path(cls): class InstanceStatus(object): - def __init__(self, instance_id, status, error=None): + def __init__(self, instance_id, status, error=None, tb=None): self.instance_id = instance_id self.status = status self.error = repr(error) + if (type(tb).__name__ == 'traceback'): + self.traceback = traceback.format_tb(tb) + else: + self.traceback = None + def has_error(self): return self.status != STATUS_OK @@ -289,6 +296,19 @@ def body_lines(self): " - Collected %s metrics & %s events" % (cs.metric_count, cs.event_count), "" ] + + if self.verbose and s.traceback is not None: + # Formatting the traceback to look like a python traceback + check_lines.append(" Traceback (most recent call last):") + + # Format the traceback lines to look good in the output + for tb_line in s.traceback: + lines = tb_line.split('\n') + for line in lines: + if line.strip() == '': + continue + check_lines.append(' ' + line) + lines += check_lines # Emitter status diff --git a/config.py b/config.py index 8fefbf0cbc..1b1144f5bf 100644 --- a/config.py +++ b/config.py @@ -30,6 +30,8 @@ def get_parsed_args(): default=False,dest='use_forwarder') parser.add_option('-n', '--disable-dd', action='store_true', default=False, dest="disable_dd") + parser.add_option('-v', '--verbose', action='store_true', default=False, + dest='verbose', help='Print out available tracebacks for errors in checks') try: options, args = parser.parse_args() except SystemExit: @@ -141,11 +143,9 @@ def get_config_path(cfg_path=None, os_name=None): sys.stderr.write("Please supply a configuration file at %s or in the directory where the agent is currently deployed.\n" % str(exc)) sys.exit(3) -def get_config(parse_args = True, cfg_path=None, init_logging=False, options=None): +def get_config(parse_args = False, cfg_path=None, init_logging=False, options=None, args=None): if parse_args: options, args = get_parsed_args() - elif not options: - args = None # General config agentConfig = { From 7dfbcc70d407dea9f424e9c386127b254016ba65 Mon Sep 17 00:00:00 2001 From: Patrick Cockwell Date: Thu, 10 Jan 2013 11:28:14 -0500 Subject: [PATCH 2/2] some slight logic/syntax fixes for #336 --- agent.py | 11 +++++++---- config.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/agent.py b/agent.py index 33427e7879..db6bbb8264 100755 --- a/agent.py +++ b/agent.py @@ -63,7 +63,7 @@ def _handle_sigterm(self, signum, frame): if self.collector: self.collector.stop() - def run(self): + def run(self, config=None): """Main loop of the collector""" # Gracefully exit on sigterm. @@ -73,7 +73,10 @@ def run(self): CollectorStatus().persist() # Intialize the collector. - agentConfig = self._set_agent_config_hostname(get_config(parse_args=true)) + if not config: + config = get_config(parse_args=True) + + agentConfig = self._set_agent_config_hostname(config) systemStats = get_system_stats() emitters = self._get_emitters(agentConfig) self.collector = Collector(agentConfig, emitters, systemStats) @@ -168,7 +171,7 @@ def setup_logging(agentConfig): def main(): options, args = get_parsed_args() - agentConfig = get_config(options=options, args=args) + agentConfig = get_config(options=options) # Logging setup_logging(agentConfig) @@ -216,7 +219,7 @@ def main(): elif 'foreground' == command: logging.info('Running in foreground') - agent.run() + agent.run(config=agentConfig) # Commands that don't need the agent to be initialized. else: diff --git a/config.py b/config.py index 1b1144f5bf..77f5913374 100644 --- a/config.py +++ b/config.py @@ -143,7 +143,7 @@ def get_config_path(cfg_path=None, os_name=None): sys.stderr.write("Please supply a configuration file at %s or in the directory where the agent is currently deployed.\n" % str(exc)) sys.exit(3) -def get_config(parse_args = False, cfg_path=None, init_logging=False, options=None, args=None): +def get_config(parse_args=False, cfg_path=None, init_logging=False, options=None): if parse_args: options, args = get_parsed_args()