Skip to content

Commit

Permalink
Merge pull request #1726 from DataDog/olivielpeau/jmx-flare
Browse files Browse the repository at this point in the history
[flare] Add JMXFetch-specific info
  • Loading branch information
olivielpeau committed Jul 2, 2015
2 parents f38fa18 + 4981b5a commit 5ba2c66
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 81 deletions.
32 changes: 2 additions & 30 deletions agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,20 @@
from checks.check_status import CollectorStatus
from checks.collector import Collector
from config import (
get_confd_path,
get_config,
get_parsed_args,
get_system_stats,
load_check_directory,
)
from daemon import AgentSupervisor, Daemon
from emitter import http_emitter
from jmxfetch import JMX_LIST_COMMANDS, JMXFetch
from util import (
EC2,
get_hostname,
get_os,
Watchdog,
)
from utils.flare import configcheck, Flare
from utils.jmx import jmx_command
from utils.pidfile import PidFile
from utils.profile import AgentProfiler

Expand Down Expand Up @@ -329,33 +327,7 @@ def parent_func():
configcheck()

elif 'jmx' == command:
if len(args) < 2 or args[1] not in JMX_LIST_COMMANDS.keys():
print "#" * 80
print "JMX tool to be used to help configuring your JMX checks."
print "See http://docs.datadoghq.com/integrations/java/ for more information"
print "#" * 80
print "\n"
print "You have to specify one of the following commands:"
for command, desc in JMX_LIST_COMMANDS.iteritems():
print " - %s [OPTIONAL: LIST OF CHECKS]: %s" % (command, desc)
print "Example: sudo /etc/init.d/datadog-agent jmx list_matching_attributes tomcat jmx solr"
print "\n"

else:
jmx_command = args[1]
checks_list = args[2:]
confd_directory = get_confd_path(get_os())

jmx_process = JMXFetch(confd_directory, agentConfig)
jmx_process.configure()
should_run = jmx_process.should_run()

if should_run:
jmx_process.run(jmx_command, checks_list, reporter="console")
else:
print "Couldn't find any valid JMX configuration in your conf.d directory: %s" % confd_directory
print "Have you enabled any JMX check ?"
print "If you think it's not normal please get in touch with Datadog Support"
jmx_command(args[1:], agentConfig)

elif 'flare' == command:
Flare.check_user_rights()
Expand Down
7 changes: 5 additions & 2 deletions checks/check_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import config
from config import _is_affirmative, _windows_commondata_path, get_config
from util import plural
from utils.jmxfiles import JMXFiles
from utils.jmx import JMXFiles
from utils.ntp import get_ntp_args
from utils.pidfile import PidFile
from utils.platform import Platform
Expand Down Expand Up @@ -88,7 +88,10 @@ def logger_info():
if len(root_logger.handlers) > 0:
for handler in root_logger.handlers:
if isinstance(handler, logging.StreamHandler):
loggers.append(handler.stream.name)
try:
loggers.append(handler.stream.name)
except AttributeError:
loggers.append("unnamed stream")
if isinstance(handler, logging.handlers.SysLogHandler):
if isinstance(handler.address, basestring):
loggers.append('syslog:%s' % handler.address)
Expand Down
2 changes: 1 addition & 1 deletion checks/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
get_uuid,
Timer,
)
from utils.jmxfiles import JMXFiles
from utils.jmx import JMXFiles
from utils.subprocess_output import subprocess

log = logging.getLogger(__name__)
Expand Down
65 changes: 44 additions & 21 deletions jmxfetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
get_logging_config,
PathNotFound,
)
from util import get_os, yLoader
from utils.jmxfiles import JMXFiles
from util import yLoader
from utils.jmx import JMXFiles
from utils.platform import Platform
from utils.subprocess_output import subprocess

Expand Down Expand Up @@ -98,27 +98,36 @@ def register_signal_handlers(self):
except ValueError:
log.exception("Unable to register signal handlers.")

def configure(self, check_list=None):
def configure(self, checks_list=None, clean_status_file=True):
"""
Instantiate JMXFetch parameters, clean potential previous run leftovers.
"""
JMXFiles.clean_status_file()
if clean_status_file:
JMXFiles.clean_status_file()

self.jmx_checks, self.invalid_checks, self.java_bin_path, self.java_options, self.tools_jar_path = \
self.get_configuration(check_list)
self.get_configuration(self.confd_path, checks_list=checks_list)

def should_run(self):
"""
Should JMXFetch run ?
"""
return self.jmx_checks is not None and self.jmx_checks != []

def run(self, command=None, check_list=None, reporter=None):
def run(self, command=None, checks_list=None, reporter=None, redirect_std_streams=False):
"""
Run JMXFetch
redirect_std_streams: if left to False, the stdout and stderr of JMXFetch are streamed
directly to the environment's stdout and stderr and cannot be retrieved via python's
sys.stdout and sys.stderr. Set to True to redirect these streams to python's sys.stdout
and sys.stderr.
"""

