Начиная с J2SE 5 , доступны платформенные MBean-компоненты , которые позволяют отслеживать некоторые ключевые характеристики, касающиеся JVM, и (в некоторых случаях даже управлять ими) через JMX . Кроме того, многие приложения на основе JVM добавляют свои собственные функции с поддержкой JMX для мониторинга и управления. В блоге Groovy, JMX и Attach API я рассмотрел, как отобразить многие MBean-компоненты, предоставляемые платформой, используя Groovy, JMX и Attach API . В этой статье я рассмотрю более конкретные сценарии, которые обращаются к узко сфокусированному подмножеству этих доступных для платформы значений, доступных в RuntimeMXBean .
Мой предыдущий пост продемонстрировал способность просматривать широкий спектр деталей JVM с помощью Groovy и JMX. В большинстве случаев мне не нужны все эти детали сразу, а просто
нужен один или два предмета. Хотя я мог бы использовать такой инструмент, как JConsole , VisualVM или даже современную Java IDE, чтобы увидеть эти подробности, я иногда хотел бы запустить простой сценарий для получения точных результатов, которые я ищу, вместо того, чтобы использовать общий клиент JMX, который я нужно запустить и перейти к этой информации. Вот где простые сценарии, такие как показанные в этом посте, особенно удобны.
Все мои примеры в этом посте предполагают, что человек, выполняющий процесс Java, который будет отслеживаться / управляться, — это тот же человек (с тем же именем пользователя), который запускает сценарии, и что они используются для мониторинга процессов Java, работающих на одном и том же локальном компьютере. Это предположение позволяет использовать API Присоединения. Если сценарий выполнялся другим пользователем, а не процессами Java, или сценарии должны были выполняться на удаленных процессах Java, вместо этого использовались бы методы для удаленного JMX . Поскольку в этих примерах будет использоваться API присоединения, я поместил код, который использует каждый пример, в файл сценария Groovy, который вызывается каждым примером. Этот файл, который будет использоваться всеми моими сценариями, называется JmxServer.groovy и показан далее.
JmxServer.groovy
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
/** * JmxServer.groovy * * Functions meant to be called by other scripts or tools that need to use * the Attach API to access an MBeanServerConnection to use to manage and * monitor a particular JVM (and possibly the application hosted in that JVM) * identified by the provided Process ID (pid) */import javax.management.MBeanServerConnectionimport javax.management.ObjectNameimport javax.management.remote.JMXConnectorimport javax.management.remote.JMXConnectorFactoryimport javax.management.remote.JMXServiceURLimport com.sun.tools.attach.VirtualMachine/** * Provide an MBeanServerConnection based on the provided process ID (pid). * * @param pid Process ID of Java process for which MBeanServerConnection is * desired. * @return MBeanServerConnection connecting to Java process identified by pid. */def static MBeanServerConnection retrieveServerConnection(String pid){ def connectorAddressStr = "com.sun.management.jmxremote.localConnectorAddress" def jmxUrl = retrieveUrlForPid(pid, connectorAddressStr) def jmxConnector = JMXConnectorFactory.connect(jmxUrl) return jmxConnector.getMBeanServerConnection()}/** * Provide JMX URL for attaching to the provided process ID (pid). * * @param @pid Process ID for which JMX URL is needed to connect. * @param @connectorAddressStr String for connecting. * @return JMX URL to communicating with Java process identified by pid. */def static JMXServiceURL retrieveUrlForPid(String pid, String connectorAddressStr){ // Attach to the target application's virtual machine def vm = VirtualMachine.attach(pid) // Obtain Connector Address def connectorAddress = vm.getAgentProperties().getProperty(connectorAddressStr) // Load Agent if no connector address is available if (connectorAddress == null) { def agent = vm.getSystemProperties().getProperty("java.home") + File.separator + "lib" + File.separator + "management-agent.jar" vm.loadAgent(agent) // agent is started, get the connector address connectorAddress = vm.getAgentProperties().getProperty(connectorAddressStr) } return new JMXServiceURL(connectorAddress);} |
Наиболее важный метод, определенный в JmxServer.groovy , с точки зрения клиента сценария, — это метод retrieveServerConnection(String) . Этот метод исключает pid в качестве идентификатора процесса и использует его и вызов другого метода retrieveUrlForPid(String,String) для подключения к процессу Java, идентифицированному этим pid, и предоставления связанного экземпляра MBeanServerConnection . Самыми простыми подходами для поиска подходящего Java-pid являются использование jps (до Java 7 и Java 7) или jcmd (только Java 7+), как я кратко описал в своей недавней публикации « Загрузка AMX в GlassFish 3 с помощью Groovy» .
Инкапсулировав логику для получения конкретного экземпляра MBeanServerConnection JVM (процесса Java) на основе предоставленного pid, легко начать создавать простые скрипты Groovy, которые используют этот предоставленный MBeanServerConnection чтобы предоставить конкретные желательные подробности о рассматриваемом JVM (процессе Java). Обратите внимание, что все эти примеры сценариев находятся в том же каталоге, что и файл JmxServer.groovy и поэтому не нужно явно указывать детали пакета или области видимости.
Обычно требуется знать, что находится на пути к классам конкретной JVM по различным причинам, включая обнаружение причин ClassNotFoundException и NoClassDefFoundError . Путь к классу конкретной JVM предоставляется одним из его платформ MBean ( атрибут ClassPath в RuntimeMXBean ) и может быть легко обнаружен с помощью следующего скрипта Groovy:
displayClasspath.groovy
|
1
2
3
4
5
|
#!/usr/bin/env groovydef pid = args[0]def javaRuntime = new javax.management.ObjectName('java.lang:type=Runtime')def classpath = JmxServer.retrieveServerConnection(pid).getAttribute(javaRuntime, 'ClassPath')println '\nClasspath for Java pid (${pid}):\n${classpath}\n' |
Тот же RuntimeMXBean также предоставляет путь к загрузочному классу и путь к библиотеке Java . В следующих двух листингах кода показаны скрипты Groovy для доступа к обоим из них.
displayBootClasspath.groovy
|
1
2
3
4
5
|
#!/usr/bin/env groovydef pid = args[0]def javaRuntime = new javax.management.ObjectName('java.lang:type=Runtime')def bootClasspath = JmxServer.retrieveServerConnection(pid).getAttribute(javaRuntime, 'BootClassPath')println '\nBoot Classpath for Java pid (${pid}):\n${bootClasspath}\n' |
displayLibraryPath.groovy
|
1
2
3
4
5
|
#!/usr/bin/env groovydef pid = args[0]def javaRuntime = new javax.management.ObjectName('java.lang:type=Runtime')def libraryPath = JmxServer.retrieveServerConnection(pid).getAttribute(javaRuntime, 'LibraryPath')println '\nLibrary Path for Java pid (${pid}):\n${libraryPath}\n' |
Сценарии Groovy, показанные до сих пор для отображения деталей, связанных с классами поиска (classpath, boot classpath и путь к библиотеке), по сути, являются одним и тем же сценарием, но с каждым атрибутом, который RuntimeMXBean в RuntimeMXBean в каждом случае. Все три сценария выполняются для запущенного экземпляра GlassFish в следующем снимке экрана. Снимок включает команды jps и jcmd для определения pid (5352) для экземпляра GlassFish.
RuntimeMXBean может предложить больше, чем просто информацию о том, откуда были загружены классы. Он также включает атрибуты, связанные с поставщиком JVM, такие как имя и версия , но другие три метода, которые мне нравятся, чтобы использовать сценарии, это входные аргументы , системные свойства и время работы JVM (и время запуска). В следующих трех списках кодов Groovy показаны три сценария для отображения этих сведений, а за каждым фрагментом кода следует снимок экрана, демонстрирующий этот сценарий в действии с тем же экземпляром GlassFish, который использовался в последних примерах.
displayInputArguments.groovy
|
1
2
3
4
|
def pid = args[0]def javaRuntime = new javax.management.ObjectName('java.lang:type=Runtime')def inputArguments = JmxServer.retrieveServerConnection(pid).getAttribute(javaRuntime, 'InputArguments')println '\nInput Arguments for Java pid (${pid}):\n${inputArguments}\n' |
displaySystemProperties.groovy
|
1
2
3
4
5
|
#!/usr/bin/env groovydef pid = args[0]def javaRuntime = new javax.management.ObjectName('java.lang:type=Runtime')def systemProperties = JmxServer.retrieveServerConnection(pid).getAttribute(javaRuntime, 'SystemProperties')println '\nSystem Properties for Java pid (${pid}):\n${systemProperties}\n' |
displayJvmUptime.groovy
|
1
2
3
4
5
6
7
|
#!/usr/bin/env groovydef pid = args[0]def javaRuntime = new javax.management.ObjectName('java.lang:type=Runtime')def server = JmxServer.retrieveServerConnection(pid)def startTime = server.getAttribute(javaRuntime, 'StartTime')def uptime = server.getAttribute(javaRuntime, 'Uptime')println '\nJava process pid (${pid}) was started at ${new Date(startTime)} and has been up for ${uptime} ms.\n' |
Я использовал этот пост для демонстрации простых скриптов Groovy, которые получают информацию из RuntimeMXBean платформы JVM, такую как время запуска и время работы JVM, системные свойства и входные аргументы для процесса JVM, а также информацию о пути, такую как classpath, boot classpath и library путь. Хотя эта информация доступна через такие инструменты, как JConsole, VisualVM и Java IDE (все они получают из того же источника, что и эти сценарии!), Сценарии иногда могут быть полезны (быстрее запускаться и могут быть включены в другие сценарии, например).
Ссылка: Мониторинг ключевых характеристик JVM с помощью Groovy, JMX и RuntimeMXBean от нашего партнера по JCG Дастина Маркса из блога Inspired by Actual Events .


