Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jmxfetch] add list_jvms command #2962

Merged
merged 1 commit into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 39 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 = {}
config_use_attach_api = False

jmx_confd_checks = get_jmx_checks(confd_path, auto_conf=False)

Expand All @@ -205,8 +221,9 @@ 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)
config_use_attach_api = config_use_attach_api or use_attach_api
if is_jmx:
jmx_checks.append(filename)
if java_bin_path is None and check_java_bin_path is not None:
Expand All @@ -223,7 +240,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, config_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 +355,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 +382,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 +391,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 +438,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