if check_list or self.jmx_checks is None:
# (Re)set/(re)configure JMXFetch parameters when `check_list` is specified or
if checks_list or self.jmx_checks is None:
# (Re)set/(re)configure JMXFetch parameters when `checks_list` is specified or
# no configuration was found
self.configure(check_list)
self.configure(checks_list)

try:
command = command or JMX_COLLECT_COMMAND
Expand All @@ -131,7 +140,7 @@ def run(self, command=None, check_list=None, reporter=None):

if len(self.jmx_checks) > 0:
return self._start(self.java_bin_path, self.java_options, self.jmx_checks,
command, reporter, self.tools_jar_path)
command, reporter, self.tools_jar_path, redirect_std_streams)
else:
# We're exiting purposefully, so exit with zero (supervisor's expected
# code). HACK: Sleep a little bit so supervisor thinks we've started cleanly
Expand All @@ -142,9 +151,10 @@ def run(self, command=None, check_list=None, reporter=None):
log.exception("Error while initiating JMXFetch")
raise

def get_configuration(self, checks_list=None):
@classmethod
def get_configuration(cls, confd_path, checks_list=None):
"""
Return a tuple (jmx_checks, invalid_checks, java_bin_path, java_options)
Return a tuple (jmx_checks, invalid_checks, java_bin_path, java_options, tools_jar_path)
jmx_checks: list of yaml files that are jmx checks
(they have the is_jmx flag enabled or they are in JMX_CHECKS)
Expand Down Expand Up @@ -173,7 +183,7 @@ def get_configuration(self, checks_list=None):
tools_jar_path = None
invalid_checks = {}

for conf in glob.glob(os.path.join(self.confd_path, '*.yaml')):
for conf in glob.glob(os.path.join(confd_path, '*.yaml')):
filename = os.path.basename(conf)
check_name = filename.split('.')[0]

Expand All @@ -190,7 +200,7 @@ def get_configuration(self, checks_list=None):

try:
is_jmx, check_java_bin_path, check_java_options, check_tools_jar_path = \
self._is_jmx_check(check_config, check_name, checks_list)
cls._is_jmx_check(check_config, check_name, checks_list)
if is_jmx:
jmx_checks.append(filename)
if java_bin_path is None and check_java_bin_path is not None:
Expand All @@ -207,7 +217,7 @@ def get_configuration(self, checks_list=None):

return (jmx_checks, invalid_checks, java_bin_path, java_options, tools_jar_path)

def _start(self, path_to_java, java_run_opts, jmx_checks, command, reporter, tools_jar_path):
def _start(self, path_to_java, java_run_opts, jmx_checks, command, reporter, tools_jar_path, redirect_std_streams):
statsd_port = self.agentConfig.get('dogstatsd_port', "8125")
if reporter is None:
reporter = "statsd:%s" % str(statsd_port)
Expand Down Expand Up @@ -260,14 +270,27 @@ def _start(self, path_to_java, java_run_opts, jmx_checks, command, reporter, too
subprocess_args.insert(1, opt)

log.info("Running %s" % " ".join(subprocess_args))
jmx_process = subprocess.Popen(subprocess_args, close_fds=True)

# Launch JMXfetch subprocess
jmx_process = subprocess.Popen(
subprocess_args,
close_fds=not redirect_std_streams, # set to True instead of False when the streams are redirected for WIN compatibility
stdout=subprocess.PIPE if redirect_std_streams else None,
stderr=subprocess.PIPE if redirect_std_streams else None
)
self.jmx_process = jmx_process

# Register SIGINT and SIGTERM signal handlers
self.register_signal_handlers()

# Wait for JMXFetch to return
jmx_process.wait()
if redirect_std_streams:
# Wait for JMXFetch to return, and write out the stdout and stderr of JMXFetch to sys.stdout and sys.stderr
out, err = jmx_process.communicate()
sys.stdout.write(out)
sys.stderr.write(err)
else:
# Wait for JMXFetch to return
jmx_process.wait()

return jmx_process.returncode

Expand All @@ -285,7 +308,8 @@ def _start(self, path_to_java, java_run_opts, jmx_checks, command, reporter, too
log.exception("Couldn't launch JMXFetch")
raise

def _is_jmx_check(self, check_config, check_name, checks_list):
@staticmethod
def _is_jmx_check(check_config, check_name, checks_list):
init_config = check_config.get('init_config', {}) or {}
java_bin_path = None
java_options = None
Expand Down Expand Up @@ -392,9 +416,8 @@ def _get_path_to_jmxfetch(self):

def init(config_path=None):
agentConfig = get_config(parse_args=False, cfg_path=config_path)
osname = get_os()
try:
confd_path = get_confd_path(osname)
confd_path = get_confd_path()
except PathNotFound, e:
log.error("No conf.d folder found at '%s' or in the directory where"
"the Agent is currently deployed.\n" % e.args[0])
Expand Down
Loading

0 comments on commit 5ba2c66

Please sign in to comment.