Skip to content

Commit

Permalink
[jmxfetch] add list_jvms command
Browse files Browse the repository at this point in the history
New `list_jvms` command.
> List available Java virtual machines on the system using the Attach
  API.

See DataDog/jmxfetch#112
  • Loading branch information
yannmh committed Mar 10, 2017
1 parent 0eccc77 commit 95dced2
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 26 deletions.
63 changes: 38 additions & 25 deletions jmxfetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@
'tomcat',
]
JMX_COLLECT_COMMAND = 'collect'
JMX_LIST_JVMS = 'list_jvms'
JMX_LIST_COMMANDS = {
'list_everything': 'List every attributes available that has a type supported by JMXFetch',
'list_collected_attributes': 'List attributes that will actually be collected by your current instances configuration',
'list_matching_attributes': 'List attributes that match at least one of your instances configuration',
'list_not_matching_attributes': "List attributes that don't match any of your instances configuration",
'list_limited_attributes': "List attributes that do match one of your instances configuration but that are not being collected because it would exceed the number of metrics that can be collected",
JMX_COLLECT_COMMAND: "Start the collection of metrics based on your current configuration and display them in the console"}
JMX_LIST_JVMS: "List available Java virtual machines on the system using the Attach API",
JMX_COLLECT_COMMAND: "Start the collection of metrics based on your current configuration and display them in the console"
}

LINK_TO_DOC = "See http://docs.datadoghq.com/integrations/java/ for more information"

Expand Down Expand Up @@ -111,17 +114,30 @@ def register_signal_handlers(self):
except ValueError:
log.exception("Unable to register signal handlers.")

def configure(self, checks_list=None, clean_status_file=True):
def configure(self, command=None, checks_list=None, clean_status_file=True):
"""
Instantiate JMXFetch parameters, clean potential previous run leftovers.
"""
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.custom_jar_paths = \
tools_jar_path, self.custom_jar_paths, use_attach_api = \
self.get_configuration(self.confd_path, checks_list=checks_list)

# Setup the JDK `tool.jar`
if command == JMX_LIST_JVMS:
if not tools_jar_path:
raise InvalidJMXConfiguration(
u"Command `{}` requires access to the JDK `tools.jar` file. "
u"See `tools_jar_path` parameter in JMX YAML configuration files.".format(
JMX_LIST_JVMS
)
)
use_attach_api = True

self.tools_jar_path = tools_jar_path if use_attach_api else None

def should_run(self):
"""
Should JMXFetch run ?
Expand All @@ -137,15 +153,14 @@ def run(self, command=None, checks_list=None, reporter=None, redirect_std_stream
sys.stdout and sys.stderr. Set to True to redirect these streams to python's sys.stdout
and sys.stderr.
"""
command = command or JMX_COLLECT_COMMAND

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

try:
command = command or JMX_COLLECT_COMMAND

if len(self.invalid_checks) > 0:
try:
JMXFiles.write_status_file(self.invalid_checks)
Expand Down Expand Up @@ -197,6 +212,7 @@ def get_configuration(cls, confd_path, checks_list=None):
tools_jar_path = None
custom_jar_paths = []
invalid_checks = {}
use_attach_api = False

jmx_confd_checks = get_jmx_checks(confd_path, auto_conf=False)

Expand All @@ -205,7 +221,7 @@ def get_configuration(cls, confd_path, checks_list=None):
check_name = check['check_name']
filename = check['filename']
try:
is_jmx, check_java_bin_path, check_java_options, check_tools_jar_path, check_custom_jar_paths = \
is_jmx, check_java_bin_path, check_java_options, check_tools_jar_path, check_custom_jar_paths, use_attach_api = \
cls._is_jmx_check(check_config, check_name, checks_list)
if is_jmx:
jmx_checks.append(filename)
Expand All @@ -223,7 +239,7 @@ def get_configuration(cls, confd_path, checks_list=None):
check_name = check_name.encode('ascii', 'ignore')
invalid_checks[check_name] = str(e)

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

def _start(self, path_to_java, java_run_opts, jmx_checks, command, reporter, tools_jar_path, custom_jar_paths, redirect_std_streams):
if reporter is None:
Expand Down Expand Up @@ -338,7 +354,7 @@ def _is_jmx_check(check_config, check_name, checks_list):
java_bin_path = None
java_options = None
is_jmx = False
is_attach_api = False
use_attach_api = False
tools_jar_path = init_config.get("tools_jar_path")
custom_jar_paths = init_config.get("custom_jar_paths")

Expand All @@ -365,7 +381,7 @@ def _is_jmx_check(check_config, check_name, checks_list):
host = inst.get('host', None)
port = inst.get('port', None)
conf = inst.get('conf', init_config.get('conf', None))
tools_jar_path = inst.get('tools_jar_path')
tools_jar_path = tools_jar_path or inst.get('tools_jar_path')

# Support for attach api using a process name regex
proc_regex = inst.get('process_name_regex')
Expand All @@ -374,7 +390,7 @@ def _is_jmx_check(check_config, check_name, checks_list):
name = inst.get('name')

if proc_regex is not None:
is_attach_api = True
use_attach_api = True
elif jmx_url is not None:
if name is None:
raise InvalidJMXConfiguration("A name must be specified when using a jmx_url")
Expand Down Expand Up @@ -421,28 +437,25 @@ def _is_jmx_check(check_config, check_name, checks_list):
if instance and instance.get('java_options'):
java_options = instance.get('java_options')

if is_attach_api:
if tools_jar_path is None:
for instance in instances:
if instance and instance.get("tools_jar_path"):
tools_jar_path = instance.get("tools_jar_path")

if tools_jar_path is None:
raise InvalidJMXConfiguration("You must specify the path to tools.jar"
" in your JDK.")
elif not os.path.isfile(tools_jar_path):
raise InvalidJMXConfiguration("Unable to find tools.jar at %s" % tools_jar_path)
else:
tools_jar_path = None
if use_attach_api and not tools_jar_path:
raise InvalidJMXConfiguration(
u"You must specify the path to `tools.jar` in your JDK."
)
if tools_jar_path and not os.path.isfile(tools_jar_path):
raise InvalidJMXConfiguration(
u"Unable to find `tools.jar` at %s" % tools_jar_path
)

if custom_jar_paths:
if isinstance(custom_jar_paths, basestring):
custom_jar_paths = [custom_jar_paths]
for custom_jar_path in custom_jar_paths:
if not os.path.isfile(custom_jar_path):
raise InvalidJMXConfiguration("Unable to find custom jar at %s" % custom_jar_path)
raise InvalidJMXConfiguration(
"Unable to find custom jar at %s" % custom_jar_path
)

return is_jmx, java_bin_path, java_options, tools_jar_path, custom_jar_paths
return is_jmx, java_bin_path, java_options, tools_jar_path, custom_jar_paths, use_attach_api

def _get_path_to_jmxfetch(self):
return os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "checks",
Expand Down
2 changes: 1 addition & 1 deletion utils/jmx.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def jmx_command(args, agent_config, redirect_std_streams=False):
confd_directory = get_confd_path()

jmx_process = JMXFetch(confd_directory, agent_config)
jmx_process.configure()
jmx_process.configure(jmx_command)
should_run = jmx_process.should_run()

if should_run:
Expand Down

0 comments on commit 95dced2

Please sign in to comment.