├── debian ├── compat ├── install ├── templates ├── config ├── changelog ├── lintian-overrides ├── prerm ├── control ├── copyright ├── preinst ├── rules ├── init └── postinst ├── bin └── yaml2jmxtrans ├── lib ├── gmetric4j.jar ├── guava-18.0.jar ├── sweetened.jar ├── jrobin-1.5.9.jar ├── junit-4.9b2.jar ├── log4j-1.2.16.jar ├── oncrpc-1.0.7.jar ├── quartz-1.8.4.jar ├── velocity-1.7.jar ├── commons-cli-1.2.jar ├── commons-io-1.4.jar ├── gmetric4j-1.0.3.jar ├── jpathwatch-0-95.jar ├── slf4j-api-1.7.6.jar ├── annotations-3.0.0.jar ├── ant-contrib-1.0b3.jar ├── commons-codec-1.3.jar ├── commons-jexl-2.1.1.jar ├── commons-lang-2.5.jar ├── commons-pool-1.5.6.jar ├── logback-core-1.1.1.jar ├── xnio-api-3.0.0.GA.jar ├── xnio-nio-3.0.7.GA.jar ├── ant-googlecode-0.0.2.jar ├── jrobin-1.5.9-sources.jar ├── quartz-1.8.4-sources.jar ├── slf4j-log4j12-1.7.6.jar ├── commons-logging-1.1.1.jar ├── jackson-core-asl-1.6.3.jar ├── jboss-logging-3.1.0.GA.jar ├── jboss-remoting-3.2.0.GA.jar ├── jboss-sasl-1.0.3.Final.jar ├── jdeparser-1.0.0.Final.jar ├── logback-classic-1.1.1.jar ├── remoting-jmx-1.1.1.CR2.jar ├── commons-codec-1.3-sources.jar ├── commons-lang-2.5-sources.jar ├── jackson-mapper-asl-1.6.3.jar ├── remoting-jmx-1.0.1.Final.jar ├── commons-pool-1.5.6-sources.jar ├── jboss-marshalling-1.3.7.GA.jar ├── remoting-jmx-1.1.1.CR2-sources.jar ├── jboss-marshalling-river-1.3.16.GA.jar ├── remoting-jmx-1.0.1.Final-sources.jar ├── jboss-logging-processor-1.1.0.Final.jar └── org.eclipse.jgit-1.1.0.201109151100-r.jar ├── .travis.yml ├── javadoc ├── resources │ ├── tab.gif │ ├── inherit.gif │ ├── titlebar.gif │ ├── background.gif │ └── titlebar_end.gif ├── package-list ├── com │ └── googlecode │ │ └── jmxtrans │ │ ├── jobs │ │ └── package-frame.html │ │ ├── package-frame.html │ │ ├── model │ │ ├── package-frame.html │ │ └── output │ │ │ └── package-frame.html │ │ ├── jmx │ │ └── package-frame.html │ │ ├── example │ │ └── package-frame.html │ │ └── util │ │ └── package-frame.html ├── overview-frame.html ├── index.html └── deprecated-list.html ├── .gitignore ├── .settings └── org.eclipse.jdt.ui.prefs ├── test ├── com │ └── googlecode │ │ └── jmxtrans │ │ ├── connections │ │ ├── JmxConnectionFactoryTests.java │ │ ├── SocketFactoryTests.java │ │ └── TCPEchoServer.java │ │ ├── model │ │ ├── ServerFixtures.java │ │ ├── output │ │ │ ├── NumberUtilsTest.java │ │ │ ├── GraphiteWriterTests.java │ │ │ ├── GangliaWriterTests.java │ │ │ └── BaseOutputWriterTests.java │ │ ├── naming │ │ │ ├── StringUtilsTest.java │ │ │ └── KeyUtilsTests.java │ │ ├── PropertyResolverTests.java │ │ ├── ServerTests.java │ │ └── MergingTests.java │ │ ├── EqualsTests.java │ │ ├── util │ │ ├── JsonUtilsTest.java │ │ ├── JsonPrinterTest.java │ │ └── WatchDirTest.java │ │ └── jmx │ │ └── JmxProcessingTests.java └── example.json ├── tools └── setup-vm.sh ├── src ├── com │ └── googlecode │ │ └── jmxtrans │ │ ├── cli │ │ ├── OptionsException.java │ │ ├── JmxTransConfiguration.java │ │ └── CliArgumentParser.java │ │ ├── model │ │ ├── NamingStrategy.java │ │ ├── ValidationException.java │ │ ├── naming │ │ │ ├── ClassAttributeNamingStrategy.java │ │ │ └── StringUtils.java │ │ ├── output │ │ │ ├── StdOutWriter.java │ │ │ ├── NumberUtils.java │ │ │ ├── DailyKeyOutWriter.java │ │ │ ├── VelocityWriter.java │ │ │ ├── Log4JWriter.java │ │ │ └── RRDWriter.java │ │ ├── OutputWriter.java │ │ ├── JmxProcess.java │ │ ├── Result.java │ │ └── PropertyResolver.java │ │ ├── util │ │ ├── WatchedCallback.java │ │ ├── JsonUtils.java │ │ ├── JsonPrinter.java │ │ ├── LocalJMXConnector.java │ │ ├── SignalInterceptor.java │ │ └── WatchDir.java │ │ ├── exceptions │ │ └── LifecycleException.java │ │ ├── monitoring │ │ ├── ManagedGenericKeyedObjectPoolMBean.java │ │ ├── ManagedObject.java │ │ ├── ManagedJmxTransformerProcessMXBean.java │ │ └── ManagedGenericKeyedObjectPool.java │ │ ├── jmx │ │ ├── ProcessServerThread.java │ │ ├── ProcessQueryThread.java │ │ └── JmxQueryProcessor.java │ │ ├── guice │ │ ├── GuiceJobFactory.java │ │ └── JmxTransModule.java │ │ ├── connections │ │ ├── DatagramSocketFactory.java │ │ ├── JmxConnectionFactory.java │ │ ├── JMXConnectionParams.java │ │ └── SocketFactory.java │ │ ├── example │ │ ├── Graphite.java │ │ ├── MemoryPool.java │ │ ├── HeapMemory.java │ │ ├── Ehcache.java │ │ ├── Ganglia.java │ │ ├── Tester.java │ │ ├── TreeWalker2.java │ │ ├── Hibernate.java │ │ ├── InterestingInfo.java │ │ ├── ActiveMQ2.java │ │ └── TreeWalker.java │ │ └── jobs │ │ └── ServerJob.java ├── etc │ └── checkstyle.xml ├── quartz.server.properties ├── log4j.xml └── assembly │ └── dist.xml ├── README.html ├── rpm ├── SOURCES │ ├── systemd │ └── jmxtrans.init └── build.sh ├── memorypool.json ├── heapmemory.json ├── samples └── activemq │ ├── queues-graphite.json │ └── queues.json ├── example.json ├── rrd-template-example.xml ├── DEVELOPERS.txt ├── LICENSE.txt ├── doc └── tools │ ├── README.md │ └── yaml2jmxtrans-example.yaml ├── heapmemory-rrd-template.xml ├── jar.properties └── README.md /debian/compat: -------------------------------------------------------------------------------- 1 | 7 -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | usr/share/@PACKAGE@ 2 | usr/share/doc/@PACKAGE@ 3 | bin /usr 4 | -------------------------------------------------------------------------------- /bin/yaml2jmxtrans: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec /usr/share/jmxtrans/tools/yaml2jmxtrans.py "$@" -------------------------------------------------------------------------------- /lib/gmetric4j.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/gmetric4j.jar -------------------------------------------------------------------------------- /lib/guava-18.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/guava-18.0.jar -------------------------------------------------------------------------------- /lib/sweetened.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/sweetened.jar -------------------------------------------------------------------------------- /lib/jrobin-1.5.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jrobin-1.5.9.jar -------------------------------------------------------------------------------- /lib/junit-4.9b2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/junit-4.9b2.jar -------------------------------------------------------------------------------- /lib/log4j-1.2.16.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/log4j-1.2.16.jar -------------------------------------------------------------------------------- /lib/oncrpc-1.0.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/oncrpc-1.0.7.jar -------------------------------------------------------------------------------- /lib/quartz-1.8.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/quartz-1.8.4.jar -------------------------------------------------------------------------------- /lib/velocity-1.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/velocity-1.7.jar -------------------------------------------------------------------------------- /lib/commons-cli-1.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-cli-1.2.jar -------------------------------------------------------------------------------- /lib/commons-io-1.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-io-1.4.jar -------------------------------------------------------------------------------- /lib/gmetric4j-1.0.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/gmetric4j-1.0.3.jar -------------------------------------------------------------------------------- /lib/jpathwatch-0-95.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jpathwatch-0-95.jar -------------------------------------------------------------------------------- /lib/slf4j-api-1.7.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/slf4j-api-1.7.6.jar -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | install: mvn dependency:go-offline -B -V 3 | script: "mvn clean verify -B -V" 4 | -------------------------------------------------------------------------------- /javadoc/resources/tab.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/javadoc/resources/tab.gif -------------------------------------------------------------------------------- /lib/annotations-3.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/annotations-3.0.0.jar -------------------------------------------------------------------------------- /lib/ant-contrib-1.0b3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/ant-contrib-1.0b3.jar -------------------------------------------------------------------------------- /lib/commons-codec-1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-codec-1.3.jar -------------------------------------------------------------------------------- /lib/commons-jexl-2.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-jexl-2.1.1.jar -------------------------------------------------------------------------------- /lib/commons-lang-2.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-lang-2.5.jar -------------------------------------------------------------------------------- /lib/commons-pool-1.5.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-pool-1.5.6.jar -------------------------------------------------------------------------------- /lib/logback-core-1.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/logback-core-1.1.1.jar -------------------------------------------------------------------------------- /lib/xnio-api-3.0.0.GA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/xnio-api-3.0.0.GA.jar -------------------------------------------------------------------------------- /lib/xnio-nio-3.0.7.GA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/xnio-nio-3.0.7.GA.jar -------------------------------------------------------------------------------- /lib/ant-googlecode-0.0.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/ant-googlecode-0.0.2.jar -------------------------------------------------------------------------------- /lib/jrobin-1.5.9-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jrobin-1.5.9-sources.jar -------------------------------------------------------------------------------- /lib/quartz-1.8.4-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/quartz-1.8.4-sources.jar -------------------------------------------------------------------------------- /lib/slf4j-log4j12-1.7.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/slf4j-log4j12-1.7.6.jar -------------------------------------------------------------------------------- /javadoc/resources/inherit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/javadoc/resources/inherit.gif -------------------------------------------------------------------------------- /javadoc/resources/titlebar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/javadoc/resources/titlebar.gif -------------------------------------------------------------------------------- /lib/commons-logging-1.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-logging-1.1.1.jar -------------------------------------------------------------------------------- /lib/jackson-core-asl-1.6.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jackson-core-asl-1.6.3.jar -------------------------------------------------------------------------------- /lib/jboss-logging-3.1.0.GA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jboss-logging-3.1.0.GA.jar -------------------------------------------------------------------------------- /lib/jboss-remoting-3.2.0.GA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jboss-remoting-3.2.0.GA.jar -------------------------------------------------------------------------------- /lib/jboss-sasl-1.0.3.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jboss-sasl-1.0.3.Final.jar -------------------------------------------------------------------------------- /lib/jdeparser-1.0.0.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jdeparser-1.0.0.Final.jar -------------------------------------------------------------------------------- /lib/logback-classic-1.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/logback-classic-1.1.1.jar -------------------------------------------------------------------------------- /lib/remoting-jmx-1.1.1.CR2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/remoting-jmx-1.1.1.CR2.jar -------------------------------------------------------------------------------- /javadoc/resources/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/javadoc/resources/background.gif -------------------------------------------------------------------------------- /lib/commons-codec-1.3-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-codec-1.3-sources.jar -------------------------------------------------------------------------------- /lib/commons-lang-2.5-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-lang-2.5-sources.jar -------------------------------------------------------------------------------- /lib/jackson-mapper-asl-1.6.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jackson-mapper-asl-1.6.3.jar -------------------------------------------------------------------------------- /lib/remoting-jmx-1.0.1.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/remoting-jmx-1.0.1.Final.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | _eclipse 4 | .idea 5 | logs 6 | out 7 | *.iml 8 | *.iws 9 | *.ipr 10 | target 11 | -------------------------------------------------------------------------------- /javadoc/resources/titlebar_end.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/javadoc/resources/titlebar_end.gif -------------------------------------------------------------------------------- /lib/commons-pool-1.5.6-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/commons-pool-1.5.6-sources.jar -------------------------------------------------------------------------------- /lib/jboss-marshalling-1.3.7.GA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jboss-marshalling-1.3.7.GA.jar -------------------------------------------------------------------------------- /lib/remoting-jmx-1.1.1.CR2-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/remoting-jmx-1.1.1.CR2-sources.jar -------------------------------------------------------------------------------- /debian/templates: -------------------------------------------------------------------------------- 1 | Template: @PACKAGE@/jvm_heap_size 2 | Type: string 3 | Description: JVM Min/Max Heap size (MB): 4 | The default is 512. 5 | -------------------------------------------------------------------------------- /lib/jboss-marshalling-river-1.3.16.GA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jboss-marshalling-river-1.3.16.GA.jar -------------------------------------------------------------------------------- /lib/remoting-jmx-1.0.1.Final-sources.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/remoting-jmx-1.0.1.Final-sources.jar -------------------------------------------------------------------------------- /lib/jboss-logging-processor-1.1.0.Final.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/jboss-logging-processor-1.1.0.Final.jar -------------------------------------------------------------------------------- /lib/org.eclipse.jgit-1.1.0.201109151100-r.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/jmxtrans/master/lib/org.eclipse.jgit-1.1.0.201109151100-r.jar -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | #Tue Jan 24 16:58:35 PST 2012 2 | eclipse.preferences.version=1 3 | formatter_profile=_Jmxtrans 4 | formatter_settings_version=12 5 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/connections/JmxConnectionFactoryTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | public class JmxConnectionFactoryTests { 4 | } 5 | -------------------------------------------------------------------------------- /tools/setup-vm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | aptitude update 4 | aptitude safe-upgrade 5 | apt-get -y install devscripts debhelper build-essential git ant openjdk-6-jdk openssh-server -------------------------------------------------------------------------------- /debian/config: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Source debconf library. 6 | . /usr/share/debconf/confmodule 7 | 8 | db_input high @PACKAGE@/jvm_heap_size || true 9 | db_go 10 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | @PACKAGE@ (@VERSION@-@DEB_VERSION@) stable; urgency=low 2 | 3 | * See http://jmxtrans.googlecode.com/ for more details. 4 | 5 | -- Jon Stevens @PROPER_NOW@ 6 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/cli/OptionsException.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.cli; 2 | 3 | public class OptionsException extends Exception { 4 | 5 | public OptionsException(String msg) { 6 | super(msg); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /javadoc/package-list: -------------------------------------------------------------------------------- 1 | com.googlecode.jmxtrans 2 | com.googlecode.jmxtrans.example 3 | com.googlecode.jmxtrans.jmx 4 | com.googlecode.jmxtrans.jobs 5 | com.googlecode.jmxtrans.model 6 | com.googlecode.jmxtrans.model.output 7 | com.googlecode.jmxtrans.util 8 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/NamingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | /** 4 | * Strategy for naming metrics, tags, and the like given a result. 5 | */ 6 | public interface NamingStrategy { 7 | String formatName(Result result); 8 | } 9 | -------------------------------------------------------------------------------- /README.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | README for jmxtrans 4 | 5 | 6 | 7 |

README

8 | 9 |

10 | For usage instructions and release notes, see the homepage. 11 |

12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/util/WatchedCallback.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import java.io.File; 4 | 5 | public interface WatchedCallback { 6 | 7 | void fileModified(File file) throws Exception; 8 | 9 | void fileDeleted(File file) throws Exception; 10 | 11 | void fileAdded(File file) throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /debian/lintian-overrides: -------------------------------------------------------------------------------- 1 | @PACKAGE@: new-package-should-close-itp-bug 2 | @PACKAGE@: maintainer-script-needs-depends-on-adduser preinst 3 | @PACKAGE@: helper-templates-in-copyright 4 | @PACKAGE@: virtual-package-depends-without-real-package-depends 5 | @PACKAGE@: binary-without-manpage usr/bin/yaml2jmxtrans 6 | @PACKAGE@: python-script-but-no-python-dep usr/share/jmxtrans/tools/yaml2jmxtrans.py 7 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/ValidationException.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | public class ValidationException extends Exception { 4 | 5 | private final Query query; 6 | 7 | public ValidationException(String msg, Query query) { 8 | super(msg); 9 | this.query = query; 10 | } 11 | 12 | public Query getQuery() { 13 | return query; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /debian/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Source debconf library. 6 | . /usr/share/debconf/confmodule 7 | 8 | 9 | case "$1" in 10 | remove|purge) 11 | rm -rf /usr/share/@PACKAGE@/logs 12 | ;; 13 | esac 14 | 15 | # dh_installdeb will replace this with shell code automatically 16 | # generated by other debhelper scripts. 17 | 18 | #DEBHELPER# 19 | 20 | exit 0 21 | 22 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: @PACKAGE@ 2 | Build-Depends: debhelper (>= 7) 3 | Maintainer: Jon Stevens 4 | Standards-Version: 3.9.1 5 | 6 | Package: @PACKAGE@ 7 | Architecture: all 8 | Section: admin 9 | Priority: optional 10 | Depends: ${misc:Depends}, java2-runtime 11 | Recommends: python-yaml 12 | Description: @FULL_VERSION@ - @PACKAGE@ 13 | dependency package, installs @PACKAGE@ 14 | -------------------------------------------------------------------------------- /rpm/SOURCES/systemd: -------------------------------------------------------------------------------- 1 | # Systemd unit file for jmxtrans 2 | # 3 | [Unit] 4 | Description=JMX Transformer - more than meets the eye 5 | After=syslog.target network.target 6 | 7 | [Service] 8 | Type=forking 9 | PIDFile=/var/run/jmxtrans.pid 10 | EnvironmentFile=/etc/sysconfig/jmxtrans 11 | ExecStart=/etc/init.d/jmxtrans start 12 | ExecStop=/etc/init.d/jmxtrans stop 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/ServerFixtures.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | public final class ServerFixtures { 4 | private ServerFixtures() {} 5 | 6 | public static Server createServerWithOneQuery(String host, String port, String queryObject) { 7 | return Server.builder() 8 | .setHost(host) 9 | .setPort(port) 10 | .addQuery(Query.builder() 11 | .setObj(queryObject) 12 | .build()) 13 | .build(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This work was packaged for Latchkey Enterprises by: 2 | 3 | Jon Stevens on @PROPER_NOW@ 4 | 5 | It was downloaded from http://marinsoftware.com 6 | 7 | Upstream Author(s): 8 | 9 | Jon Stevens 10 | 11 | Copyright: 12 | 13 | Copyright (C) @YEAR@ Jon Stevens 14 | 15 | License: 16 | 17 | OpenSource Software by Jon Stevens 18 | 19 | The Debian packaging is: 20 | 21 | Copyright (C) @YEAR@ Jon Stevens 22 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/exceptions/LifecycleException.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.exceptions; 2 | 3 | public class LifecycleException extends Exception { 4 | 5 | public LifecycleException() { 6 | super(); 7 | } 8 | 9 | public LifecycleException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | 13 | public LifecycleException(String message) { 14 | super(message); 15 | } 16 | 17 | public LifecycleException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /debian/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | case "$1" in 6 | install) 7 | if ! id jmxtrans > /dev/null 2>&1 ; then 8 | adduser --system --shell /bin/bash --home /home/jmxtrans --disabled-login --disabled-password --group jmxtrans 9 | fi 10 | ;; 11 | upgrade|abort-upgrade) 12 | ;; 13 | *) 14 | echo "preinst called with unknown argument \`$1'" >&2 15 | exit 1 16 | ;; 17 | esac 18 | 19 | # dh_installdeb will replace this with shell code automatically 20 | # generated by other debhelper scripts. 21 | 22 | #DEBHELPER# 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /memorypool.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers" : [ { 3 | "port" : "1099", 4 | "host" : "w2", 5 | "queries" : [ { 6 | "obj" : "java.lang:type=MemoryPool,name=*", 7 | "outputWriters" : [ { 8 | "@class" : "com.googlecode.jmxtrans.model.output.RRDToolWriter", 9 | "settings" : { 10 | "templateFile" : "memorypool-rrd-template.xml", 11 | "outputFile" : "target/memorypool.rrd", 12 | "binaryPath" : "/opt/local/bin", 13 | "typeNames" : ["name"], 14 | "debug" : true, 15 | "generate" : true 16 | } 17 | } ] 18 | } ] 19 | } ] 20 | } -------------------------------------------------------------------------------- /heapmemory.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers" : [ { 3 | "port" : "1099", 4 | "host" : "w2", 5 | "queries" : [ { 6 | "obj" : "java.lang:type=Memory", 7 | "attr" : [ "HeapMemoryUsage", "NonHeapMemoryUsage" ], 8 | "outputWriters" : [ { 9 | "@class" : "com.googlecode.jmxtrans.model.output.RRDToolWriter", 10 | "settings" : { 11 | "templateFile" : "heapmemory-rrd-template.xml", 12 | "outputFile" : "target/heap.rrd", 13 | "binaryPath" : "/opt/local/bin", 14 | "debug" : true, 15 | "generate" : true 16 | } 17 | } ] 18 | } ] 19 | } ] 20 | } -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/monitoring/ManagedGenericKeyedObjectPoolMBean.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.monitoring; 2 | 3 | /** 4 | * Managed attributes and operations of a {@link org.apache.commons.pool.impl.GenericKeyedObjectPool}. 5 | */ 6 | public interface ManagedGenericKeyedObjectPoolMBean { 7 | 8 | /** 9 | * Gets the max active. 10 | * 11 | * @return the max active 12 | */ 13 | int getMaxActive(); 14 | 15 | int getMaxIdle(); 16 | 17 | long getMaxWait(); 18 | 19 | int getMinIdle(); 20 | 21 | int getNumActive(); 22 | 23 | int getNumIdle(); 24 | 25 | void setMaxActive(int maxActive); 26 | 27 | void setMaxIdle(int maxIdle); 28 | 29 | void setMinIdle(int maxIdle); 30 | 31 | void setMaxWait(long maxWait); 32 | } 33 | -------------------------------------------------------------------------------- /rpm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# = 0 ]; then 4 | echo "Usage: build.sh jmxtrans-xxx.zip [VERSION] [RELEASE]" 5 | exit 1 6 | fi 7 | 8 | # Copy source 9 | cp $1 SOURCES 10 | 11 | SOURCE=`basename $1` 12 | 13 | if [ $# -ge 2 ]; then 14 | VERSION=$2 15 | else 16 | VERSION=`echo $SOURCE | cut -d '-' -f2 | cut -d '.' -f1` 17 | fi 18 | 19 | if [ $# -ge 3 ]; then 20 | RELEASE=$3 21 | else 22 | RELEASE="0" 23 | fi 24 | 25 | echo Version to package is $VERSION, release $RELEASE 26 | 27 | # prepare fresh directories 28 | rm -rf BUILD RPMS SRPMS TEMP 29 | mkdir -p BUILD RPMS SRPMS TEMP 30 | 31 | # Build using rpmbuild 32 | rpmbuild -ba --define="_topdir $PWD" --define="_tmppath $PWD/TEMP" --define="VERSION $VERSION" --define="RELEASE $RELEASE" --define="JMXTRANS_SOURCE $SOURCE" SPECS/jmxtrans.spec 33 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/jmx/ProcessServerThread.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.jmx; 2 | 3 | import com.googlecode.jmxtrans.model.Server; 4 | 5 | import javax.management.remote.JMXConnector; 6 | 7 | /** 8 | * Executes either a getAttribute or getAttributes query. 9 | */ 10 | public class ProcessServerThread implements Runnable { 11 | private final Server server; 12 | private final JMXConnector conn; 13 | private final JmxUtils jmxUtils; 14 | 15 | public ProcessServerThread(Server server, JMXConnector conn, JmxUtils jmxUtils) { 16 | this.server = server; 17 | this.conn = conn; 18 | this.jmxUtils = jmxUtils; 19 | } 20 | 21 | public void run() { 22 | try { 23 | jmxUtils.processServer(this.server, this.conn); 24 | } catch (Exception e) { 25 | throw new RuntimeException(e); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/guice/GuiceJobFactory.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.guice; 2 | 3 | import com.google.inject.Injector; 4 | import org.quartz.Job; 5 | import org.quartz.JobDetail; 6 | import org.quartz.SchedulerException; 7 | import org.quartz.spi.JobFactory; 8 | import org.quartz.spi.TriggerFiredBundle; 9 | 10 | import javax.inject.Inject; 11 | 12 | public class GuiceJobFactory implements JobFactory { 13 | 14 | private final Injector injector; 15 | 16 | @Inject 17 | public GuiceJobFactory(Injector injector) { 18 | this.injector = injector; 19 | } 20 | 21 | @Override 22 | public Job newJob(TriggerFiredBundle bundle) throws SchedulerException { 23 | JobDetail jobDetail = bundle.getJobDetail(); 24 | Class jobClass = jobDetail.getJobClass(); 25 | return injector.getInstance(jobClass); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/etc/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/util/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.datatype.guava.GuavaModule; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | import com.googlecode.jmxtrans.model.JmxProcess; 10 | 11 | public final class JsonUtils { 12 | 13 | private JsonUtils() {} 14 | 15 | /** 16 | * Uses jackson to load json configuration from a File into a full object 17 | * tree representation of that json. 18 | */ 19 | public static JmxProcess getJmxProcess(File file) throws IOException { 20 | ObjectMapper mapper = new ObjectMapper(); 21 | mapper.registerModule(new GuavaModule()); 22 | JmxProcess jmx = mapper.readValue(file, JmxProcess.class); 23 | jmx.setName(file.getName()); 24 | return jmx; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/activemq/queues-graphite.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers" : [ { 3 | "port" : "1099", 4 | "host" : "localhost", 5 | "queries" : [ { 6 | "obj" : "org.apache.activemq:BrokerName=localhost,Destination=*,Type=Queue", 7 | "attr" : [ 8 | "QueueSize", 9 | "MaxEnqueueTime", 10 | "MinEnqueueTime", 11 | "AverageEnqueueTime", 12 | "InFlightCount", 13 | "ConsumerCount", 14 | "ProducerCount", 15 | "DispatchCount", 16 | "DequeueCount", 17 | "EnqueueCount", 18 | "Subscriptions" 19 | ], 20 | "typeNames" : ["Destination"], 21 | "resultAlias" : "ActiveMQ.Queue", 22 | 23 | "outputWriters" : [ { 24 | "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter", 25 | "settings" : { 26 | "port" : 2003, 27 | "host" : "192.168.1.88" 28 | } 29 | } ] 30 | } ] 31 | } ] 32 | } -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/jobs/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans.jobs (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans.jobs

12 |
13 |

Classes

14 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /example.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers" : [ { 3 | "port" : "1099", 4 | "host" : "w2", 5 | "queries" : [ { 6 | "outputWriters" : [ { 7 | "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter", 8 | "settings" : { 9 | } 10 | } ], 11 | "obj" : "java.lang:type=Memory", 12 | "attr" : [ "HeapMemoryUsage", "NonHeapMemoryUsage" ] 13 | }, { 14 | "outputWriters" : [ { 15 | "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter", 16 | "settings" : { 17 | } 18 | } ], 19 | "obj" : "java.lang:name=CMS Old Gen,type=MemoryPool", 20 | "attr" : [ "Usage" ] 21 | }, { 22 | "outputWriters" : [ { 23 | "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter", 24 | "settings" : { 25 | } 26 | } ], 27 | "obj" : "java.lang:name=ConcurrentMarkSweep,type=GarbageCollector", 28 | "attr" : [ "LastGcInfo" ] 29 | } ], 30 | "numQueryThreads" : 2 31 | } ] 32 | } 33 | -------------------------------------------------------------------------------- /test/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers" : [ { 3 | "port" : "1099", 4 | "host" : "w2", 5 | "queries" : [ { 6 | "outputWriters" : [ { 7 | "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter", 8 | "settings" : { 9 | } 10 | } ], 11 | "obj" : "java.lang:type=Memory", 12 | "attr" : [ "HeapMemoryUsage", "NonHeapMemoryUsage" ] 13 | }, { 14 | "outputWriters" : [ { 15 | "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter", 16 | "settings" : { 17 | } 18 | } ], 19 | "obj" : "java.lang:name=CMS Old Gen,type=MemoryPool", 20 | "attr" : [ "Usage" ] 21 | }, { 22 | "outputWriters" : [ { 23 | "@class" : "com.googlecode.jmxtrans.model.output.StdOutWriter", 24 | "settings" : { 25 | } 26 | } ], 27 | "obj" : "java.lang:name=ConcurrentMarkSweep,type=GarbageCollector", 28 | "attr" : [ "LastGcInfo" ] 29 | } ], 30 | "numQueryThreads" : 2 31 | } ] 32 | } -------------------------------------------------------------------------------- /rrd-template-example.xml: -------------------------------------------------------------------------------- 1 | 2 | ${database} 3 | 4 | 1000123456 5 | 6 | 300 7 | 8 | 9 | input 10 | COUNTER 11 | 300 12 | 0 13 | U 14 | 15 | 16 | temperature 17 | GAUGE 18 | 400 19 | U 20 | 1000 21 | 22 | 23 | 24 | AVERAGE 25 | 0.5 26 | 1 27 | 600 28 | 29 | 30 | MAX 31 | 0.6 32 | 6 33 | 7000 34 | 35 | -------------------------------------------------------------------------------- /samples/activemq/queues.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers":[ 3 | { 4 | "port":"1099", 5 | "host":"localhost", 6 | "queries":[ 7 | { 8 | "obj":"org.apache.activemq:BrokerName=localhost,Destination=*,Type=Queue", 9 | "attr":[ 10 | "QueueSize", 11 | "MaxEnqueueTime", 12 | "MinEnqueueTime", 13 | "AverageEnqueueTime", 14 | "InFlightCount", 15 | "ConsumerCount", 16 | "ProducerCount", 17 | "DispatchCount", 18 | "DequeueCount", 19 | "EnqueueCount", 20 | "Subscriptions" 21 | ], 22 | "typeNames" : ["Destination"], 23 | "resultAlias" : "ActiveMQ.Queue", 24 | "outputWriters":[ 25 | { 26 | "@class":"com.googlecode.jmxtrans.model.output.KeyOutWriter", 27 | "settings":{ 28 | "outputFile" : "logs/output.txt" 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /DEVELOPERS.txt: -------------------------------------------------------------------------------- 1 | How to do a release (must be on an Ubuntu machine): 2 | 3 | Run these commands on a vm: 4 | echo "sun-java6-bin shared/accepted-sun-dlj-v1-1 boolean true" | debconf-set-selections 5 | echo "deb http://archive.canonical.com/ubuntu lucid partner" > /etc/apt/sources.list.d/partner.list 6 | echo "deb-src http://archive.canonical.com/ubuntu lucid partner" >> /etc/apt/sources.list.d/partner.list 7 | aptitude update 8 | aptitude install build-essential devscripts debhelper sun-java6-jdk ant1.8 ntp ssh-server 9 | 10 | 11 | #1. Create a file called build.credentials.properties in the top level project directory. 12 | 13 | #2. Add two properties (and fill them in with your google code u/p): 14 | gc.username= 15 | gc.password= 16 | 17 | #3. Make changes to the code and commit them. 18 | 19 | #4. svn up; ant debian; ant upload 20 | 21 | #5. Now, commit the javadoc directory. 22 | 23 | #6. Go to http://code.google.com/p/jmxtrans/downloads/list 24 | 25 | #7. Click on Summary for the previous version. 26 | 27 | #8. Change Label from Featured to Deprecated. 28 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/naming/ClassAttributeNamingStrategy.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.naming; 2 | 3 | import com.googlecode.jmxtrans.model.NamingStrategy; 4 | import com.googlecode.jmxtrans.model.Result; 5 | 6 | /** 7 | * Strategy for naming metrics, tags, and the like given a result. 8 | */ 9 | public class ClassAttributeNamingStrategy implements NamingStrategy { 10 | protected String delimiter = "."; 11 | 12 | public void setDelimiter(String delim) { 13 | this.delimiter = delim; 14 | } 15 | 16 | public String getDelimiter() { 17 | return this.delimiter; 18 | } 19 | 20 | @Override 21 | public String formatName(Result result) { 22 | StringBuilder formatted = new StringBuilder(); 23 | String attName = result.getAttributeName(); 24 | String className = result.getClassNameAlias(); 25 | 26 | if (className == null) 27 | className = result.getClassName(); 28 | 29 | formatted.append(className); 30 | formatted.append(delimiter); 31 | formatted.append(attName); 32 | 33 | return formatted.toString(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # Uncomment this to turn on verbose mode. 3 | export DH_VERBOSE=1 4 | 5 | 6 | clean: 7 | dh_testdir 8 | dh_testroot 9 | # dh_clean 10 | 11 | setup-perms: 12 | chmod -f ugo+x debian/tmp/usr/share/@PACKAGE@/*.sh || true 13 | chmod -f ugo+x debian/tmp/usr/share/@PACKAGE@/tools/*.py || true 14 | 15 | binary: binary-indep 16 | binary-indep: setup-perms 17 | # dh_prep 18 | dh_testdir 19 | dh_testroot 20 | dh_installdirs 21 | dh_install 22 | dh_installchangelogs 23 | dh_installdocs 24 | # dh_installexamples 25 | # dh_installmenu 26 | dh_installdebconf 27 | # dh_installlogrotate 28 | # dh_installemacsen 29 | # dh_installpam 30 | # dh_installmime 31 | # dh_python 32 | dh_installinit 33 | # dh_installcron 34 | # dh_installinfo 35 | # dh_installman 36 | dh_lintian 37 | # dh_link 38 | # dh_strip 39 | dh_compress 40 | dh_fixperms 41 | # dh_perl 42 | # dh_makeshlibs 43 | dh_installdeb 44 | # dh_shlibdeps 45 | dh_gencontrol 46 | dh_md5sums 47 | dh_builddeb 48 | 49 | %: 50 | dh $@ 51 | 52 | .PHONY: clean binary binary-indep setup-perms 53 | -------------------------------------------------------------------------------- /src/quartz.server.properties: -------------------------------------------------------------------------------- 1 | #============================================================================ 2 | # Configure Server Scheduler Properties 3 | #============================================================================ 4 | 5 | org.quartz.scheduler.instanceName = ServerScheduler 6 | org.quartz.scheduler.instanceId = AUTO 7 | org.quartz.scheduler.skipUpdateCheck = true 8 | org.quartz.scheduler.jmx.export = true 9 | 10 | #============================================================================ 11 | # Configure ThreadPool 12 | #============================================================================ 13 | 14 | org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool 15 | org.quartz.threadPool.threadCount = 10 16 | org.quartz.threadPool.threadPriority = 5 17 | 18 | #============================================================================ 19 | # Configure JobStore 20 | #============================================================================ 21 | 22 | org.quartz.jobStore.misfireThreshold = 60000 23 | org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Jon Scott Stevens 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 4 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 6 | persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 9 | Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 12 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 13 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 14 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans

12 |
13 |

Interfaces

14 | 17 |

Classes

18 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/connections/DatagramSocketFactory.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | import org.apache.commons.pool.BaseKeyedPoolableObjectFactory; 4 | 5 | import java.net.DatagramSocket; 6 | import java.net.SocketAddress; 7 | 8 | /** 9 | * Allows us to pool socket connections. 10 | */ 11 | public class DatagramSocketFactory extends BaseKeyedPoolableObjectFactory { 12 | 13 | /** 14 | * Creates the socket and the writer to go with it. 15 | */ 16 | @Override 17 | public DatagramSocket makeObject(SocketAddress socketAddress) throws Exception { 18 | return new DatagramSocket(socketAddress); 19 | } 20 | 21 | /** 22 | * Closes the socket. 23 | */ 24 | @Override 25 | public void destroyObject(SocketAddress key, DatagramSocket socket) throws Exception { 26 | socket.close(); 27 | } 28 | 29 | /** 30 | * Validates that the socket is good. 31 | */ 32 | @Override 33 | public boolean validateObject(SocketAddress key, DatagramSocket socket) { 34 | return socket.isBound() && !socket.isClosed() && socket.isConnected(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/jmx/ProcessQueryThread.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.jmx; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.management.MBeanServerConnection; 7 | 8 | import com.googlecode.jmxtrans.model.Query; 9 | import com.googlecode.jmxtrans.model.Server; 10 | 11 | /** 12 | * Executes either a getAttribute or getAttributes query. 13 | */ 14 | public class ProcessQueryThread implements Runnable { 15 | 16 | private final Logger log = LoggerFactory.getLogger(getClass()); 17 | 18 | private final MBeanServerConnection mbeanServer; 19 | private final Server server; 20 | private final Query query; 21 | 22 | public ProcessQueryThread(MBeanServerConnection mbeanServer, Server server, Query query) { 23 | this.mbeanServer = mbeanServer; 24 | this.server = server; 25 | this.query = query; 26 | } 27 | 28 | public void run() { 29 | try { 30 | new JmxQueryProcessor().processQuery(this.mbeanServer, this.server, this.query); 31 | } catch (Exception e) { 32 | log.error("Error executing query: " + query, e); 33 | throw new RuntimeException(e); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/output/NumberUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import org.junit.Test; 4 | 5 | import static com.googlecode.jmxtrans.model.output.NumberUtils.isNumeric; 6 | import static java.lang.Boolean.FALSE; 7 | import static org.junit.Assert.assertFalse; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class NumberUtilsTest { 11 | @Test 12 | public void testIsNumeric() { 13 | assertFalse(isNumeric(null)); 14 | assertTrue(isNumeric("")); // this is "true" for historical 15 | // reasons 16 | assertFalse(isNumeric(" ")); 17 | assertTrue(isNumeric("123")); 18 | assertFalse(isNumeric("12 3")); 19 | assertFalse(isNumeric("ab2c")); 20 | assertFalse(isNumeric("12-3")); 21 | assertTrue(isNumeric("12.3")); 22 | assertFalse(isNumeric("12.3.3.3")); 23 | assertTrue(isNumeric(".2")); 24 | assertFalse(isNumeric(".")); 25 | assertFalse(isNumeric("3.")); 26 | assertTrue(isNumeric(1L)); 27 | assertTrue(isNumeric(2)); 28 | assertTrue(isNumeric((Object) "3.2")); 29 | assertFalse(isNumeric((Object) "abc")); 30 | assertFalse(isNumeric(FALSE)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/Graphite.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.googlecode.jmxtrans.model.JmxProcess; 4 | import com.googlecode.jmxtrans.model.Query; 5 | import com.googlecode.jmxtrans.model.Server; 6 | import com.googlecode.jmxtrans.model.output.GraphiteWriter; 7 | import com.googlecode.jmxtrans.util.JsonPrinter; 8 | 9 | /** 10 | * This class hits a Graphite server running on port 2003 and sends the memory 11 | * usage data to it for graphing. 12 | * 13 | * @author jon 14 | */ 15 | public class Graphite { 16 | 17 | private static JsonPrinter printer = new JsonPrinter(System.out); 18 | 19 | public static void main(String[] args) throws Exception { 20 | printer.prettyPrint(new JmxProcess(Server.builder() 21 | .setHost("w2") 22 | .setPort("1099") 23 | .addQuery(Query.builder() 24 | .setObj("java.lang:type=GarbageCollector,name=ConcurrentMarkSweep") 25 | .addOutputWriter(GraphiteWriter.builder() 26 | .setHost("192.168.192.133") 27 | .setPort(2003) 28 | .setDebugEnabled(true) 29 | .setRootPrefix("jon.foo.bar") 30 | .build()) 31 | .build()) 32 | .build())); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/MemoryPool.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | 6 | import java.io.File; 7 | 8 | import com.googlecode.jmxtrans.JmxTransformer; 9 | import com.googlecode.jmxtrans.guice.JmxTransModule; 10 | import com.googlecode.jmxtrans.model.JmxProcess; 11 | import com.googlecode.jmxtrans.util.JsonPrinter; 12 | import com.googlecode.jmxtrans.util.JsonUtils; 13 | 14 | /** 15 | * Shows how to process a file. 16 | * 17 | * @author jon 18 | */ 19 | public class MemoryPool { 20 | 21 | /** 22 | * 23 | */ 24 | public static void main(String[] args) throws Exception { 25 | 26 | JmxProcess process = JsonUtils.getJmxProcess(new File("memorypool.json")); 27 | new JsonPrinter(System.out).print(process); 28 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 29 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 30 | transformer.executeStandalone(process); 31 | 32 | // for (int i = 0; i < 160; i++) { 33 | // JmxUtils.execute(jmx); 34 | // Thread.sleep(1000); 35 | // } 36 | 37 | System.out.println("done!"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/HeapMemory.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | 6 | import java.io.File; 7 | 8 | import com.googlecode.jmxtrans.JmxTransformer; 9 | import com.googlecode.jmxtrans.guice.JmxTransModule; 10 | import com.googlecode.jmxtrans.model.JmxProcess; 11 | import com.googlecode.jmxtrans.util.JsonPrinter; 12 | import com.googlecode.jmxtrans.util.JsonUtils; 13 | 14 | /** 15 | * Shows how to process a file. 16 | * 17 | * @author jon 18 | */ 19 | public class HeapMemory { 20 | 21 | /** 22 | * 23 | */ 24 | public static void main(String[] args) throws Exception { 25 | 26 | JmxProcess process = JsonUtils.getJmxProcess(new File("heapmemory.json")); 27 | new JsonPrinter(System.out).print(process); 28 | 29 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 30 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 31 | transformer.executeStandalone(process); 32 | 33 | // for (int i = 0; i < 160; i++) { 34 | // JmxUtils.execute(jmx); 35 | // Thread.sleep(1000); 36 | // } 37 | 38 | System.out.println("done!"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/monitoring/ManagedObject.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.monitoring; 2 | 3 | import javax.management.MalformedObjectNameException; 4 | import javax.management.ObjectName; 5 | 6 | /** 7 | * The Interface ManagedObject represents a MBean managed object, 8 | * force some ObjectName methods, used on register / unregister 9 | * in the MBeanServer. 10 | * 11 | * @author marcos.lois 12 | */ 13 | public interface ManagedObject { 14 | 15 | /** 16 | * Gets the object name. 17 | * 18 | * @return the object name 19 | * @throws MalformedObjectNameException if the object name is not valid 20 | */ 21 | ObjectName getObjectName() throws MalformedObjectNameException; 22 | 23 | /** 24 | * Sets the object name. 25 | * 26 | * @param objectName the object name 27 | * @throws MalformedObjectNameException if the object name is not valid 28 | */ 29 | void setObjectName(ObjectName objectName) throws MalformedObjectNameException; 30 | 31 | /** 32 | * Sets the object name. 33 | * 34 | * @param objectName the object name 35 | * @throws MalformedObjectNameException if the object name is not valid 36 | */ 37 | void setObjectName(String objectName) throws MalformedObjectNameException; 38 | } 39 | -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/model/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans.model (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans.model

12 |
13 |

Classes

14 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /doc/tools/README.md: -------------------------------------------------------------------------------- 1 | # yaml2jmxtrans.py # 2 | _yaml2jmxtrans.py_ allows you to write _jmxtrans_ query configurations 3 | using a simple [YAML][YAML] format. 4 | 5 | The custom YAML format is more concise through letting you specify 6 | your quieries in one place and the hosts that use that use the queries 7 | in another one ([DRY][DRY] principle). 8 | 9 | YAML format 10 | ---------- 11 | Look at the _jmxtrans-demo.yaml_ file which gives an example of the 12 | format. 13 | 14 | Usage 15 | ---------- 16 | yaml2jmxtrans.py INFILE.yaml 17 | 18 | Generates JSON jmxtrans configuration files, one for each host set 19 | defined in _INFILE.yaml_. 20 | 21 | Dependencies 22 | ---------- 23 | * python 2.6 24 | * [PyYAML][PyYAML] 25 | 26 | Limitations 27 | ---------- 28 | * _yaml2trans.py_ only supports [Graphite][Graphite] as an output 29 | writer as that's what I use. Please file issues if you require 30 | other output writers. 31 | * EXPERIMENTAL: The "outputWriters:" map in the YAML configuration file supports other 32 | output writers. Please file issues if there are problems. 33 | 34 | [YAML]: http://yaml.org/ 35 | [PyYAML]: http://pyyaml.org/ 36 | [DRY]: http://de.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself 37 | [Graphite]: http://graphite.wikidot.com/ 38 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/output/StdOutWriter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.collect.ImmutableList; 6 | import com.googlecode.jmxtrans.model.Query; 7 | import com.googlecode.jmxtrans.model.Result; 8 | import com.googlecode.jmxtrans.model.Server; 9 | import com.googlecode.jmxtrans.model.ValidationException; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * Basic filter good for testing that just outputs the Result objects using 15 | * System.out. 16 | * 17 | * @author jon 18 | */ 19 | public class StdOutWriter extends BaseOutputWriter { 20 | 21 | @JsonCreator 22 | public StdOutWriter( 23 | @JsonProperty("typeNames") ImmutableList typeNames, 24 | @JsonProperty("debug") Boolean debugEnabled, 25 | @JsonProperty("settings") Map settings) { 26 | super(typeNames, debugEnabled, settings); 27 | } 28 | 29 | /** 30 | * nothing to validate 31 | */ 32 | public void validateSetup(Server server, Query query) throws ValidationException { 33 | } 34 | 35 | public void doWrite(Server server, Query query, ImmutableList results) throws Exception { 36 | for (Result r : results) { 37 | System.out.println(r); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/util/JsonPrinter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.fasterxml.jackson.databind.ObjectWriter; 5 | import com.fasterxml.jackson.databind.SerializationFeature; 6 | 7 | import java.io.PrintStream; 8 | 9 | import com.googlecode.jmxtrans.model.JmxProcess; 10 | 11 | public class JsonPrinter { 12 | 13 | private final PrintStream out; 14 | private final ObjectMapper mapper; 15 | private final ObjectWriter prettyPrintingWriter; 16 | 17 | public JsonPrinter(PrintStream out) { 18 | this.out = out; 19 | mapper = new ObjectMapper(); 20 | mapper.getSerializationConfig().without(SerializationFeature.WRITE_NULL_MAP_VALUES); 21 | //mapper.getSerializationConfig().set(SerializationFeature.WRITE_NULL_MAP_VALUES, false); 22 | prettyPrintingWriter = mapper.writerWithDefaultPrettyPrinter(); 23 | } 24 | 25 | /** 26 | * Utility function good for testing things. Prints out the json tree of the 27 | * JmxProcess. 28 | */ 29 | public void print(JmxProcess process) throws Exception { 30 | mapper.writeValue(out, process); 31 | } 32 | 33 | /** 34 | * Utility function good for testing things. Prints out the json tree of the 35 | * JmxProcess. 36 | */ 37 | public void prettyPrint(JmxProcess process) throws Exception { 38 | prettyPrintingWriter.writeValue(out, process); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/connections/JmxConnectionFactory.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | import org.apache.commons.pool.BaseKeyedPoolableObjectFactory; 4 | 5 | import javax.management.remote.JMXConnector; 6 | import javax.management.remote.JMXConnectorFactory; 7 | import java.io.IOException; 8 | 9 | /** 10 | * Allows us to pool connections to remote jmx servers. 11 | */ 12 | public class JmxConnectionFactory extends BaseKeyedPoolableObjectFactory { 13 | 14 | /** 15 | * Creates the connection. 16 | */ 17 | @Override 18 | public JMXConnector makeObject(JMXConnectionParams params) throws Exception { 19 | return JMXConnectorFactory.connect(params.getUrl(), params.getEnvironment()); 20 | } 21 | 22 | /** 23 | * Closes the connection. 24 | */ 25 | @Override 26 | public void destroyObject(JMXConnectionParams params, JMXConnector connector) throws Exception { 27 | connector.close(); 28 | } 29 | 30 | /** 31 | * Validates that the connection is good. 32 | */ 33 | @Override 34 | public boolean validateObject(JMXConnectionParams params, JMXConnector connector) { 35 | boolean result = false; 36 | try { 37 | connector.getConnectionId(); 38 | connector.getMBeanServerConnection().getMBeanCount(); 39 | result = true; 40 | } catch (IOException ex) { 41 | // ignored 42 | } 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/naming/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.naming; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | public final class StringUtils { 6 | private static final Pattern DOT_SLASH_UNDERSCORE_PAT = Pattern.compile("[./]"); 7 | private static final Pattern SLASH_UNDERSCORE_PAT = Pattern.compile("/", Pattern.LITERAL); 8 | private static final Pattern SPACE_PAT = Pattern.compile("[ \"']+"); 9 | 10 | private StringUtils() {} 11 | 12 | /** 13 | * Replaces all . and / with _ and removes all spaces and double/single quotes. 14 | * 15 | * @param name the name 16 | * @return the string 17 | */ 18 | public static String cleanupStr(String name) { 19 | return cleanupStr(name, false); 20 | } 21 | 22 | /** 23 | * Replaces all . and / with _ and removes all spaces and double/single quotes. 24 | * 25 | * @param name the name 26 | * @param allowDottedKeys whether we remove the dots or not. 27 | * @return 28 | */ 29 | public static String cleanupStr(String name, boolean allowDottedKeys) { 30 | if (name == null) { 31 | return null; 32 | } 33 | Pattern pattern; 34 | if (!allowDottedKeys) { 35 | pattern = DOT_SLASH_UNDERSCORE_PAT; 36 | } else { 37 | pattern = SLASH_UNDERSCORE_PAT; 38 | } 39 | String clean = pattern.matcher(name).replaceAll("_"); 40 | clean = SPACE_PAT.matcher(clean).replaceAll(""); 41 | return clean; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/EqualsTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans; 2 | 3 | import org.junit.Test; 4 | 5 | import com.googlecode.jmxtrans.model.Query; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | 9 | public class EqualsTests { 10 | 11 | @Test 12 | public void testQuery() { 13 | Query q1 = Query.builder() 14 | .setObj("obj") 15 | .addKeys("key1", "key2") 16 | .addAttr("foo", "bar") 17 | .setResultAlias("alias") 18 | .build(); 19 | 20 | // same as q1 21 | Query q2 = Query.builder() 22 | .setObj("obj") 23 | .addKeys("key1", "key2") 24 | .addAttr("foo", "bar") 25 | .setResultAlias("alias") 26 | .build(); 27 | 28 | // different 29 | Query q3 = Query.builder() 30 | .setObj("obj3") 31 | .addKeys("key1", "key2") 32 | .addAttr("foo", "bar") 33 | .setResultAlias("alias") 34 | .build(); 35 | 36 | assertThat(q1).isEqualTo(q2); 37 | assertThat(q1).isNotEqualTo(q3); 38 | } 39 | 40 | @Test 41 | public void testQuery2() { 42 | Query q1 = Query.builder() 43 | .setObj("*") 44 | .addKeys("key1", "key2") 45 | .addAttr("foo", "bar") 46 | .setResultAlias("alias") 47 | .build(); 48 | 49 | // not same as q1 50 | Query q2 = Query.builder() 51 | .setObj("obj") 52 | .addKeys("key1", "key2") 53 | .addAttr("foo", "bar") 54 | .setResultAlias("alias") 55 | .build(); 56 | 57 | assertThat(q1).isNotEqualTo(q2); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/monitoring/ManagedJmxTransformerProcessMXBean.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.monitoring; 2 | 3 | import com.googlecode.jmxtrans.exceptions.LifecycleException; 4 | 5 | /** 6 | * The Interface ManagedJmxTransformerProcessMBean. 7 | */ 8 | public interface ManagedJmxTransformerProcessMXBean { 9 | 10 | /** 11 | * Start the JmxProcess. 12 | * 13 | * @throws LifecycleException the lifecycle exception 14 | */ 15 | void start() throws LifecycleException; 16 | 17 | /** 18 | * Stop the JmxProcess. 19 | * 20 | * @throws LifecycleException the lifecycle exception 21 | */ 22 | void stop() throws LifecycleException; 23 | 24 | /** 25 | * Gets the quart properties file. 26 | * 27 | * @return the quart properties file 28 | */ 29 | String getQuartPropertiesFile(); 30 | 31 | /** 32 | * Sets the quart properties file. 33 | * 34 | * @param quartPropertiesFile the quart properties file 35 | */ 36 | void setQuartPropertiesFile(String quartPropertiesFile); 37 | 38 | /** 39 | * Gets the run period. 40 | * 41 | * @return the run period 42 | */ 43 | int getRunPeriod(); 44 | 45 | /** 46 | * Sets the run period. 47 | * 48 | * @param runPeriod the run period 49 | */ 50 | void setRunPeriod(int runPeriod); 51 | 52 | /** 53 | * Sets the json dir or file. 54 | * 55 | * @param jsonDirOrFile the json dir or file 56 | */ 57 | void setJsonDirOrFile(String jsonDirOrFile); 58 | 59 | /** 60 | * Gets the json dir or file. 61 | * 62 | * @return the json dir or file 63 | */ 64 | String getJsonDirOrFile(); 65 | } 66 | -------------------------------------------------------------------------------- /javadoc/overview-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Overview List (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 | 12 | 24 |

 

25 | 26 | 27 | -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/jmx/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans.jmx (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans.jmx

12 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/util/JsonUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import com.google.common.base.Optional; 4 | import com.google.common.base.Predicate; 5 | import org.junit.Test; 6 | 7 | import javax.annotation.Nullable; 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.net.URISyntaxException; 11 | 12 | import com.googlecode.jmxtrans.model.JmxProcess; 13 | import com.googlecode.jmxtrans.model.Query; 14 | import com.googlecode.jmxtrans.model.Server; 15 | 16 | import static com.google.common.collect.FluentIterable.from; 17 | import static org.assertj.core.api.Assertions.assertThat; 18 | 19 | public class JsonUtilsTest { 20 | 21 | @Test 22 | public void loadingFromFile() throws URISyntaxException, IOException { 23 | File input = new File(JsonUtilsTest.class.getResource("/example.json").toURI()); 24 | 25 | JmxProcess process = JsonUtils.getJmxProcess(input); 26 | assertThat(process.getName()).isEqualTo("example.json"); 27 | 28 | Server server = process.getServers().get(0); 29 | assertThat(server.getNumQueryThreads()).isEqualTo(2); 30 | 31 | Optional queryOptional = from(server.getQueries()).firstMatch(new ByObj("java.lang:type=Memory")); 32 | assertThat(queryOptional.isPresent()).isTrue(); 33 | assertThat(queryOptional.get().getAttr().get(0)).isEqualTo("HeapMemoryUsage"); 34 | } 35 | 36 | private static class ByObj implements Predicate { 37 | 38 | private final String obj; 39 | 40 | private ByObj(String obj) { 41 | this.obj = obj; 42 | } 43 | 44 | @Override 45 | public boolean apply(@Nullable Query query) { 46 | return query.getObj().equals(this.obj); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/connections/JMXConnectionParams.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import org.apache.commons.lang.builder.EqualsBuilder; 5 | import org.apache.commons.lang.builder.HashCodeBuilder; 6 | 7 | import javax.management.remote.JMXServiceURL; 8 | 9 | /* 10 | * TODO This class has been extracted as a simple holder to break the 11 | * dependency between the JMXConnectionFactory and the Server. There is 12 | * probably a cleaner way to do this, but this will come later. 13 | */ 14 | public class JMXConnectionParams { 15 | private final JMXServiceURL url; 16 | private final ImmutableMap environment; 17 | 18 | public JMXConnectionParams(JMXServiceURL url, ImmutableMap environment) { 19 | this.url = url; 20 | this.environment = environment; 21 | } 22 | 23 | public JMXServiceURL getUrl() { 24 | return url; 25 | } 26 | 27 | public ImmutableMap getEnvironment() { 28 | return environment; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | if (o == null) { 34 | return false; 35 | } 36 | if (o == this) { 37 | return true; 38 | } 39 | if (o.getClass() != this.getClass()) { 40 | return false; 41 | } 42 | 43 | if (!(o instanceof JMXConnectionParams)) { 44 | return false; 45 | } 46 | 47 | JMXConnectionParams that = (JMXConnectionParams) o; 48 | 49 | return new EqualsBuilder() 50 | .append(this.environment, that.environment) 51 | .append(this.url, that.url) 52 | .isEquals(); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return new HashCodeBuilder(135, 211) 58 | .append(this.environment) 59 | .append(this.url) 60 | .toHashCode(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 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 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/OutputWriter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.google.common.collect.ImmutableList; 6 | 7 | import java.util.Map; 8 | 9 | import com.googlecode.jmxtrans.exceptions.LifecycleException; 10 | 11 | import static com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_NULL; 12 | 13 | /** 14 | * Interface which defines a writer for taking jmx data and writing it out in 15 | * whatever format you want. 16 | * 17 | * Note that this class uses a feature of Jackson to serialize anything that 18 | * implements this as a "@class". That way, when Jackson deserializes 19 | * implementations of this interface, it is done with new objects that implement 20 | * this interface. 21 | * 22 | * @author jon 23 | */ 24 | @JsonSerialize(include = NON_NULL) 25 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") 26 | public interface OutputWriter { 27 | 28 | void start() throws LifecycleException; 29 | 30 | void stop() throws LifecycleException; 31 | 32 | void doWrite(Server server, Query query, ImmutableList results) throws Exception; 33 | 34 | /** 35 | * Settings allow you to configure your Writers with whatever they might 36 | * need. 37 | */ 38 | Map getSettings(); 39 | 40 | /** 41 | * Settings allow you to configure your Writers with whatever they might 42 | * need. 43 | */ 44 | void setSettings(Map settings); 45 | 46 | /** 47 | * This is run when the object is instantiated. You want to get the settings 48 | * and validate them. 49 | */ 50 | void validateSetup(Server server, Query query) throws ValidationException; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/output/NumberUtils.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | import java.util.regex.Pattern; 6 | 7 | public final class NumberUtils { 8 | private static final Pattern IS_NUMERIC_PAT = Pattern.compile("\\d*(?:[.]\\d+)?"); 9 | 10 | private NumberUtils() {} 11 | 12 | /** 13 | * Useful for figuring out if an Object is a number. 14 | */ 15 | public static boolean isNumeric(Object value) { 16 | return ((value instanceof Number) || ((value instanceof String) && isNumeric((String) value))); 17 | } 18 | 19 | /** 20 | *

21 | * Checks if the String contains only unicode digits. A decimal point is a 22 | * digit and returns true. 23 | *

24 | *

25 | *

26 | * null will return false. An empty String ("") 27 | * will return true. 28 | *

29 | *

30 | *

31 | 	 * StringUtils.isNumeric(null)   = false
32 | 	 * StringUtils.isNumeric("")     = true
33 | 	 * StringUtils.isNumeric("  ")   = false
34 | 	 * StringUtils.isNumeric("123")  = true
35 | 	 * StringUtils.isNumeric("12 3") = false
36 | 	 * StringUtils.isNumeric("ab2c") = false
37 | 	 * StringUtils.isNumeric("12-3") = false
38 | 	 * StringUtils.isNumeric("12.3") = true
39 | 	 * 
40 | * 41 | * @param str the String to check, may be null 42 | * @return true if only contains digits, and is non-null 43 | * @deprecated There is already a dependency in this project on Apache 44 | * common-lang, so you should probably use {@see org.apache.commons.lang.math.NumberUtils}. 45 | */ 46 | @Deprecated 47 | public static boolean isNumeric(String str) { 48 | if (StringUtils.isEmpty(str)) { 49 | return str != null; // Null = false, empty = true 50 | } 51 | return IS_NUMERIC_PAT.matcher(str).matches(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/connections/SocketFactoryTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | import com.google.common.io.Closer; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | import java.net.InetSocketAddress; 10 | import java.net.Socket; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | public class SocketFactoryTests { 15 | 16 | private TCPEchoServer echoServer; 17 | private InetSocketAddress echoServerAddress; 18 | 19 | @Before 20 | public void startEchoServer() { 21 | echoServer = new TCPEchoServer(); 22 | echoServer.start(); 23 | echoServerAddress = echoServer.getLocalSocketAddress(); 24 | } 25 | 26 | @Test 27 | public void createdSocketIsValid() throws IOException { 28 | Closer closer = Closer.create(); 29 | try { 30 | SocketFactory socketFactory = new SocketFactory(); 31 | Socket socket = closer.register(socketFactory.makeObject(echoServerAddress)); 32 | assertThat(socketFactory.validateObject(echoServerAddress, socket)).isTrue(); 33 | } catch (Throwable t) { 34 | throw closer.rethrow(t); 35 | } finally { 36 | closer.close(); 37 | } 38 | } 39 | 40 | @Test 41 | public void nullSocketIsInvalid() { 42 | assertThat(new SocketFactory().validateObject(echoServerAddress, null)).isFalse(); 43 | } 44 | 45 | @Test 46 | public void closedSocketIsInvalid() throws IOException { 47 | Closer closer = Closer.create(); 48 | try { 49 | SocketFactory socketFactory = new SocketFactory(); 50 | Socket socket = closer.register(socketFactory.makeObject(echoServerAddress)); 51 | socket.close(); 52 | assertThat(socketFactory.validateObject(echoServerAddress, socket)).isFalse(); 53 | } catch (Throwable t) { 54 | throw closer.rethrow(t); 55 | } finally { 56 | closer.close(); 57 | } 58 | } 59 | 60 | @After 61 | public void stopEchoServer() { 62 | echoServer.stop(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/Ehcache.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.googlecode.jmxtrans.JmxTransformer; 6 | import com.googlecode.jmxtrans.guice.JmxTransModule; 7 | import com.googlecode.jmxtrans.model.JmxProcess; 8 | import com.googlecode.jmxtrans.model.Query; 9 | import com.googlecode.jmxtrans.model.Server; 10 | import com.googlecode.jmxtrans.model.output.GraphiteWriter; 11 | import com.googlecode.jmxtrans.util.JsonPrinter; 12 | 13 | /** 14 | * This example shows how to query ehcache for its statistics information. 15 | * 16 | * @author jon 17 | */ 18 | public class Ehcache { 19 | 20 | private static final String GW_HOST = "192.168.192.133"; 21 | private static final JsonPrinter printer = new JsonPrinter(System.out); 22 | 23 | /** */ 24 | public static void main(String[] args) throws Exception { 25 | 26 | JmxProcess process = new JmxProcess(Server.builder() 27 | .setHost("w2") 28 | .setPort("1099") 29 | .setAlias("w2_ehcache_1099") 30 | .addQuery(Query.builder() 31 | .setObj("net.sf.ehcache:CacheManager=net.sf.ehcache.CacheManager@*,name=*,type=CacheStatistics") 32 | .addAttr("CacheHits") 33 | .addAttr("InMemoryHits") 34 | .addAttr("OnDiskHits") 35 | .addAttr("CacheMisses") 36 | .addAttr("ObjectCount") 37 | .addAttr("MemoryStoreObjectCount") 38 | .addAttr("DiskStoreObjectCount") 39 | .addOutputWriter(GraphiteWriter.builder() 40 | .addTypeName("name") 41 | .setDebugEnabled(true) 42 | .setHost(GW_HOST) 43 | .setPort(2003) 44 | .build()) 45 | .build()) 46 | .build()); 47 | 48 | printer.prettyPrint(process); 49 | 50 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 51 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 52 | 53 | transformer.executeStandalone(process); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/JmxProcess.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_NULL; 10 | 11 | /** 12 | * This is the container for a list of Servers. 13 | * 14 | * @author jon 15 | */ 16 | @JsonSerialize(include = NON_NULL) 17 | public class JmxProcess { 18 | 19 | private String name; 20 | private List servers = new ArrayList(); 21 | private Integer numMultiThreadedServers; 22 | 23 | public JmxProcess() { 24 | } 25 | 26 | public JmxProcess(Server server) { 27 | this.servers.add(server); 28 | } 29 | 30 | public JmxProcess(List servers) { 31 | this.setServers(servers); 32 | } 33 | 34 | public void setServers(List servers) { 35 | this.servers = servers; 36 | } 37 | 38 | public List getServers() { 39 | return servers; 40 | } 41 | 42 | @JsonIgnore 43 | public boolean isServersMultiThreaded() { 44 | return this.numMultiThreadedServers != null && this.numMultiThreadedServers > 0; 45 | } 46 | 47 | /** 48 | * Set this if you want each JmxProcess to run in its own thread up to the 49 | * count you set. So, if you set this to 3 and you have 6 JmxProcesses, 50 | * it'll start up a max of 3 threads and then block until a thread becomes 51 | * available. It'll then start another thread up to fill in the blanks. 52 | */ 53 | public void setNumMultiThreadedServers(Integer numMultiThreadedServers) { 54 | this.numMultiThreadedServers = numMultiThreadedServers; 55 | } 56 | 57 | public Integer getNumMultiThreadedServers() { 58 | return numMultiThreadedServers; 59 | } 60 | 61 | public void setName(String name) { 62 | this.name = name; 63 | } 64 | 65 | public String getName() { 66 | return name; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/naming/StringUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.naming; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class StringUtilsTest { 8 | 9 | @Test 10 | public void testCleanupStr() { 11 | assertEquals("addfber1241qdw!èé$", StringUtils.cleanupStr("addfber1241qdw!èé$")); 12 | assertEquals("abcd_abcd", StringUtils.cleanupStr("abcd.abcd")); 13 | assertEquals("abcd_abcd_", StringUtils.cleanupStr("abcd.abcd.")); 14 | assertEquals("_abcd_abcd", StringUtils.cleanupStr(".abcd_abcd")); 15 | assertEquals("abcd_abcd", StringUtils.cleanupStr("abcd/abcd")); 16 | assertEquals("abcd_abcd_", StringUtils.cleanupStr("abcd/abcd/")); 17 | assertEquals("_abcd_abcd", StringUtils.cleanupStr("/abcd_abcd")); 18 | assertEquals("abcd_abcd", StringUtils.cleanupStr("abcd'_abcd'")); 19 | assertEquals("_abcd_abcd", StringUtils.cleanupStr("/abcd\"_abcd\"")); 20 | assertEquals("_abcd_abcd", StringUtils.cleanupStr("/ab cd_abcd")); 21 | assertEquals(null, StringUtils.cleanupStr(null)); 22 | assertEquals("", StringUtils.cleanupStr("")); 23 | } 24 | 25 | @Test 26 | public void testCleanupStrDottedKeysKept() { 27 | assertEquals("addfber1241qdw!èé$", StringUtils.cleanupStr("addfber1241qdw!èé$", true)); 28 | assertEquals("abcd.abcd", StringUtils.cleanupStr("abcd.abcd", true)); 29 | assertEquals("abcd.abcd.", StringUtils.cleanupStr("abcd.abcd.", true)); 30 | assertEquals(".abcd_abcd", StringUtils.cleanupStr(".abcd_abcd", true)); 31 | assertEquals("abcd_abcd", StringUtils.cleanupStr("abcd/abcd", true)); 32 | assertEquals("abcd_abcd_", StringUtils.cleanupStr("abcd/abcd/", true)); 33 | assertEquals("_abcd_abcd", StringUtils.cleanupStr("/abcd_abcd", true)); 34 | assertEquals("abcd_abcd", StringUtils.cleanupStr("abcd'_abcd'", true)); 35 | assertEquals("_abcd_abcd", StringUtils.cleanupStr("/abcd\"_abcd\"", true)); 36 | assertEquals("_abcd_abcd", StringUtils.cleanupStr("/ab cd_abcd", true)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/Result.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 4 | import com.google.common.collect.ImmutableMap; 5 | 6 | import javax.annotation.concurrent.Immutable; 7 | import javax.annotation.concurrent.ThreadSafe; 8 | import java.util.Map; 9 | 10 | import static com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion.NON_NULL; 11 | 12 | /** 13 | * Represents the result of a query. 14 | * 15 | * @author jon 16 | */ 17 | @JsonSerialize(include = NON_NULL) 18 | @ThreadSafe 19 | @Immutable 20 | public class Result { 21 | private final String attributeName; 22 | private final String className; 23 | private final String typeName; 24 | private final ImmutableMap values; 25 | private final long epoch; 26 | private final String classNameAlias; 27 | 28 | public Result(String attributeName, String className, String classNameAlias, String typeName, Map values) { 29 | this.className = className; 30 | this.typeName = typeName; 31 | this.values = ImmutableMap.copyOf(values); 32 | this.epoch = System.currentTimeMillis(); 33 | this.attributeName = attributeName; 34 | this.classNameAlias = classNameAlias; 35 | } 36 | 37 | public String getClassName() { 38 | return className; 39 | } 40 | 41 | /** 42 | * Specified as part of the query. 43 | */ 44 | public String getClassNameAlias() { 45 | return classNameAlias; 46 | } 47 | 48 | public String getTypeName() { 49 | return typeName; 50 | } 51 | 52 | public ImmutableMap getValues() { 53 | return values; 54 | } 55 | 56 | public String getAttributeName() { 57 | return attributeName; 58 | } 59 | 60 | public long getEpoch() { 61 | return this.epoch; 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return "Result [attributeName=" + attributeName + ", className=" + className + ", typeName=" + typeName + ", values=" + values + ", epoch=" 67 | + epoch + "]"; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/Ganglia.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.googlecode.jmxtrans.JmxTransformer; 6 | import com.googlecode.jmxtrans.guice.JmxTransModule; 7 | import com.googlecode.jmxtrans.model.JmxProcess; 8 | import com.googlecode.jmxtrans.model.Query; 9 | import com.googlecode.jmxtrans.model.Server; 10 | import com.googlecode.jmxtrans.model.output.GangliaWriter; 11 | import com.googlecode.jmxtrans.util.JsonPrinter; 12 | 13 | /** 14 | * This class hits a Graphite server running on port 2003 and sends the memory 15 | * usage data to it for graphing. 16 | * 17 | * @author jon 18 | */ 19 | public class Ganglia { 20 | 21 | private static final JsonPrinter printer = new JsonPrinter(System.out); 22 | 23 | public static void main(String[] args) throws Exception { 24 | printer.prettyPrint(new JmxProcess(Server.builder() 25 | .setHost("w2") 26 | .setPort("1099") 27 | .setAlias("fooalias") 28 | .addQuery(Query.builder() 29 | .setObj("java.lang:type=GarbageCollector,name=ConcurrentMarkSweep") 30 | .addOutputWriter(GangliaWriter.builder() 31 | .setHost("10.0.3.16") 32 | .setPort(8649) 33 | .setDebugEnabled(true) 34 | .setGroupName("memory") 35 | .build()) 36 | .build()) 37 | .build())); 38 | 39 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 40 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 41 | transformer.executeStandalone(new JmxProcess(Server.builder() 42 | .setHost("w2") 43 | .setPort("1099") 44 | .setAlias("fooalias") 45 | .addQuery(Query.builder() 46 | .setObj("java.lang:type=GarbageCollector,name=ConcurrentMarkSweep") 47 | .addOutputWriter(GangliaWriter.builder() 48 | .setHost("10.0.3.16") 49 | .setPort(8649) 50 | .setDebugEnabled(true) 51 | .setGroupName("memory") 52 | .build()) 53 | .build()) 54 | .build())); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /debian/init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # /etc/init.d/@PACKAGE -- startup script for @PACKAGE 4 | # 5 | ### BEGIN INIT INFO 6 | # Provides: @PACKAGE@ 7 | # Required-Start: $time $network $remote_fs $syslog 8 | # Required-Stop: $time $network $remote_fs $syslog 9 | # Default-Start: 2 3 4 5 10 | # Default-Stop: 0 1 6 11 | # Short-Description: @PACKAGE@ 12 | ### END INIT INFO 13 | 14 | . /lib/lsb/init-functions 15 | 16 | PIDFILE="/var/run/@PACKAGE@.pid" 17 | 18 | # Run @PACKAGE@ as this user ID and group ID 19 | JMXTRANS_USER=@PACKAGE@ 20 | JMXTRANS_GROUP=@PACKAGE@ 21 | 22 | RUNCMD="/usr/share/@PACKAGE@/jmxtrans.sh" 23 | 24 | # overwrite settings from default file 25 | if [ -f /etc/default/@PACKAGE@ ]; then 26 | set -a 27 | source /etc/default/@PACKAGE@ 28 | set +a 29 | fi 30 | 31 | RETVAL=0 32 | 33 | do_start() { 34 | /usr/bin/touch "$PIDFILE" && /bin/chown "$JMXTRANS_USER":"$JMXTRANS_USER" "$PIDFILE" 35 | start-stop-daemon --start -b --pidfile $PIDFILE --oknodo \ 36 | --chuid $JMXTRANS_USER:$JMXTRANS_GROUP -u $JMXTRANS_USER -g $JMXTRANS_GROUP -v \ 37 | -d /usr/share/@PACKAGE@ --exec $RUNCMD -- start 38 | RETVAL=$? 39 | } 40 | 41 | do_stop() { 42 | su -m jmxtrans -c "$RUNCMD stop" 43 | RETVAL=$? 44 | } 45 | 46 | do_status() { 47 | su -m jmxtrans -c "$RUNCMD status" 48 | RETVAL=$? 49 | } 50 | 51 | case "$1" in 52 | start) 53 | log_daemon_msg "Starting @PACKAGE@" "@PACKAGE@" 54 | do_start 55 | log_end_msg $RETVAL 56 | ;; 57 | stop) 58 | log_daemon_msg "Stopping @PACKAGE@" "@PACKAGE@" 59 | do_stop 60 | log_end_msg $RETVAL 61 | ;; 62 | 63 | restart|reload|force-reload|try-restart) 64 | log_daemon_msg "Restarting @PACKAGE@" "@PACKAGE@" 65 | do_stop 66 | do_start 67 | log_end_msg $RETVAL 68 | ;; 69 | 70 | status) 71 | log_daemon_msg "Status @PACKAGE@" "@PACKAGE@" 72 | do_status 73 | log_end_msg $RETVAL 74 | ;; 75 | 76 | *) 77 | log_action_msg "Usage: /etc/init.d/@PACKAGE@ {start|stop|reload|force-reload|restart|try-restart|status}" 78 | exit 1 79 | esac 80 | 81 | exit $RETVAL 82 | -------------------------------------------------------------------------------- /heapmemory-rrd-template.xml: -------------------------------------------------------------------------------- 1 | 2 | ${database} 3 | 5 | 6 | 60 7 | 8 | HeapMemoryUsagefd71GAUGE400UU 9 | HeapMemoryUsage25f7GAUGE400UU 10 | HeapMemoryUsageffe4GAUGE400UU 11 | HeapMemoryUsaged3bbGAUGE400UU 12 | NHMUb93cabbe11008a2GAUGE400UU 13 | NHMU0a2a437bb561de8GAUGE400UU 14 | NHMU925cc6ce551095eGAUGE400UU 15 | NHMU42f37e7c3e62970GAUGE400UU 16 | 17 | 18 | AVERAGE 19 | 0.5 20 | 1 21 | 7000 22 | 23 | 24 | MIN 25 | 0.5 26 | 1 27 | 7000 28 | 29 | 30 | MAX 31 | 0.5 32 | 1 33 | 7000 34 | 35 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/Tester.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.inject.Guice; 5 | import com.google.inject.Injector; 6 | import com.googlecode.jmxtrans.JmxTransformer; 7 | import com.googlecode.jmxtrans.guice.JmxTransModule; 8 | import com.googlecode.jmxtrans.model.JmxProcess; 9 | import com.googlecode.jmxtrans.model.Query; 10 | import com.googlecode.jmxtrans.model.Server; 11 | import com.googlecode.jmxtrans.model.output.StdOutWriter; 12 | import com.googlecode.jmxtrans.util.JsonPrinter; 13 | 14 | import java.util.Collections; 15 | 16 | /** 17 | * This class produces the json that is in example.json. 18 | * 19 | * @author jon 20 | */ 21 | public class Tester { 22 | 23 | private static final JsonPrinter printer = new JsonPrinter(System.out); 24 | 25 | /** */ 26 | public static void main(String[] args) throws Exception { 27 | Server server = Server.builder() 28 | .setHost("w2") 29 | .setPort("1099") 30 | .setNumQueryThreads(2) 31 | .addQuery(Query.builder() 32 | .setObj("java.lang:type=Memory") 33 | .addAttr("HeapMemoryUsage", "NonHeapMemoryUsage") 34 | .addOutputWriter(new StdOutWriter(ImmutableList.of(), false, Collections.emptyMap())) 35 | .build()) 36 | .addQuery(Query.builder() 37 | .setObj("java.lang:name=CMS Old Gen,type=MemoryPool") 38 | .addAttr("Usage") 39 | .addOutputWriter(new StdOutWriter(ImmutableList.of(), false, Collections.emptyMap())) 40 | .build()) 41 | .addQuery(Query.builder() 42 | .setObj("java.lang:name=ConcurrentMarkSweep,type=GarbageCollector") 43 | .addAttr("LastGcInfo") 44 | .addOutputWriter(new StdOutWriter(ImmutableList.of(), false, Collections.emptyMap())) 45 | .build()) 46 | .build(); 47 | 48 | JmxProcess process = new JmxProcess(server); 49 | printer.prettyPrint(process); 50 | 51 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 52 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 53 | 54 | transformer.executeStandalone(process); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/util/JsonPrinterTest.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import com.google.common.io.Closer; 4 | import org.junit.Test; 5 | 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.PrintStream; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import com.googlecode.jmxtrans.model.JmxProcess; 12 | import com.googlecode.jmxtrans.model.Query; 13 | import com.googlecode.jmxtrans.model.Server; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | public class JsonPrinterTest { 18 | 19 | @Test 20 | public void standardJsonPrinting() throws Exception { 21 | Closer closer = Closer.create(); 22 | try { 23 | ByteArrayOutputStream baos = closer.register(new ByteArrayOutputStream()); 24 | PrintStream out = closer.register(new PrintStream(baos)); 25 | 26 | new JsonPrinter(out).print(standardProcess()); 27 | String result = new String(baos.toByteArray()); 28 | 29 | assertThat(result).contains("\"url\":\"service:jmx:rmi:///jndi/rmi://example.org:123/jmxrmi\""); 30 | } catch (Throwable t) { 31 | throw closer.rethrow(t); 32 | } finally { 33 | closer.close(); 34 | } 35 | } 36 | 37 | @Test 38 | public void prettyJsonPrinting() throws Exception { 39 | Closer closer = Closer.create(); 40 | try { 41 | ByteArrayOutputStream baos = closer.register(new ByteArrayOutputStream()); 42 | PrintStream out = closer.register(new PrintStream(baos)); 43 | 44 | new JsonPrinter(out).prettyPrint(standardProcess()); 45 | String result = new String(baos.toByteArray()); 46 | 47 | assertThat(result).contains("\"url\" : \"service:jmx:rmi:///jndi/rmi://example.org:123/jmxrmi\""); 48 | } catch (Throwable t) { 49 | throw closer.rethrow(t); 50 | } finally { 51 | closer.close(); 52 | } 53 | } 54 | 55 | private JmxProcess standardProcess() { 56 | List servers = new ArrayList(); 57 | Server server = Server.builder() 58 | .setAlias("alias") 59 | .setHost("example.org") 60 | .setPort("123") 61 | .addQuery(Query.builder() 62 | .setObj("obj") 63 | .build()) 64 | .build(); 65 | servers.add(server); 66 | return new JmxProcess(servers); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/assembly/dist.xml: -------------------------------------------------------------------------------- 1 | 3 | dist 4 | 5 | tar.gz 6 | 7 | 8 | 9 | 10 | target/jmxtrans-${project.version}-all.jar 11 | /lib 12 | jmxtrans-all.jar 13 | 644 14 | 15 | 16 | 17 | 18 | 19 | ${basedir} 20 | /bin 21 | 755 22 | 775 23 | 24 | *sh 25 | 26 | 27 | 28 | ${basedir}/doc 29 | /doc 30 | 755 31 | 644 32 | unix 33 | 34 | 35 | ${basedir} 36 | /doc/examples 37 | 755 38 | 644 39 | unix 40 | 41 | *json 42 | *xml 43 | 44 | 45 | pom.xml 46 | build.xml 47 | 48 | 49 | 50 | ${basedir}/tools 51 | /tools 52 | 755 53 | 755 54 | unix 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/jobs/ServerJob.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.jobs; 2 | 3 | import com.googlecode.jmxtrans.connections.JMXConnectionParams; 4 | import com.googlecode.jmxtrans.jmx.JmxUtils; 5 | import com.googlecode.jmxtrans.model.Server; 6 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; 7 | import org.quartz.Job; 8 | import org.quartz.JobDataMap; 9 | import org.quartz.JobExecutionContext; 10 | import org.quartz.JobExecutionException; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import javax.inject.Inject; 15 | import javax.management.remote.JMXConnector; 16 | 17 | /** 18 | * This is a quartz job that is responsible for executing a Server object on a 19 | * cron schedule that is defined within the Server object. 20 | * 21 | * @author jon 22 | */ 23 | public class ServerJob implements Job { 24 | private static final Logger log = LoggerFactory.getLogger(ServerJob.class); 25 | 26 | private final GenericKeyedObjectPool jmxPool; 27 | 28 | private final JmxUtils jmxUtils; 29 | 30 | @Inject 31 | public ServerJob(GenericKeyedObjectPool jmxPool, JmxUtils jmxUtils) { 32 | this.jmxPool = jmxPool; 33 | this.jmxUtils = jmxUtils; 34 | } 35 | 36 | public void execute(JobExecutionContext context) throws JobExecutionException { 37 | JobDataMap map = context.getMergedJobDataMap(); 38 | Server server = (Server) map.get(Server.class.getName()); 39 | 40 | log.debug("+++++ Started server job: {}", server); 41 | 42 | JMXConnector conn = null; 43 | JMXConnectionParams connectionParams = null; 44 | try { 45 | connectionParams = new JMXConnectionParams(server.getJmxServiceURL(), server.getEnvironment()); 46 | if (!server.isLocal()) { 47 | conn = jmxPool.borrowObject(connectionParams); 48 | } 49 | jmxUtils.processServer(server, conn); 50 | } catch (Exception e) { 51 | log.error("Error in job for server: " + server, e); 52 | throw new JobExecutionException(e); 53 | } finally { 54 | try { 55 | jmxPool.returnObject(connectionParams, conn); 56 | } catch (Exception ex) { 57 | log.error("Error returning object to pool for server: " + server); 58 | } 59 | } 60 | 61 | log.debug("+++++ Finished server job: {}", server); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/connections/SocketFactory.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | import org.apache.commons.pool.BaseKeyedPoolableObjectFactory; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.net.InetSocketAddress; 8 | import java.net.Socket; 9 | import java.net.SocketTimeoutException; 10 | 11 | /** 12 | * Allows us to pool socket connections. 13 | */ 14 | public class SocketFactory extends BaseKeyedPoolableObjectFactory { 15 | 16 | private final Logger log = LoggerFactory.getLogger(getClass()); 17 | 18 | /** 19 | * Creates the socket and the writer to go with it. 20 | */ 21 | @Override 22 | public Socket makeObject(InetSocketAddress address) throws Exception { 23 | Socket socket = new Socket(address.getHostName(), address.getPort()); 24 | socket.setKeepAlive(true); 25 | return socket; 26 | } 27 | 28 | /** 29 | * Closes the socket. 30 | */ 31 | @Override 32 | public void destroyObject(InetSocketAddress address, Socket socket) throws Exception { 33 | socket.close(); 34 | } 35 | 36 | /** 37 | * Validates that the socket is good. 38 | */ 39 | @Override 40 | public boolean validateObject(InetSocketAddress address, Socket socket) { 41 | if (socket == null) { 42 | log.error("Socket is null [{}]", address); 43 | return false; 44 | } 45 | 46 | if (!socket.isBound()) { 47 | log.error("Socket is not bound [{}]", address); 48 | return false; 49 | } 50 | if (socket.isClosed()) { 51 | log.error("Socket is closed [{}]", address); 52 | return false; 53 | } 54 | if (!socket.isConnected()) { 55 | log.error("Socket is not connected [{}]", address); 56 | return false; 57 | } 58 | if (socket.isInputShutdown()) { 59 | log.error("Socket input is shutdown [{}]", address); 60 | return false; 61 | } 62 | if (socket.isOutputShutdown()) { 63 | log.error("Socket output is shutdown [{}]", address); 64 | return false; 65 | } 66 | // This is a slow test, let's at least put it last. Should probably be removed anyway. 67 | try { 68 | socket.setSoTimeout(100); 69 | if (socket.getInputStream().read() == -1) { 70 | return false; 71 | } 72 | } catch (SocketTimeoutException e) { 73 | } catch (Exception e) { 74 | return false; 75 | } 76 | return true; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/example/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans.example (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans.example

12 |
13 |

Classes

14 | 29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /rpm/SOURCES/jmxtrans.init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # chkconfig: - 90 60 4 | # pidfile: /var/run/jmxtrans.pid 5 | # config: /etc/sysconfig/jmxtrans 6 | # 7 | ### BEGIN INIT INFO 8 | # Provides: jmxtrans 9 | # Required-Start: $local_fs $remote_fs $network $named 10 | # Required-Stop: $local_fs $remote_fs $network 11 | # Default-Start: 3 5 12 | # Default-Stop: 0 1 2 6 13 | # Short-Description: run jmxtrans daemon 14 | # Description: jmxtrans is very powerful tool which reads json 15 | # configuration files of servers/ports and jmx domains - attributes - types 16 | # and then outputs the data in whatever format you want via special 'Writer' objects which you can code up yourself. 17 | # It does this with a very efficient engine design that will scale to querying thousands of machines. 18 | ### END INIT INFO 19 | 20 | # 21 | # init.d / servicectl compatibility (openSUSE) 22 | # 23 | if [ -f /etc/rc.status ]; then 24 | . /etc/rc.status 25 | rc_reset 26 | fi 27 | 28 | # Source function library. 29 | if [ -r /etc/init.d/functions ]; then 30 | . /etc/init.d/functions 31 | fi 32 | 33 | RETVAL=0 34 | prog="jmxtrans" 35 | user="jmxtrans" 36 | exec="/usr/share/jmxtrans/jmxtrans.sh" 37 | lockdir=/var/lock/subsys 38 | lockfile=$lockdir/jmxtrans 39 | config=/etc/sysconfig/jmxtrans 40 | 41 | if [ -f "${config}" ]; then 42 | . "${config}" 43 | fi 44 | 45 | 46 | start() { 47 | echo -n $"Starting $prog: " 48 | 49 | daemon --user=$user $exec start 50 | RETVAL=$? 51 | 52 | echo 53 | [ $RETVAL -eq 0 ] && [ -d $lockdir ] && touch $lockfile 54 | } 55 | 56 | stop() { 57 | echo -n $"Stopping $prog: " 58 | $exec stop 59 | RETVAL=$? 60 | echo 61 | [ $RETVAL -eq 0 ] && [ -f $lockfile ] && rm -f $lockfile 62 | } 63 | 64 | status() { 65 | $exec status 66 | } 67 | 68 | restart() { 69 | daemon --user=$user $exec restart 70 | } 71 | 72 | # See how we were called. 73 | case "$1" in 74 | start) 75 | status && exit 0 76 | $1 77 | ;; 78 | stop) 79 | status || exit 0 80 | $1 81 | ;; 82 | status) 83 | status 84 | RETVAL=$? 85 | ;; 86 | restart|force-reload|reload) 87 | restart 88 | ;; 89 | *) 90 | echo $"Usage: $prog {start|stop|restart|force-reload|reload|status}" 91 | RETVAL=2 92 | esac 93 | 94 | exit $RETVAL 95 | -------------------------------------------------------------------------------- /jar.properties: -------------------------------------------------------------------------------- 1 | ant-contrib.jar=lib/ant-contrib-1.0b3.jar 2 | commons-cli.jar=lib/commons-cli-1.2.jar 3 | commons-cli.src=lib/commons-cli-1.2-sources.jar 4 | commons-codec.jar=lib/commons-codec-1.3.jar 5 | commons-codec.src=lib/commons-codec-1.3-sources.jar 6 | commons-io.jar=lib/commons-io-1.4.jar 7 | commons-io.src=lib/commons-io-1.4-sources.jar 8 | commons-lang.jar=lib/commons-lang-2.5.jar 9 | commons-lang.src=lib/commons-lang-2.5-sources.jar 10 | commons-logging.jar=lib/commons-logging-1.1.1.jar 11 | commons-logging.src=lib/commons-logging-1.1.1-sources.jar 12 | commons-pool.jar=lib/commons-pool-1.5.6.jar 13 | commons-pool.src=lib/commons-pool-1.5.6-sources.jar 14 | findbugs-annotations.jar=lib/annotations-3.0.0.jar 15 | gmetric4j.jar=lib/gmetric4j-1.0.3.jar 16 | guava.jar=lib/guava-18.0.jar 17 | jackson-core.jar=lib/jackson-core-asl-1.6.3.jar 18 | jackson-mapper.jar=lib/jackson-mapper-asl-1.6.3.jar 19 | jackson.src=lib/jackson-1.6.3-sources.jar 20 | jgit.jar=lib/org.eclipse.jgit-1.1.0.201109151100-r.jar 21 | jpathwatch.jar=lib/jpathwatch-0-95.jar 22 | jrobin.jar=lib/jrobin-1.5.9.jar 23 | jrobin.src=lib/jrobin-1.5.9-sources.jar 24 | junit.jar=lib/junit-4.9b2.jar 25 | log4j.jar=lib/log4j-1.2.16.jar 26 | oncrpc.jar=lib/oncrpc-1.0.7.jar 27 | quartz.jar=lib/quartz-1.8.4.jar 28 | quartz.src=lib/quartz-1.8.4-sources.jar 29 | slf4j-api.jar=lib/slf4j-api-1.7.6.jar 30 | slf4j-api.src=lib/slf4j-api-1.7.6-sources.jar 31 | slf4j-log4j.jar=lib/slf4j-log4j12-1.7.6.jar 32 | slf4j-log4j.src=lib/slf4j-log4j12-1.7.6-sources.jar 33 | logback-classic.jar=lib/logback-classic-1.1.1.jar 34 | logback-core.jar=lib/logback-core-1.1.1.jar 35 | sweetened.jar=lib/sweetened.jar 36 | velocity.jar=lib/velocity-1.7.jar 37 | velocity.src=lib/velocity-1.7-sources.jar 38 | remoting3-remoting-jmx.jar=lib/remoting-jmx-1.0.1.Final.jar 39 | remoting3-remoting-jmx.src=lib/remoting-jmx-1.0.1.Final-sources.jar 40 | remotingjmx-remoting-jmx.jar=lib/remoting-jmx-1.1.1.CR2.jar 41 | remotingjmx-remoting-jmx.src=lib/remoting-jmx-1.1.1.CR2-sources.jar 42 | jboss-loging.jar=jboss-logging-3.1.0.GA.jar 43 | jboss-logging-processor.jar=jboss-logging-processor-1.1.0.Final.jar 44 | jboss-marshalling.jar=jboss-marshalling-1.3.7.GA.jar 45 | jboss-marshalling-river.jar=jboss-marshalling-river-1.3.16.GA.jar 46 | jboss-sasl.jar=jboss-sasl-1.0.3.Final.jar 47 | jbossjdeparser.jar=jdeparser-1.0.0.Final.jar 48 | jboss-xnio-api.jar=xnio-api-3.0.0.GA.jar 49 | jboss-xnio-nio.jar=xnio-nio-3.0.7.GA.jar 50 | jexl.jar=lib/commons-jexl-2.1.1.jar 51 | -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/model/output/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans.model.output (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans.model.output

12 |
13 |

Classes

14 | 27 |

Enums

28 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![jmxtranslogo](http://www.jmxtrans.org/images/jmxtrans-logo.gif) 2 | 3 | [![Build Status](https://secure.travis-ci.org/jmxtrans/jmxtrans.png?branch=master)](http://travis-ci.org/jmxtrans/jmxtrans) 4 | [![Build Status](https://buildhive.cloudbees.com/job/jmxtrans/job/jmxtrans/badge/icon)](https://buildhive.cloudbees.com/job/jmxtrans/job/jmxtrans/) 5 | 6 | This is the source code repository for the jmxtrans project. 7 | 8 | This is effectively the missing connector between speaking to a JVM via JMX on one end and whatever logging / monitoring / graphing package that you can dream up on the other end. 9 | 10 | jmxtrans is very powerful tool which uses easily generated JSON based configuration files and then outputs the data in whatever format you desire. It does this with a very efficient engine design that will scale to communicating with thousands of machines from a single jmxtrans instance. 11 | 12 | The core engine is very solid and there are writers for [Graphite](http://graphite.wikidot.com/), [StatsD](https://github.com/etsy/statsd), [Ganglia](http://ganglia.sourceforge.net/), [cacti/rrdtool](http://www.cacti.net/), [OpenTSDB](http://opentsdb.net/), text files, and stdout. Feel free to suggest more on the discussion group or issue tracker. 13 | 14 | * [Download a recent stable build](https://github.com/jmxtrans/jmxtrans/downloads) 15 | * See the [Wiki](https://github.com/jmxtrans/jmxtrans/wiki) for full documentation. 16 | * Join the [Google Group](http://groups.google.com/group/jmxtrans) if you have anything to discuss or [follow the commits](http://groups.google.com/group/jmxtrans-commits). Please don't email Jon directly because he just doesn't have enough time to answer every question individually. 17 | * People are [talking - this is me! (skip to 21:45)](http://www.justin.tv/kctv88/b/290736874) and [talking](http://www.slideshare.net/cyrille.leclerc/paris-devops-monitoring-and-feature-toggle-pattern-with-jmx) and [talking (skip to 34:40)](http://www.justin.tv/kctv88/b/288229232) and [(french)](http://www.slideshare.net/henri.gomez/devops-retour-dexprience-marsjug-du-29-juin-2011 taking) about it. 18 | * If you are seeing duplication of output data, look for 'typeNames' in the documentation. 19 | * If you like this project, please tell your friends, blog & tweet. I'd really love your help getting more publicity. 20 | 21 | Coda Hale did [an excellent talk](http://pivotallabs.com/talks/139-metrics-metrics-everywhere) for [Pivotal Labs](http://pivotallabs.com/) on *why* metrics matter. Great justification for using a tool like jmxtrans. 22 | 23 | ![render](http://jmxtrans.googlecode.com/svn/wiki/render.png) 24 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/output/GraphiteWriterTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import com.googlecode.jmxtrans.model.Query; 5 | import com.googlecode.jmxtrans.model.Result; 6 | import com.googlecode.jmxtrans.model.Server; 7 | import com.googlecode.jmxtrans.model.ValidationException; 8 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; 9 | import org.junit.Test; 10 | 11 | import java.io.ByteArrayOutputStream; 12 | import java.net.InetSocketAddress; 13 | import java.net.Socket; 14 | 15 | import static com.google.common.collect.ImmutableList.of; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.mockito.Matchers.any; 18 | import static org.mockito.Mockito.mock; 19 | import static org.mockito.Mockito.when; 20 | 21 | public class GraphiteWriterTests { 22 | 23 | @Test(expected = NullPointerException.class) 24 | public void hostIsRequired() throws ValidationException { 25 | try { 26 | GraphiteWriter.builder() 27 | .setPort(123) 28 | .build(); 29 | } catch (NullPointerException npe) { 30 | assertThat(npe).hasMessage("Host cannot be null."); 31 | throw npe; 32 | } 33 | } 34 | 35 | @Test(expected = NullPointerException.class) 36 | public void portIsRequired() throws ValidationException { 37 | try { 38 | GraphiteWriter.builder() 39 | .setHost("localhost") 40 | .build(); 41 | } catch (NullPointerException npe) { 42 | assertThat(npe).hasMessage("Port cannot be null."); 43 | throw npe; 44 | } 45 | } 46 | 47 | @Test 48 | public void writeSingleResult() throws Exception { 49 | // a lot of setup for not much of a test ... 50 | Server server = Server.builder().setHost("host").setPort("123").build(); 51 | Query query = Query.builder().build(); 52 | Result result = new Result("attributeName", "className", "classNameAlias", "typeName", ImmutableMap.of("key", (Object)1)); 53 | 54 | GenericKeyedObjectPool pool = mock(GenericKeyedObjectPool.class); 55 | Socket socket = mock(Socket.class); 56 | when(pool.borrowObject(any(InetSocketAddress.class))).thenReturn(socket); 57 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 58 | when(socket.getOutputStream()).thenReturn(out); 59 | 60 | GraphiteWriter writer = GraphiteWriter.builder() 61 | .setHost("localhost") 62 | .setPort(2003) 63 | .build(); 64 | writer.setPool(pool); 65 | 66 | writer.doWrite(server, query, of(result)); 67 | 68 | // check that Graphite format is respected 69 | assertThat(out.toString()).startsWith("servers.host_123.classNameAlias.attributeName_key 1 "); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/util/LocalJMXConnector.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | package com.googlecode.jmxtrans.util; 19 | 20 | import javax.management.ListenerNotFoundException; 21 | import javax.management.MBeanServerConnection; 22 | import javax.management.NotificationFilter; 23 | import javax.management.NotificationListener; 24 | import javax.management.remote.JMXConnector; 25 | import javax.security.auth.Subject; 26 | import java.io.IOException; 27 | import java.util.Map; 28 | 29 | /** 30 | * Represents a connection to a local {@link MBeanServerConnection} 31 | */ 32 | public class LocalJMXConnector implements JMXConnector { 33 | private final MBeanServerConnection serverConnection; 34 | 35 | public LocalJMXConnector(MBeanServerConnection serverConnection) { 36 | this.serverConnection = serverConnection; 37 | } 38 | 39 | public void connect() throws IOException { 40 | } 41 | 42 | public void connect(Map env) throws IOException { 43 | } 44 | 45 | public MBeanServerConnection getMBeanServerConnection() throws IOException { 46 | return serverConnection; 47 | } 48 | 49 | public MBeanServerConnection getMBeanServerConnection(Subject delegationSubject) throws IOException { 50 | return serverConnection; 51 | } 52 | 53 | public void close() throws IOException { 54 | } 55 | 56 | public void addConnectionNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { 57 | // TODO 58 | } 59 | 60 | public void removeConnectionNotificationListener(NotificationListener listener) throws ListenerNotFoundException { 61 | // TODO 62 | } 63 | 64 | public void removeConnectionNotificationListener(NotificationListener l, NotificationFilter f, Object handback) throws ListenerNotFoundException { 65 | // TODO 66 | } 67 | 68 | public String getConnectionId() throws IOException { 69 | return "LocalJMXConnector"; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/TreeWalker2.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.googlecode.jmxtrans.jmx.JmxQueryProcessor; 5 | import com.googlecode.jmxtrans.model.Query; 6 | import com.googlecode.jmxtrans.model.Server; 7 | import com.googlecode.jmxtrans.model.output.StdOutWriter; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import javax.management.AttributeNotFoundException; 12 | import javax.management.MBeanAttributeInfo; 13 | import javax.management.MBeanInfo; 14 | import javax.management.MBeanServerConnection; 15 | import javax.management.ObjectName; 16 | import javax.management.remote.JMXConnector; 17 | import java.io.IOException; 18 | import java.util.Collections; 19 | import java.util.Set; 20 | 21 | /** 22 | * Walks a JMX tree and prints out all of the attribute values actually using 23 | * the JmxTrans api. 24 | * 25 | * This is a good test of the core engine of JmxTrans to ensure that it covers 26 | * all cases. 27 | * 28 | * @author jon 29 | */ 30 | public class TreeWalker2 { 31 | 32 | private static final Logger log = LoggerFactory.getLogger(TreeWalker2.class); 33 | 34 | /** */ 35 | public static void main(String[] args) throws Exception { 36 | Server server = Server.builder().setHost("localhost").setPort("1099").build(); 37 | 38 | JMXConnector conn = null; 39 | try { 40 | conn = server.getServerConnection(); 41 | MBeanServerConnection mbeanServer = conn.getMBeanServerConnection(); 42 | 43 | TreeWalker2 tw = new TreeWalker2(); 44 | tw.walkTree(mbeanServer); 45 | } catch (IOException e) { 46 | log.error("Problem processing queries for server: " + server.getHost() + ":" + server.getPort(), e); 47 | } finally { 48 | if (conn != null) { 49 | conn.close(); 50 | } 51 | } 52 | } 53 | 54 | /** */ 55 | public void walkTree(MBeanServerConnection connection) throws Exception { 56 | 57 | // key here is null, null returns everything! 58 | Set mbeans = connection.queryNames(null, null); 59 | for (ObjectName name : mbeans) { 60 | MBeanInfo info = connection.getMBeanInfo(name); 61 | MBeanAttributeInfo[] attrs = info.getAttributes(); 62 | 63 | Query.Builder query = Query.builder() 64 | .setObj(name.getCanonicalName()) 65 | .addOutputWriter(new StdOutWriter(ImmutableList.of(), false, Collections.emptyMap())); 66 | 67 | for (MBeanAttributeInfo attrInfo : attrs) { 68 | query.addAttr(attrInfo.getName()); 69 | } 70 | 71 | try { 72 | new JmxQueryProcessor().processQuery(connection, null, query.build()); 73 | } catch (AttributeNotFoundException anfe) { 74 | log.error("Error", anfe); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/connections/TCPEchoServer.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.connections; 2 | 3 | import com.google.common.io.Closer; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | import java.io.PrintWriter; 11 | import java.net.InetSocketAddress; 12 | import java.net.ServerSocket; 13 | import java.net.Socket; 14 | 15 | import static com.google.common.base.Preconditions.checkState; 16 | 17 | public class TCPEchoServer { 18 | 19 | private final Logger log = LoggerFactory.getLogger(getClass()); 20 | 21 | private Thread thread = null; 22 | private volatile ServerSocket server; 23 | 24 | private final Object startSynchro = new Object(); 25 | 26 | public void start() { 27 | if (thread != null) { 28 | throw new IllegalStateException("Server already started"); 29 | } 30 | thread = new Thread(new Runnable() { 31 | @Override 32 | public void run() { 33 | Closer closer = Closer.create(); 34 | try { 35 | try { 36 | server = closer.register(new ServerSocket(0)); 37 | while (true) { 38 | processRequests(server); 39 | } 40 | } catch (Throwable t) { 41 | throw closer.rethrow(t); 42 | } finally { 43 | closer.close(); 44 | server = null; 45 | } 46 | } catch (IOException ioe) { 47 | log.error("Exception in TCP echo server", ioe); 48 | } 49 | 50 | } 51 | }); 52 | thread.start(); 53 | try { 54 | synchronized (startSynchro) { 55 | startSynchro.wait(1000); 56 | } 57 | } catch (InterruptedException interrupted) { 58 | log.error("TCP Echo server seems to take too long to start", interrupted); 59 | } 60 | } 61 | 62 | private void processRequests(ServerSocket server) throws IOException { 63 | Closer closer = Closer.create(); 64 | try { 65 | Socket socket = server.accept(); 66 | synchronized (startSynchro) { 67 | startSynchro.notifyAll(); 68 | } 69 | BufferedReader in = closer.register(new BufferedReader(new InputStreamReader(socket.getInputStream()))); 70 | PrintWriter out = closer.register(new PrintWriter(socket.getOutputStream())); 71 | String line; 72 | while ((line = in.readLine()) != null) { 73 | out.print(line); 74 | } 75 | } catch (Throwable t) { 76 | throw closer.rethrow(t); 77 | } finally { 78 | closer.close(); 79 | } 80 | } 81 | 82 | public void stop() { 83 | checkState(thread != null, "Server not started"); 84 | thread.interrupt(); 85 | } 86 | 87 | public InetSocketAddress getLocalSocketAddress() { 88 | checkState(server != null, "Server not started"); 89 | return new InetSocketAddress("localhost", server.getLocalPort()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/jmx/JmxProcessingTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.jmx; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.mockito.ArgumentCaptor; 8 | import org.mockito.Captor; 9 | import org.mockito.runners.MockitoJUnitRunner; 10 | 11 | import javax.management.InstanceAlreadyExistsException; 12 | import javax.management.MBeanRegistrationException; 13 | import javax.management.MBeanServer; 14 | import javax.management.MBeanServerFactory; 15 | import javax.management.MalformedObjectNameException; 16 | import javax.management.NotCompliantMBeanException; 17 | import javax.management.ObjectName; 18 | import java.util.List; 19 | 20 | import com.googlecode.jmxtrans.model.OutputWriter; 21 | import com.googlecode.jmxtrans.model.Query; 22 | import com.googlecode.jmxtrans.model.Result; 23 | import com.googlecode.jmxtrans.model.Server; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | import static org.mockito.Matchers.any; 27 | import static org.mockito.Mockito.mock; 28 | import static org.mockito.Mockito.verify; 29 | 30 | @RunWith(MockitoJUnitRunner.class) 31 | public class JmxProcessingTests { 32 | 33 | public static final String MBEAN_NAME = "domain:type=SomeType"; 34 | private MBeanServer server; 35 | 36 | @Captor 37 | private ArgumentCaptor queryCaptor; 38 | @Captor 39 | private ArgumentCaptor> resultsCaptor; 40 | 41 | @Before 42 | public void startMBeanServer() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException { 43 | server = MBeanServerFactory.createMBeanServer(); 44 | server.registerMBean(new TestBean(), new ObjectName(MBEAN_NAME)); 45 | } 46 | 47 | @Test 48 | public void querySimpleAttribute() throws Exception { 49 | OutputWriter outputWriter = mock(OutputWriter.class); 50 | Query query = Query.builder() 51 | .setObj(MBEAN_NAME) 52 | .addAttr("DummyValue") 53 | .addOutputWriter(outputWriter) 54 | .build(); 55 | 56 | new JmxQueryProcessor().processQuery(server, null, query); 57 | 58 | verify(outputWriter).doWrite(any(Server.class), queryCaptor.capture(), resultsCaptor.capture()); 59 | 60 | assertThat(queryCaptor.getValue()).isEqualTo(query); 61 | 62 | List results = resultsCaptor.getValue(); 63 | assertThat(results).hasSize(1); 64 | 65 | Result result = results.get(0); 66 | assertThat(result.getValues().get("DummyValue")).isEqualTo(123); 67 | } 68 | 69 | 70 | 71 | public interface TestMXBean { 72 | int getDummyValue(); 73 | } 74 | 75 | public class TestBean implements TestMXBean { 76 | @Override 77 | public int getDummyValue() { 78 | return 123; 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Source debconf library. 6 | . /usr/share/debconf/confmodule 7 | 8 | # defaults file 9 | CONFIG="/etc/default/@PACKAGE@" 10 | 11 | # get number of cores so we can set number of GC threads 12 | CPU_CORES=$(cat /proc/cpuinfo | grep processor | wc -l) 13 | NEW_RATIO=8 14 | 15 | # defaults for JVM 16 | HEAP_SIZE="512" 17 | 18 | purge_line () { 19 | if [ -s "$1" ]; then 20 | # safely create a temp file 21 | t=$(tempfile) || exit 22 | trap "rm -f -- '$t'" EXIT 23 | 24 | # purge line 25 | sed "/$2/d" "$1" > "$t" 26 | mv "$t" "$1" 27 | 28 | # cleanup temp file 29 | rm -f -- "$t" 30 | trap - EXIT 31 | fi 32 | } 33 | 34 | sed_file () { 35 | # safely create a temp file 36 | t=$(tempfile) || exit 37 | trap "rm -f -- '$t'" EXIT 38 | 39 | sed "s/$1/$2/g" "$3" > "$t" 40 | mv "$t" "$3" 41 | 42 | # cleanup temp file 43 | rm -f -- "$t" 44 | trap - EXIT 45 | } 46 | 47 | case "$1" in 48 | configure) 49 | 50 | ##### deal with logs ##### 51 | mkdir -p /var/log/@PACKAGE@ 52 | chown jmxtrans:jmxtrans /var/log/@PACKAGE@ 53 | 54 | if [ ! -d /usr/share/@PACKAGE@/logs -a ! -h /usr/share/@PACKAGE@/logs ]; then 55 | cd /usr/share/@PACKAGE@ 56 | ln -fs /var/log/@PACKAGE@ logs 57 | fi 58 | ##### deal with logs ##### 59 | 60 | # collect user inputs 61 | db_get @PACKAGE@/jvm_heap_size 62 | if [ ! -z "$RET" ]; then 63 | HEAP_SIZE="${RET}" 64 | fi 65 | 66 | HEAP_NUMBER=$(echo $HEAP_SIZE|sed 's/[a-zA-Z]//g') 67 | NEW_SIZE=$(expr $HEAP_SIZE / $NEW_RATIO) 68 | 69 | mkdir -p /var/lib/@PACKAGE@ || true 70 | chown jmxtrans:jmxtrans /var/lib/@PACKAGE@ 71 | 72 | # populate defaults file 73 | if [ ! -e "$CONFIG" ]; then 74 | echo "# default file for package @PACKAGE@" > "$CONFIG" 75 | echo "export LOG_DIR=\"/var/log/@PACKAGE@\"" >> "$CONFIG" 76 | echo "export SECONDS_BETWEEN_RUNS=60" >> "$CONFIG" 77 | echo "export JSON_DIR=\"/var/lib/@PACKAGE@\"" >> "$CONFIG" 78 | echo "export HEAP_SIZE=${HEAP_SIZE}" >> "$CONFIG" 79 | echo "export NEW_SIZE=${NEW_SIZE}" >> "$CONFIG" 80 | echo "export CPU_CORES=${CPU_CORES}" >> "$CONFIG" 81 | echo "export NEW_RATIO=${NEW_RATIO}" >> "$CONFIG" 82 | echo "export LOG_LEVEL=debug" >> "$CONFIG" 83 | fi 84 | 85 | chmod 644 "${CONFIG}" || true 86 | ;; 87 | *) 88 | echo "postinst called with unknown argument \`$1'" >&2 89 | ;; 90 | esac 91 | 92 | # dh_installdeb will replace this with shell code automatically 93 | # generated by other debhelper scripts. 94 | 95 | #DEBHELPER# 96 | 97 | exit 0 98 | 99 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/output/DailyKeyOutWriter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.collect.ImmutableList; 6 | import org.apache.log4j.Appender; 7 | import org.apache.log4j.DailyRollingFileAppender; 8 | import org.apache.log4j.PatternLayout; 9 | 10 | import java.io.IOException; 11 | import java.util.Map; 12 | 13 | /** 14 | * This class is derived from KeyOutWriter. It uses DailyRollingFileAppender 15 | * instead of RollingFileAppender. 16 | * 17 | * Writes out data in the same format as the GraphiteWriter, except to a file 18 | * and tab delimited. Takes advantage of Log4J DailyRollingFileAppender to 19 | * automatically handle rolling the files at defined intervals (datePattern). 20 | * 21 | * Note that this writer will NOT clean up after itself. The files will not be 22 | * deleted. It is up to the user to clean things up. 23 | * 24 | * The datePattern is taken directly from DailyRollingFileAppender DatePattern. 25 | * 26 | * The default datePattern will roll the files at midnight once a day 27 | * ("'.'yyyy-MM-dd") See the documentation for DailyRollingFileAppender for 28 | * other useful patterns. 29 | * 30 | */ 31 | public class DailyKeyOutWriter extends KeyOutWriter { 32 | 33 | private static final String DATE_PATTERN = "'.'yyyy-MM-dd"; 34 | 35 | private final String datePattern; 36 | 37 | @JsonCreator 38 | public DailyKeyOutWriter( 39 | @JsonProperty("typeNames") ImmutableList typeNames, 40 | @JsonProperty("debug") Boolean debugEnabled, 41 | @JsonProperty("outputFile") String outputFile, 42 | @JsonProperty("maxLogFileSize") String maxLogFileSize, 43 | @JsonProperty("maxLogBackupFiles") int maxLogBackupFiles, 44 | @JsonProperty("delimiter") String delimiter, 45 | @JsonProperty("datePattern") String datePattern, 46 | @JsonProperty("settings") Map settings) { 47 | super(typeNames, debugEnabled, outputFile, maxLogFileSize, maxLogBackupFiles, delimiter, settings); 48 | this.datePattern = firstNonNull( 49 | datePattern, 50 | (String) getSettings().get("datePattern"), 51 | DATE_PATTERN 52 | ); 53 | } 54 | 55 | /** 56 | * The maxLogFileSize and maxLogBackupFiles are ignored as per the existing behaviour of DailyKeyOutWriter. 57 | */ 58 | @Override 59 | protected Appender buildLog4jAppender(String fileStr, String maxLogFileSize, Integer maxLogBackupFiles) 60 | throws IOException { 61 | return new DailyRollingFileAppender(new PatternLayout(LOG_PATTERN), fileStr, datePattern); 62 | } 63 | 64 | @Override 65 | protected String buildLoggerName() { 66 | return "DailyKeyOutWriter" + this.hashCode(); 67 | } 68 | 69 | public String getDatePattern() { 70 | return datePattern; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/cli/JmxTransConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.cli; 2 | 3 | import java.io.File; 4 | 5 | public class JmxTransConfiguration { 6 | private boolean continueOnJsonError = false; 7 | private File jsonDirOrFile; 8 | private boolean runEndlessly = false; 9 | /** 10 | * The Quartz server properties. 11 | */ 12 | private String quartPropertiesFile = null; 13 | /** 14 | * The seconds between server job runs. 15 | */ 16 | private int runPeriod = 60; 17 | private boolean help = false; 18 | 19 | 20 | /** 21 | * If it is false, then JmxTrans will stop when one of the JSON 22 | * configuration file is invalid. Otherwise, it will just print an error 23 | * and continue processing. 24 | * 25 | * @param continueOnJsonError 26 | */ 27 | public void setContinueOnJsonError(boolean continueOnJsonError) { 28 | this.continueOnJsonError = continueOnJsonError; 29 | } 30 | 31 | /** 32 | * Sets the json dir or file. 33 | * 34 | * @param jsonDirOrFile the json dir or file 35 | */ 36 | public void setJsonDirOrFile(File jsonDirOrFile) { 37 | this.jsonDirOrFile = jsonDirOrFile; 38 | } 39 | 40 | /** 41 | * If this is true, then this class will execute the main() loop and then 42 | * wait 60 seconds until running again. 43 | * 44 | * @param runEndlessly 45 | */ 46 | public void setRunEndlessly(boolean runEndlessly) { 47 | this.runEndlessly = runEndlessly; 48 | } 49 | 50 | /** 51 | * Sets the quart properties file. 52 | * 53 | * @param quartPropertiesFile the quart properties file 54 | */ 55 | public void setQuartPropertiesFile(String quartPropertiesFile) { 56 | this.quartPropertiesFile = quartPropertiesFile; 57 | } 58 | 59 | /** 60 | * Sets the run period. 61 | * 62 | * @param runPeriod the run period 63 | */ 64 | public void setRunPeriod(int runPeriod) { 65 | this.runPeriod = runPeriod; 66 | } 67 | 68 | /** 69 | * Gets the json dir or file. 70 | * 71 | * @return the json dir or file 72 | */ 73 | public File getJsonDirOrFile() { 74 | return jsonDirOrFile; 75 | } 76 | 77 | public boolean isRunEndlessly() { 78 | return runEndlessly; 79 | } 80 | 81 | public boolean isContinueOnJsonError() { 82 | return continueOnJsonError; 83 | } 84 | 85 | /** 86 | * Gets the quart properties file. 87 | * 88 | * @return the quart properties file 89 | */ 90 | public String getQuartPropertiesFile() { 91 | return quartPropertiesFile; 92 | } 93 | 94 | /** 95 | * Gets the run period. 96 | * 97 | * @return the run period 98 | */ 99 | public int getRunPeriod() { 100 | return runPeriod; 101 | } 102 | 103 | public void setHelp(boolean help) { 104 | this.help = help; 105 | } 106 | 107 | public boolean isHelp() { 108 | return help; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/output/VelocityWriter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.collect.ImmutableList; 6 | import com.googlecode.jmxtrans.model.JmxProcess; 7 | import com.googlecode.jmxtrans.model.Query; 8 | import com.googlecode.jmxtrans.model.Result; 9 | import com.googlecode.jmxtrans.model.Server; 10 | import com.googlecode.jmxtrans.model.ValidationException; 11 | import org.apache.commons.lang.StringUtils; 12 | import org.apache.velocity.app.VelocityEngine; 13 | import org.apache.velocity.runtime.RuntimeConstants; 14 | 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | /** 19 | * This class isn't finished yet. 20 | * 21 | * @author jon 22 | */ 23 | public class VelocityWriter extends BaseOutputWriter { 24 | 25 | @JsonCreator 26 | public VelocityWriter( 27 | @JsonProperty("typeNames") ImmutableList typeNames, 28 | @JsonProperty("debug") Boolean debugEnabled, 29 | @JsonProperty("settings") Map settings) { 30 | super(typeNames, debugEnabled, settings); 31 | } 32 | 33 | public void doWrite(Server server, Query query, ImmutableList results) throws Exception { 34 | // TODO Auto-generated method stub 35 | 36 | } 37 | 38 | public void validateSetup(Server server, Query query) throws ValidationException { 39 | // TODO 40 | } 41 | 42 | /** 43 | * Uses velocity to generate output for a List of JmxProcess. 44 | */ 45 | protected void genVelocityOutput(List processes) { 46 | 47 | // Generate settings XML using Velocity 48 | 49 | // for (JmxProcess process : processes) { 50 | // for (Server server : process.getServers()) { 51 | 52 | // VelocityEngine ve = getVelocityEngine(); 53 | // VelocityContext context = new VelocityContext(); 54 | // context.put("results", ); 55 | // StringWriter writer = new StringWriter(); 56 | // ve.mergeTemplate("conf.zend/crawler_settings.xml", "UTF-8", context, 57 | // writer); 58 | // } 59 | // } 60 | } 61 | 62 | /** 63 | * Sets velocity up to load resources from a list of paths. 64 | */ 65 | protected VelocityEngine getVelocityEngine(List paths) { 66 | VelocityEngine ve = new VelocityEngine(); 67 | ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "file"); 68 | ve.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader"); 69 | ve.setProperty("cp.resource.loader.cache", "true"); 70 | ve.setProperty("cp.resource.loader.path", StringUtils.join(paths, ",")); 71 | ve.setProperty("cp.resource.loader.modificationCheckInterval ", "10"); 72 | ve.setProperty("input.encoding", "UTF-8"); 73 | ve.setProperty("output.encoding", "UTF-8"); 74 | ve.setProperty("runtime.log", ""); 75 | return ve; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/Hibernate.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.googlecode.jmxtrans.JmxTransformer; 6 | import com.googlecode.jmxtrans.guice.JmxTransModule; 7 | import com.googlecode.jmxtrans.model.JmxProcess; 8 | import com.googlecode.jmxtrans.model.Query; 9 | import com.googlecode.jmxtrans.model.Server; 10 | import com.googlecode.jmxtrans.model.output.GraphiteWriter; 11 | import com.googlecode.jmxtrans.util.JsonPrinter; 12 | 13 | /** 14 | * This example shows how to query hibernate for its statistics information. 15 | * 16 | * @author jon 17 | */ 18 | public class Hibernate { 19 | 20 | private static final String GW_HOST = "192.168.192.133"; 21 | private static final JsonPrinter printer = new JsonPrinter(System.out); 22 | 23 | public static void main(String[] args) throws Exception { 24 | 25 | JmxProcess process = new JmxProcess(Server.builder() 26 | .setHost("w2") 27 | .setPort("1099") 28 | .setAlias("w2_hibernate_1099") 29 | .addQuery(Query.builder() 30 | .setObj("org.hibernate.jmx:name=*,type=StatisticsService") 31 | .addAttr("EntityDeleteCount") 32 | .addAttr("EntityInsertCount") 33 | .addAttr("EntityLoadCount") 34 | .addAttr("EntityFetchCount") 35 | .addAttr("EntityUpdateCount") 36 | .addAttr("QueryExecutionCount") 37 | .addAttr("QueryCacheHitCount") 38 | .addAttr("QueryExecutionMaxTime") 39 | .addAttr("QueryCacheMissCount") 40 | .addAttr("QueryCachePutCount") 41 | .addAttr("FlushCount") 42 | .addAttr("ConnectCount") 43 | .addAttr("SecondLevelCacheHitCount") 44 | .addAttr("SecondLevelCacheMissCount") 45 | .addAttr("SecondLevelCachePutCount") 46 | .addAttr("SessionCloseCount") 47 | .addAttr("SessionOpenCount") 48 | .addAttr("CollectionLoadCount") 49 | .addAttr("CollectionFetchCount") 50 | .addAttr("CollectionUpdateCount") 51 | .addAttr("CollectionRemoveCount") 52 | .addAttr("CollectionRecreateCount") 53 | .addAttr("SuccessfulTransactionCount") 54 | .addAttr("TransactionCount") 55 | .addAttr("CloseStatementCount") 56 | .addAttr("PrepareStatementCount") 57 | .addAttr("OptimisticFailureCount") 58 | .addOutputWriter(GraphiteWriter.builder() 59 | .addTypeName("name") 60 | .setDebugEnabled(true) 61 | .setHost(GW_HOST) 62 | .setPort(2003) 63 | .build()) 64 | .build()) 65 | .build()); 66 | 67 | printer.prettyPrint(process); 68 | 69 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 70 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 71 | transformer.executeStandalone(process); 72 | 73 | // for (int i = 0; i < 160; i++) { 74 | // JmxUtils.processServer(server); 75 | // Thread.sleep(1000); 76 | // } 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /javadoc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | jmxlogger javadoc 7 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | <noscript> 61 | <div>JavaScript is disabled on your browser.</div> 62 | </noscript> 63 | <h2>Frame Alert</h2> 64 | <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="overview-summary.html">Non-frame version</a>.</p> 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/InterestingInfo.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.inject.Guice; 5 | import com.google.inject.Injector; 6 | import com.googlecode.jmxtrans.JmxTransformer; 7 | import com.googlecode.jmxtrans.guice.JmxTransModule; 8 | import com.googlecode.jmxtrans.model.JmxProcess; 9 | import com.googlecode.jmxtrans.model.Query; 10 | import com.googlecode.jmxtrans.model.Server; 11 | import com.googlecode.jmxtrans.model.output.GraphiteWriter; 12 | import com.googlecode.jmxtrans.model.output.StdOutWriter; 13 | import com.googlecode.jmxtrans.util.JsonPrinter; 14 | 15 | import java.util.Collections; 16 | import java.util.Map; 17 | 18 | import static com.google.common.collect.Maps.newHashMap; 19 | 20 | /** 21 | * This class produces the json that is in example.json. 22 | * 23 | * @author jon 24 | */ 25 | public class InterestingInfo { 26 | 27 | private static final JsonPrinter printer = new JsonPrinter(System.out); 28 | 29 | public static void main(String[] args) throws Exception { 30 | Server.Builder serverBuilder = Server.builder() 31 | .setHost("w2") 32 | .setPort("1099") 33 | .setNumQueryThreads(2); 34 | 35 | Map settings = newHashMap(); 36 | settings.put(GraphiteWriter.HOST, "192.168.192.133"); 37 | settings.put(GraphiteWriter.PORT, 2003); 38 | 39 | GraphiteWriter gw = GraphiteWriter.builder() 40 | .setHost("192.168.192.133") 41 | .setPort(2003) 42 | .build(); 43 | 44 | StdOutWriter sw = new StdOutWriter(ImmutableList.of(), false, Collections.emptyMap()); 45 | 46 | Query q = Query.builder() 47 | .setObj("java.lang:type=Memory") 48 | .addAttr("HeapMemoryUsage") 49 | .addAttr("NonHeapMemoryUsage") 50 | .addOutputWriters(gw, sw) 51 | .build(); 52 | serverBuilder.addQuery(q); 53 | 54 | Query q2 = Query.builder() 55 | .setObj("java.lang:type=Threading") 56 | .addAttr("DaemonThreadCount") 57 | .addAttr("PeakThreadCount") 58 | .addAttr("ThreadCount") 59 | .addOutputWriters(gw, sw) 60 | .build(); 61 | serverBuilder.addQuery(q2); 62 | 63 | Query q3 = Query.builder() 64 | .setObj("java.lang:name=ConcurrentMarkSweep,type=GarbageCollector") 65 | .addAttr("LastGcInfo") 66 | .addOutputWriters(gw, sw) 67 | .build(); 68 | serverBuilder.addQuery(q3); 69 | 70 | Query q4 = Query.builder() 71 | .setObj("java.lang:name=ParNew,type=GarbageCollector") 72 | .addAttr("LastGcInfo") 73 | .addOutputWriters(gw, sw) 74 | .build(); 75 | serverBuilder.addQuery(q4); 76 | 77 | JmxProcess process = new JmxProcess(serverBuilder.build()); 78 | printer.prettyPrint(process); 79 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 80 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 81 | 82 | transformer.executeStandalone(process); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /javadoc/com/googlecode/jmxtrans/util/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | com.googlecode.jmxtrans.util (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 |

com.googlecode.jmxtrans.util

12 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/tools/yaml2jmxtrans-example.yaml: -------------------------------------------------------------------------------- 1 | # Host/Port Grahpite listens on 2 | # Deprecated in favor of "outputWriters:" configuration below 3 | graphite_host: "graphite.yourdomain.com" 4 | graphite_port: 2003 5 | 6 | # Configure your outputWriters here: 7 | outputWriters: 8 | - "@class": "com.googlecode.jmxtrans.model.output.GraphiteWriter" 9 | settings: 10 | host: "graphite.yourdomain.com" 11 | port: 2003 12 | 13 | # Global port to query JMX on 14 | query_port: 5400 15 | 16 | # Query definitions, every query needs obj, resultAlias, attr 17 | # from jmxtrans format, "name" must be given for referencing 18 | # the query in host sets 19 | queries: 20 | - name: mempool 21 | obj: "java.lang:type=MemoryPool,name=*" 22 | resultAlias: "memorypool" 23 | attr: 24 | - "Usage" 25 | - name: gc 26 | obj: "java.lang:type=GarbageCollector,name=*" 27 | resultAlias: "gc" 28 | attr: 29 | - "CollectionCount" 30 | - "CollectionTime" 31 | - name: hibernate 32 | obj: "Hibernate:type=statistics,name=*" 33 | resultAlias: "hibernate" 34 | attr: 35 | - "QueryExecutionMaxTime" 36 | - "Queries" 37 | - "TransactionCount" 38 | - name: sys 39 | obj: "java.lang:type=OperatingSystem" 40 | resultAlias: "sys" 41 | attr: 42 | - "SystemLoadAverage" 43 | - "AvailableProcessors" 44 | - "TotalPhysicalMemorySize" 45 | - "FreePhysicalMemorySize" 46 | - "TotalSwapSpaceSize" 47 | - "FreeSwapSpaceSize" 48 | - "OpenFileDescriptorCount" 49 | - "MaxFileDescriptorCount" 50 | - name: threads 51 | obj : "java.lang:type=Threading" 52 | resultAlias: "threads" 53 | attr: 54 | - "DaemonThreadCount" 55 | - "PeakThreadCount" 56 | - "ThreadCount" 57 | - "TotalStartedThreadCount" 58 | 59 | # Define named sets of hosts that get the same 60 | # queries 61 | # query_names and hosts is a list 62 | sets: 63 | - setname: set1 64 | username: jmxlogin 65 | password: jmxpassword 66 | query_names: 67 | - mempool 68 | - gc 69 | - hibernate 70 | - sys 71 | - threads 72 | hosts: 73 | - machine01.yourdomain.com 74 | - machine02.yourdomain.com 75 | - machine03.yourdomain.com 76 | - machine04.yourdomain.com 77 | - setname: set2 78 | query_names: 79 | - mempool 80 | - gc 81 | - hibernate 82 | - sys 83 | - threads 84 | hosts: 85 | - machine11.yourdomain.com 86 | - machine12.yourdomain.com 87 | - machine13.yourdomain.com 88 | - machine14.yourdomain.com 89 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/naming/KeyUtilsTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.naming; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Collections; 6 | import java.util.Map; 7 | 8 | import static com.google.common.collect.Maps.newHashMap; 9 | import static com.googlecode.jmxtrans.model.naming.KeyUtils.getTypeNameValueMap; 10 | import static java.util.Arrays.asList; 11 | import static org.assertj.core.api.Assertions.assertThat; 12 | 13 | /** 14 | * @author Zack Radick Date: 1/20/12 15 | * @author Arthur Naseef Date: 02/23/2014 16 | */ 17 | public class KeyUtilsTests { 18 | 19 | @Test 20 | public void testGetTypeNameValueMap() { 21 | assertThat(getTypeNameValueMap(null)).isEmpty(); 22 | assertThat(getTypeNameValueMap("")).isEmpty(); 23 | assertThat(getTypeNameValueMap("x-key1-x")).isEqualTo(makeMap("x-key1-x", "")); 24 | assertThat(getTypeNameValueMap("x-key1-x,x-key2-x")).isEqualTo(makeMap("x-key1-x", "", "x-key2-x", "")); 25 | assertThat(getTypeNameValueMap("x-key1-x=x-value1-x")).isEqualTo(makeMap("x-key1-x", "x-value1-x")); 26 | 27 | assertThat(getTypeNameValueMap("x-key1-x=x-value1-x,y-key2-y=y-value2-y")) 28 | .isEqualTo(makeMap("x-key1-x", "x-value1-x", "y-key2-y", "y-value2-y")); 29 | assertThat(getTypeNameValueMap("x-key1-x=x-value1-x,y-key2-y=y-value2-y,z-key3-z=z-value3-z")) 30 | .isEqualTo(makeMap("x-key1-x", "x-value1-x", "y-key2-y", "y-value2-y", "z-key3-z", "z-value3-z")); 31 | assertThat(getTypeNameValueMap("x-key1-x=x-value1-x,y-key2-y,yy-key2.5-yy=a=1,z-key3-z=z-value3-z")) 32 | .isEqualTo(makeMap("x-key1-x", "x-value1-x", "y-key2-y", "", "yy-key2.5-yy", "a=1", "z-key3-z", "z-value3-z")); 33 | } 34 | 35 | @Test 36 | public void testGetConcatenatedTypeNameValues() { 37 | assertThat(KeyUtils.getConcatedTypeNameValues(null, "a=1")).isNull(); 38 | assertThat(KeyUtils.getConcatedTypeNameValues(Collections.emptyList(), "a=1")).isNull(); 39 | assertThat(KeyUtils.getConcatedTypeNameValues(asList("x-key1-x"), "")).isEmpty(); 40 | assertThat(KeyUtils.getConcatedTypeNameValues(asList("x-key1-x", "y-key2-y"), "")).isEmpty(); 41 | assertThat(KeyUtils.getConcatedTypeNameValues(asList("x-key1-x"), "x-key1-x=x-value1-x")).isEqualTo("x-value1-x"); 42 | assertThat(KeyUtils.getConcatedTypeNameValues(asList("x-key1-x"), "y-key2-y=y-value2-y")).isEmpty(); 43 | assertThat(KeyUtils.getConcatedTypeNameValues(asList("x-key1-x", "y-key2-y"), "x-key1-x=x-value1-x,y-key2-y=y-value2-y")) 44 | .isEqualTo("x-value1-x_y-value2-y"); 45 | } 46 | 47 | /** Convenience method for creating a Map for comparison. */ 48 | private Map makeMap(String... keysAndValues) { 49 | Map result; 50 | int cur; 51 | 52 | result = newHashMap(); 53 | 54 | cur = 0; 55 | while (cur < keysAndValues.length) { 56 | if (cur < keysAndValues.length - 1) { 57 | result.put(keysAndValues[cur], keysAndValues[cur + 1]); 58 | cur += 2; 59 | } else { 60 | result.put(keysAndValues[cur], ""); 61 | cur++; 62 | } 63 | } 64 | 65 | return result; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/monitoring/ManagedGenericKeyedObjectPool.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.monitoring; 2 | 3 | import com.google.common.base.MoreObjects; 4 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; 5 | 6 | import javax.management.MalformedObjectNameException; 7 | import javax.management.ObjectName; 8 | 9 | /** 10 | * The Class ManagedGenericKeyedObjectPool. 11 | * 12 | * @author marcos.lois 13 | */ 14 | public class ManagedGenericKeyedObjectPool implements ManagedGenericKeyedObjectPoolMBean, ManagedObject { 15 | 16 | /** The object name. */ 17 | private ObjectName objectName; 18 | 19 | /** The default pool name. */ 20 | private final String poolName; 21 | 22 | /** The pool. */ 23 | private final GenericKeyedObjectPool pool; 24 | 25 | /** 26 | * The Constructor. 27 | * 28 | * @param pool the pool 29 | * @param poolName the pool name 30 | */ 31 | public ManagedGenericKeyedObjectPool(GenericKeyedObjectPool pool, String poolName) { 32 | this.poolName = MoreObjects.firstNonNull(poolName, "Noname"); 33 | this.pool = pool; 34 | } 35 | 36 | /** 37 | * Gets the pool name. 38 | * 39 | * @return the pool name 40 | */ 41 | public String getPoolName() { 42 | return poolName; 43 | } 44 | 45 | @Override 46 | public ObjectName getObjectName() throws MalformedObjectNameException { 47 | if (objectName == null) { 48 | objectName = new ObjectName("com.googlecode.jmxtrans:Type=GenericKeyedObjectPool,PoolName=" + this.poolName + ",Name=" + this.getClass().getSimpleName() + "@" + this.hashCode()); 49 | } 50 | return objectName; 51 | } 52 | 53 | @Override 54 | public void setObjectName(ObjectName objectName) throws MalformedObjectNameException { 55 | this.objectName = objectName; 56 | } 57 | 58 | @Override 59 | public void setObjectName(String objectName) throws MalformedObjectNameException { 60 | this.objectName = ObjectName.getInstance(objectName); 61 | } 62 | 63 | @Override 64 | public int getMaxActive() { 65 | return pool.getMaxActive(); 66 | } 67 | 68 | @Override 69 | public int getMaxIdle() { 70 | return pool.getMaxIdle(); 71 | } 72 | 73 | @Override 74 | public long getMaxWait() { 75 | return pool.getMaxWait(); 76 | } 77 | 78 | @Override 79 | public int getMinIdle() { 80 | return pool.getMinIdle(); 81 | } 82 | 83 | @Override 84 | public int getNumActive() { 85 | return pool.getNumActive(); 86 | } 87 | 88 | @Override 89 | public int getNumIdle() { 90 | return pool.getNumIdle(); 91 | } 92 | 93 | @Override 94 | public void setMaxActive(int maxActive) { 95 | this.pool.setMaxActive(maxActive); 96 | } 97 | 98 | @Override 99 | public void setMaxIdle(int maxIdle) { 100 | this.pool.setMaxIdle(maxIdle); 101 | } 102 | 103 | @Override 104 | public void setMinIdle(int maxIdle) { 105 | this.pool.setMinIdle(maxIdle); 106 | } 107 | 108 | @Override 109 | public void setMaxWait(long maxWait) { 110 | this.pool.setMaxWait(maxWait); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/ActiveMQ2.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import com.google.inject.Guice; 4 | import com.google.inject.Injector; 5 | import com.googlecode.jmxtrans.JmxTransformer; 6 | import com.googlecode.jmxtrans.guice.JmxTransModule; 7 | import com.googlecode.jmxtrans.model.JmxProcess; 8 | import com.googlecode.jmxtrans.model.Query; 9 | import com.googlecode.jmxtrans.model.Server; 10 | import com.googlecode.jmxtrans.model.output.RRDToolWriter; 11 | import com.googlecode.jmxtrans.util.JsonPrinter; 12 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 13 | 14 | import java.io.File; 15 | 16 | /** 17 | * This example shows how to query an ActiveMQ server for some information. 18 | * 19 | * The point of this example is to show that * works as part of the objectName. 20 | * It also shows that you don't have to set an attribute to get for a query. 21 | * jmxtrans will get all attributes on an object if you don't specify any. 22 | * 23 | * @author jon 24 | */ 25 | public class ActiveMQ2 { 26 | 27 | private static final JsonPrinter jsonPrinter = new JsonPrinter(System.out); 28 | 29 | @SuppressFBWarnings( 30 | value = "DMI_HARDCODED_ABSOLUTE_FILENAME", 31 | justification = "Path to RRD binary is hardcoded as this is example code") 32 | public static void main(String[] args) throws Exception { 33 | RRDToolWriter gw = RRDToolWriter.builder() 34 | .setTemplateFile(new File("memorypool-rrd-template.xml")) 35 | .setOutputFile(new File("target/w2-TEST.rrd")) 36 | .setBinaryPath(new File("/opt/local/bin")) 37 | .setDebugEnabled(true) 38 | .setGenerate(true) 39 | .addTypeName("Destination") 40 | .build(); 41 | 42 | JmxProcess process = new JmxProcess(Server.builder() 43 | .setHost("w2") 44 | .setPort("1105") 45 | .setAlias("w2_activemq_1105") 46 | .addQuery(Query.builder() 47 | .setObj("org.apache.activemq:BrokerName=localhost,Type=Queue,Destination=*") 48 | .addAttr("QueueSize") 49 | .addAttr("MaxEnqueueTime") 50 | .addAttr("MinEnqueueTime") 51 | .addAttr("AverageEnqueueTime") 52 | .addAttr("InFlightCount") 53 | .addAttr("ConsumerCount") 54 | .addAttr("ProducerCount") 55 | .addAttr("DispatchCount") 56 | .addAttr("DequeueCount") 57 | .addAttr("EnqueueCount") 58 | .addOutputWriter(gw) 59 | .build()) 60 | .addQuery(Query.builder() 61 | .setObj("org.apache.activemq:BrokerName=localhost,Type=Topic,Destination=*") 62 | .addAttr("QueueSize") 63 | .addAttr("MaxEnqueueTime") 64 | .addAttr("MinEnqueueTime") 65 | .addAttr("AverageEnqueueTime") 66 | .addAttr("InFlightCount") 67 | .addAttr("ConsumerCount") 68 | .addAttr("ProducerCount") 69 | .addAttr("DispatchCount") 70 | .addAttr("DequeueCount") 71 | .addAttr("EnqueueCount") 72 | .addOutputWriter(gw) 73 | .build()).build()); 74 | jsonPrinter.prettyPrint(process); 75 | 76 | Injector injector = Guice.createInjector(new JmxTransModule(null)); 77 | JmxTransformer transformer = injector.getInstance(JmxTransformer.class); 78 | transformer.executeStandalone(process); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/PropertyResolverTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import org.assertj.core.api.Assertions; 5 | import org.junit.After; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.TreeMap; 14 | 15 | import static com.google.common.collect.Maps.newHashMap; 16 | 17 | /** 18 | * @author lanyonm 19 | */ 20 | public class PropertyResolverTests { 21 | 22 | @Before 23 | public void setSomeProperties() { 24 | System.setProperty("myhost", "w2"); 25 | System.setProperty("myport", "1099"); 26 | } 27 | 28 | @Test 29 | public void testProps() { 30 | String s1 = "${xxx} : ${yyy}"; 31 | String s2 = PropertyResolver.resolveProps(s1); 32 | Assert.assertEquals(s1, s2); 33 | 34 | s1 = "${myhost} : ${myport}"; 35 | s2 = PropertyResolver.resolveProps(s1); 36 | Assert.assertEquals("w2 : 1099", s2); 37 | 38 | s1 = "${myhost} : ${myaltport:2099}"; 39 | s2 = PropertyResolver.resolveProps(s1); 40 | Assert.assertEquals("w2 : 2099", s2); 41 | s1 = "${myhost}:2099"; 42 | s2 = PropertyResolver.resolveProps(s1); 43 | Assert.assertEquals("w2:2099", s2); 44 | 45 | } 46 | 47 | @Test 48 | public void testMap() { 49 | TreeMap map = new TreeMap(); 50 | map.put("host", "${myhost}"); 51 | map.put("port", "${myport}"); 52 | map.put("count", 10); 53 | 54 | ImmutableMap resolved = PropertyResolver.resolveMap(map); 55 | Assertions.assertThat(resolved).containsEntry("host", "w2"); 56 | Assertions.assertThat(resolved).containsEntry("port", "1099"); 57 | Assertions.assertThat(resolved).containsEntry("count", 10); 58 | } 59 | 60 | @Test 61 | public void testResolveMap() { 62 | Map map = newHashMap(); 63 | Assertions.assertThat(System.getProperty("myhost")).isEqualTo("w2"); 64 | Assertions.assertThat(System.getProperty("mihost")).isNull(); 65 | 66 | map.put("a", "${myhost}"); 67 | map.put("b", "${mihost:w4}"); 68 | map.put("c", "${mybean:defbean}.${mybean2:defbean2}"); 69 | map.put("d", "${myhost:defbean}.${mybean2:defbean2}"); 70 | 71 | ImmutableMap resolved = PropertyResolver.resolveMap(map); 72 | 73 | Assertions.assertThat(resolved).containsEntry("a", "w2"); 74 | Assertions.assertThat(resolved).containsEntry("b", "w4"); 75 | Assertions.assertThat(resolved).containsEntry("c", "defbean.defbean2"); 76 | Assertions.assertThat(resolved).containsEntry("d", "w2.defbean2"); 77 | } 78 | 79 | @Test 80 | public void testList() { 81 | List list = new ArrayList(); 82 | list.add("${myhost}"); 83 | list.add("${myport}"); 84 | list.add("count"); 85 | 86 | List resolvedList = PropertyResolver.resolveList(list); 87 | Assert.assertEquals("w2", resolvedList.get(0)); 88 | Assert.assertEquals("1099", resolvedList.get(1)); 89 | Assert.assertEquals("count", resolvedList.get(2)); 90 | } 91 | 92 | @After 93 | public void removeSystemProperties() { 94 | System.clearProperty("myhost"); 95 | System.clearProperty("myport"); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/jmx/JmxQueryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.jmx; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.management.AttributeList; 8 | import javax.management.InstanceNotFoundException; 9 | import javax.management.IntrospectionException; 10 | import javax.management.MBeanAttributeInfo; 11 | import javax.management.MBeanInfo; 12 | import javax.management.MBeanServerConnection; 13 | import javax.management.ObjectInstance; 14 | import javax.management.ObjectName; 15 | import javax.management.ReflectionException; 16 | import java.io.IOException; 17 | import java.rmi.UnmarshalException; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import com.googlecode.jmxtrans.model.OutputWriter; 22 | import com.googlecode.jmxtrans.model.Query; 23 | import com.googlecode.jmxtrans.model.Result; 24 | import com.googlecode.jmxtrans.model.Server; 25 | 26 | public class JmxQueryProcessor { 27 | private final Logger log = LoggerFactory.getLogger(getClass()); 28 | 29 | /** 30 | * Responsible for processing individual Queries. 31 | */ 32 | public void processQuery(MBeanServerConnection mbeanServer, Server server, Query query) throws Exception { 33 | ObjectName oName = new ObjectName(query.getObj()); 34 | for (ObjectName queryName : mbeanServer.queryNames(oName, null)) { 35 | ImmutableList results = fetchResults(mbeanServer, query, queryName); 36 | runOutputWritersForQuery(server, query, results); 37 | } 38 | } 39 | 40 | private ImmutableList fetchResults(MBeanServerConnection mbeanServer, Query query, ObjectName queryName) throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException { 41 | MBeanInfo info = mbeanServer.getMBeanInfo(queryName); 42 | ObjectInstance oi = mbeanServer.getObjectInstance(queryName); 43 | 44 | List attributes; 45 | if (query.getAttr().isEmpty()) { 46 | attributes = new ArrayList(); 47 | for (MBeanAttributeInfo attrInfo : info.getAttributes()) { 48 | attributes.add(attrInfo.getName()); 49 | } 50 | } else { 51 | attributes = query.getAttr(); 52 | } 53 | 54 | ImmutableList results = ImmutableList.of(); 55 | try { 56 | if (attributes.size() > 0) { 57 | log.debug("Executing queryName [{}] from query [{}]", queryName.getCanonicalName(), query); 58 | 59 | AttributeList al = mbeanServer.getAttributes(queryName, attributes.toArray(new String[attributes.size()])); 60 | 61 | results = new JmxResultProcessor(query, oi, al.asList(), info.getClassName()).getResults(); 62 | } 63 | } catch (UnmarshalException ue) { 64 | if ((ue.getCause() != null) && (ue.getCause() instanceof ClassNotFoundException)) { 65 | log.debug("Bad unmarshall, continuing. This is probably ok and due to something like this: " 66 | + "http://ehcache.org/xref/net/sf/ehcache/distribution/RMICacheManagerPeerListener.html#52", ue.getMessage()); 67 | } 68 | } 69 | return results; 70 | } 71 | 72 | private void runOutputWritersForQuery(Server server, Query query, ImmutableList results) throws Exception { 73 | for (OutputWriter writer : query.getOutputWriters()) { 74 | writer.doWrite(server, query, results); 75 | } 76 | log.debug("Finished running outputWriters for query: {}", query); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/output/Log4JWriter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.collect.ImmutableList; 6 | import com.googlecode.jmxtrans.model.Query; 7 | import com.googlecode.jmxtrans.model.Result; 8 | import com.googlecode.jmxtrans.model.Server; 9 | import com.googlecode.jmxtrans.model.ValidationException; 10 | import com.googlecode.jmxtrans.model.naming.KeyUtils; 11 | import com.googlecode.jmxtrans.model.naming.StringUtils; 12 | import org.apache.log4j.Logger; 13 | import org.apache.log4j.MDC; 14 | 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.Map.Entry; 18 | 19 | 20 | /** 21 | * A writer for Log4J. It may be a nice way to send JMX metrics to Logstash for example.

22 | *

23 | * Here is an example of MDC variables that are set by this class.

server: localhost_9003
metric: 24 | * sun_management_MemoryImpl.HeapMemoryUsage_committed
value: 1251999744
resultAlias: myHeapMemoryUsage 25 | *
attributeName: HeapMemoryUsage
key: committed
epoch: 1388343325728
26 | * 27 | * @author Yannick Robin 28 | */ 29 | public class Log4JWriter extends BaseOutputWriter { 30 | private final Logger log; 31 | private final String logger; 32 | 33 | @JsonCreator 34 | public Log4JWriter( 35 | @JsonProperty("typeNames") ImmutableList typeNames, 36 | @JsonProperty("debug") Boolean debugEnabled, 37 | @JsonProperty("logger") String logger, 38 | @JsonProperty("settings") Map settings) { 39 | super(typeNames, debugEnabled, settings); 40 | this.logger = firstNonNull(logger, (String) getSettings().get("logger"), "Log4JWriter"); 41 | this.log = Logger.getLogger("Log4JWriter." + this.logger); 42 | } 43 | 44 | public void validateSetup(Server server, final Query query) throws ValidationException {} 45 | 46 | /** 47 | * Set the log context and log 48 | */ 49 | public void doWrite(Server server, final Query query, ImmutableList results) throws Exception { 50 | final List typeNames = getTypeNames(); 51 | 52 | for (final Result result : results) { 53 | final Map resultValues = result.getValues(); 54 | if (resultValues != null) { 55 | for (final Entry values : resultValues.entrySet()) { 56 | if (NumberUtils.isNumeric(values.getValue())) { 57 | String alias; 58 | if (server.getAlias() != null) { 59 | alias = server.getAlias(); 60 | } else { 61 | alias = server.getHost() + "_" + server.getPort(); 62 | alias = StringUtils.cleanupStr(alias); 63 | } 64 | 65 | MDC.put("server", alias); 66 | MDC.put("metric", KeyUtils.getKeyString(server, query, result, values, typeNames, null)); 67 | MDC.put("value", values.getValue()); 68 | if (result.getClassNameAlias() != null) { 69 | MDC.put("resultAlias", result.getClassNameAlias()); 70 | } 71 | MDC.put("attributeName", result.getAttributeName()); 72 | MDC.put("key", values.getKey()); 73 | MDC.put("Epoch", String.valueOf(result.getEpoch())); 74 | log.info(""); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | 81 | public String getLogger() { 82 | return logger; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/util/SignalInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import sun.misc.Signal; 4 | import sun.misc.SignalHandler; 5 | 6 | public abstract class SignalInterceptor { 7 | 8 | protected SignalInterceptor() { 9 | } 10 | 11 | /** 12 | *

13 | * Register for the given signal. Note that the signal name should 14 | * not begin with SIG. For example, if you are interested in 15 | * SIGTERM, you should call register("TERM"). 16 | *

17 | *

18 | * If the registration fails for any reason, a 19 | * SignalInterceptorException will be thrown. This is usually 20 | * caused by one of the following conditions: 21 | *

22 | *
    23 | *
  • The sun.misc.Signal* classes are not available (e.g. you 24 | * are not using Sun's JVM).
  • 25 | *
  • signame is not a valid trappable signal name on this OS 26 | * (e.g. KILL can't be trapped, HUP does not exist on Windows) 27 | *
  • 28 | *
  • The JVM refuses to let you trap signame because it is 29 | * already being used for some other important purpose (e.g. QUIT 30 | * and/or BREAK cause the JVM to print diagnostic output).
  • 31 | *
32 | */ 33 | protected void register(String signame) throws SignalInterceptorException { 34 | try { 35 | new SignalInterceptorHelper(signame, this); 36 | } catch (Throwable e) { 37 | throw new SignalInterceptorException(signame, e); 38 | } 39 | } 40 | 41 | /** 42 | * A wrapper around register(String) which never throws an 43 | * exception. Instead, it returns true if registration 44 | * succeeded, and false if it failed. 45 | */ 46 | protected boolean registerQuietly(String signame) { 47 | try { 48 | register(signame); 49 | } catch (Throwable e) { 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | /** 56 | * Handle the given signal (which you had previously registered for). If 57 | * this method return false, or throws an exception, subsequent handlers in 58 | * the chain will not be called. 59 | */ 60 | protected abstract boolean handle(String signame); 61 | 62 | /** 63 | *

64 | * Private helper class for SignalInterceptor. 65 | *

66 | *

67 | * This class exists separately from SignalInterceptor to 68 | * permit graceful handling of LinkageErrors when the 69 | * sun.misc.Signal* classes don't exist. 70 | *

71 | */ 72 | private static class SignalInterceptorHelper implements SignalHandler { 73 | 74 | private final SignalHandler oldHandler; 75 | 76 | private final SignalInterceptor interceptor; 77 | 78 | SignalInterceptorHelper(String signame, SignalInterceptor interceptor) { 79 | this.interceptor = interceptor; 80 | Signal signal = new Signal(signame); 81 | oldHandler = Signal.handle(signal, this); 82 | } 83 | 84 | public void handle(Signal sig) { 85 | if (interceptor.handle(sig.getName()) && (oldHandler != null)) { 86 | oldHandler.handle(sig); 87 | } 88 | } 89 | } 90 | 91 | @SuppressWarnings("serial") 92 | private static class SignalInterceptorException extends Exception { 93 | 94 | SignalInterceptorException(String signal, Throwable cause) { 95 | super("Unable to register for SIG" + signal, cause); 96 | } 97 | 98 | } 99 | } -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/output/GangliaWriterTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.googlecode.jmxtrans.model.Query; 4 | import com.googlecode.jmxtrans.model.Server; 5 | import com.googlecode.jmxtrans.model.ValidationException; 6 | import info.ganglia.gmetric4j.gmetric.GMetric; 7 | import info.ganglia.gmetric4j.gmetric.GMetricSlope; 8 | import org.junit.Test; 9 | 10 | import static junit.framework.Assert.assertEquals; 11 | 12 | /** 13 | * Tests for {@link GangliaWriter}. 14 | * 15 | * @author Zack Radick 16 | * @author Julien Nicoulaud 17 | */ 18 | public class GangliaWriterTests { 19 | 20 | /** Test validation when no parameter is set. */ 21 | @Test(expected = NullPointerException.class) 22 | public void testValidationWithoutSettings() throws ValidationException { 23 | GangliaWriter.builder().build(); 24 | } 25 | 26 | /** Test validation when only required parameters are set. */ 27 | @Test 28 | public void testValidationMinimalSettings() throws ValidationException { 29 | GangliaWriter writer = GangliaWriter.builder().setHost("192.168.1.144").build(); 30 | Query test = Query.builder() 31 | .setObj("test") 32 | .build(); 33 | Server server = Server.builder().setHost("localhost").setPort("123").build(); 34 | writer.validateSetup(server, test); 35 | assertEquals("192.168.1.144", writer.getHost()); 36 | assertEquals(GangliaWriter.DEFAULT_PORT, writer.getPort()); 37 | assertEquals(GangliaWriter.DEFAULT_ADDRESSING_MODE.name(), writer.getAddressingMode()); 38 | assertEquals(GangliaWriter.DEFAULT_TTL, writer.getTtl()); 39 | assertEquals(GangliaWriter.DEFAULT_V31, writer.isV31()); 40 | assertEquals(GangliaWriter.DEFAULT_UNITS, writer.getUnits()); 41 | assertEquals(GangliaWriter.DEFAULT_SLOPE, writer.getSlope()); 42 | assertEquals(GangliaWriter.DEFAULT_TMAX, writer.getTmax()); 43 | assertEquals(GangliaWriter.DEFAULT_DMAX, writer.getDmax()); 44 | assertEquals(GangliaWriter.DEFAULT_GROUP_NAME, writer.getGroupName()); 45 | } 46 | 47 | /** Test validation when all parameters are set. */ 48 | @Test 49 | public void testValidationAllSettings() throws ValidationException { 50 | GangliaWriter writer = GangliaWriter.builder() 51 | .setHost("192.168.1.144") 52 | .setPort(25654) 53 | .setAddressingMode("MULTICAST") 54 | .setTtl(4) 55 | .setV31(false) 56 | .setUnits("km/h") 57 | .setSlope("NEGATIVE") 58 | .setTmax(354) 59 | .setDmax(24) 60 | .setGroupName("dummy") 61 | .build(); 62 | 63 | Query test = Query.builder() 64 | .setObj("test") 65 | .build(); 66 | Server server = Server.builder().setHost("localhost").setPort("123").build(); 67 | writer.validateSetup(server, test); 68 | assertEquals("192.168.1.144", writer.getHost()); 69 | assertEquals(25654, writer.getPort()); 70 | assertEquals(GMetric.UDPAddressingMode.MULTICAST.name(), writer.getAddressingMode()); 71 | assertEquals(4, writer.getTtl()); 72 | assertEquals(false, writer.isV31()); 73 | assertEquals("km/h", writer.getUnits()); 74 | assertEquals(GMetricSlope.NEGATIVE, writer.getSlope()); 75 | assertEquals(354, writer.getTmax()); 76 | assertEquals(24, writer.getDmax()); 77 | assertEquals("dummy", writer.getGroupName()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/output/BaseOutputWriterTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.googlecode.jmxtrans.model.Query; 5 | import com.googlecode.jmxtrans.model.Result; 6 | import com.googlecode.jmxtrans.model.Server; 7 | import com.googlecode.jmxtrans.model.ValidationException; 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import java.util.Collections; 13 | import java.util.Map; 14 | 15 | import static com.google.common.collect.Maps.newHashMap; 16 | import static com.googlecode.jmxtrans.model.output.Settings.getIntSetting; 17 | import static com.googlecode.jmxtrans.model.output.Settings.getIntegerSetting; 18 | import static com.googlecode.jmxtrans.model.output.Settings.getStringSetting; 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | /** 22 | * @author Zack Radick Date: 1/20/12 23 | */ 24 | public class BaseOutputWriterTests { 25 | 26 | @Before 27 | public void setUpOutputWriter() { 28 | System.setProperty("myHost", "w2"); 29 | System.setProperty("myPort", "123"); 30 | } 31 | 32 | @Test(expected = NullPointerException.class) 33 | public void cannotHaveNullValueInSettings() { 34 | BaseOutputWriter outputWriter = new TestBaseOuputWriter(); 35 | Map settings = newHashMap(); 36 | settings.put("null", null); 37 | outputWriter.setSettings(settings); 38 | } 39 | 40 | @Test 41 | public void propertyResolvedIntegerSettings() { 42 | BaseOutputWriter outputWriter = new TestBaseOuputWriter(); 43 | Map settings = newHashMap(); 44 | settings.put("resolvedPort", "${myPort}"); 45 | outputWriter.setSettings(settings); 46 | 47 | assertThat(getIntegerSetting(outputWriter.getSettings(), "resolvedPort", 0)).isEqualTo(123); 48 | } 49 | 50 | @Test 51 | public void propertyResolvedIntSettings() { 52 | BaseOutputWriter outputWriter = new TestBaseOuputWriter(); 53 | Map settings = newHashMap(); 54 | settings.put("resolvedPort", "${myPort}"); 55 | outputWriter.setSettings(settings); 56 | 57 | assertThat(getIntSetting(outputWriter.getSettings(), "resolvedPort", 0)).isEqualTo(123); 58 | } 59 | 60 | @Test 61 | public void propertyResolvedStringSettings() { 62 | BaseOutputWriter outputWriter = new TestBaseOuputWriter(); 63 | Map settings = newHashMap(); 64 | settings.put("resolvedHost", "${myHost}"); 65 | settings.put("resolvedPort", "${myPort}"); 66 | outputWriter.setSettings(settings); 67 | 68 | assertThat(getStringSetting(outputWriter.getSettings(), "resolvedHost", "")).isEqualTo("w2"); 69 | assertThat(getStringSetting(outputWriter.getSettings(), "resolvedPort", "")).isEqualTo("123"); 70 | } 71 | 72 | @After 73 | public void removeSystemProperties() { 74 | System.clearProperty("myHost"); 75 | System.clearProperty("myPort"); 76 | } 77 | 78 | private static final class TestBaseOuputWriter extends BaseOutputWriter { 79 | public TestBaseOuputWriter() { 80 | super(ImmutableList.of(), false, Collections.emptyMap()); 81 | } 82 | 83 | @Override 84 | public void doWrite(Server server, Query query, ImmutableList results) throws Exception { 85 | throw new UnsupportedOperationException("doWrite() not implemented for TestBaseOutputWriter."); 86 | } 87 | 88 | @Override 89 | public void validateSetup(Server server, Query query) throws ValidationException { 90 | throw new UnsupportedOperationException("validateSetup() not implemented for TestBaseOutputWriter."); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/cli/CliArgumentParser.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.cli; 2 | 3 | import org.apache.commons.cli.CommandLine; 4 | import org.apache.commons.cli.CommandLineParser; 5 | import org.apache.commons.cli.GnuParser; 6 | import org.apache.commons.cli.HelpFormatter; 7 | import org.apache.commons.cli.Option; 8 | import org.apache.commons.cli.Options; 9 | 10 | import java.io.File; 11 | 12 | public class CliArgumentParser { 13 | /** 14 | * Parse the options given on the command line. 15 | * 16 | * @param args 17 | */ 18 | public JmxTransConfiguration parseOptions(String[] args) throws OptionsException, org.apache.commons.cli.ParseException { 19 | CommandLineParser parser = new GnuParser(); 20 | CommandLine cl = parser.parse(getOptions(), args); 21 | Option[] options = cl.getOptions(); 22 | 23 | JmxTransConfiguration configuration = new JmxTransConfiguration(); 24 | 25 | for (Option option : options) { 26 | if (option.getOpt().equals("c")) { 27 | configuration.setContinueOnJsonError(Boolean.parseBoolean(option.getValue())); 28 | } else if (option.getOpt().equals("j")) { 29 | File jsonDir = new File(option.getValue()); 30 | if (jsonDir.exists() && jsonDir.isDirectory()) { 31 | configuration.setJsonDirOrFile(jsonDir); 32 | } else { 33 | throw new OptionsException("Path to json directory is invalid: " + jsonDir); 34 | } 35 | } else if (option.getOpt().equals("f")) { 36 | File jsonFile = new File(option.getValue()); 37 | if (jsonFile.exists() && jsonFile.isFile()) { 38 | configuration.setJsonDirOrFile(jsonFile); 39 | } else { 40 | throw new OptionsException("Path to json file is invalid: " + jsonFile); 41 | } 42 | } else if (option.getOpt().equals("e")) { 43 | configuration.setRunEndlessly(true); 44 | } else if (option.getOpt().equals("q")) { 45 | File quartzConfigFile = new File(option.getValue()); 46 | if (quartzConfigFile.exists() && quartzConfigFile.isFile()) { 47 | configuration.setQuartPropertiesFile(option.getValue()); 48 | } else { 49 | throw new OptionsException("Could not find path to the quartz properties file: " 50 | + quartzConfigFile.getAbsolutePath()); 51 | } 52 | } else if (option.getOpt().equals("s")) { 53 | try { 54 | configuration.setRunPeriod(Integer.parseInt(option.getValue())); 55 | } catch (NumberFormatException nfe) { 56 | throw new OptionsException("Seconds between server job runs must be an integer"); 57 | } 58 | } else if (option.getOpt().equals("h")) { 59 | HelpFormatter formatter = new HelpFormatter(); 60 | formatter.printHelp("java -jar jmxtrans-all.jar", getOptions()); 61 | configuration.setHelp(true); 62 | } 63 | } 64 | if ((!configuration.isHelp()) && (configuration.getJsonDirOrFile() == null)) { 65 | throw new OptionsException("Please specify either the -f or -j option."); 66 | } 67 | return configuration; 68 | } 69 | 70 | private Options getOptions() { 71 | Options options = new Options(); 72 | options.addOption("c", true, "Continue processing even if one of the JSON configuration file is invalid."); 73 | options.addOption("j", true, "Directory where json configuration is stored. Default is ."); 74 | options.addOption("f", true, "A single json file to execute."); 75 | options.addOption("e", false, "Run endlessly. Default false."); 76 | options.addOption("q", true, "Path to quartz configuration file."); 77 | options.addOption("s", true, "Seconds between server job runs (not defined with cron). Default: 60"); 78 | options.addOption("h", false, "Help"); 79 | return options; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/util/WatchDir.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import name.pachler.nio.file.ClosedWatchServiceException; 4 | import name.pachler.nio.file.FileSystems; 5 | import name.pachler.nio.file.Path; 6 | import name.pachler.nio.file.Paths; 7 | import name.pachler.nio.file.StandardWatchEventKind; 8 | import name.pachler.nio.file.WatchEvent; 9 | import name.pachler.nio.file.WatchKey; 10 | import name.pachler.nio.file.WatchService; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | import static com.google.common.collect.Maps.newHashMap; 20 | 21 | /** 22 | * Watch a directory (or tree) for changes to files. 23 | */ 24 | public class WatchDir extends Thread { 25 | private static final Logger log = LoggerFactory.getLogger(WatchDir.class); 26 | 27 | private final WatchService watchService; 28 | private final WatchedCallback watched; 29 | private final Map keys; 30 | 31 | /** 32 | * 33 | */ 34 | public WatchDir(File dir, WatchedCallback watched) throws IOException { 35 | this.watched = watched; 36 | this.keys = newHashMap(); 37 | watchService = FileSystems.getDefault().newWatchService(); 38 | Path watchedPath = Paths.get(dir.getAbsolutePath()); 39 | WatchKey signalledKey = watchedPath.register(watchService, StandardWatchEventKind.ENTRY_CREATE, StandardWatchEventKind.ENTRY_DELETE, StandardWatchEventKind.ENTRY_MODIFY); 40 | // Store the path that we're watching, so we can later retrieve it and build a proper path to the file 41 | keys.put(signalledKey, watchedPath); 42 | } 43 | 44 | /** */ 45 | @Override 46 | public void run() { 47 | for (;;) { 48 | // take() will block until a file has been created/deleted 49 | WatchKey signalledKey; 50 | try { 51 | signalledKey = watchService.take(); 52 | } catch (InterruptedException ix) { 53 | // we'll ignore being interrupted 54 | continue; 55 | } catch (ClosedWatchServiceException cwse) { 56 | // other thread closed watch service 57 | log.debug("Watch service closed, terminating."); 58 | break; 59 | } 60 | 61 | // get list of events from key 62 | List> list = signalledKey.pollEvents(); 63 | 64 | // VERY IMPORTANT! call reset() AFTER pollEvents() to allow the 65 | // key to be reported again by the watch service 66 | signalledKey.reset(); 67 | 68 | // Retrieve the path for the files from the key created above; this is used by the 69 | // resolver below. 70 | Path dir = keys.get(signalledKey); 71 | try { 72 | for (WatchEvent e : list) { 73 | if (e.kind() == StandardWatchEventKind.ENTRY_CREATE) { 74 | Path context = (Path) e.context(); 75 | Path fullPath = dir.resolve(context); 76 | watched.fileAdded(new File(fullPath.toString())); 77 | } else if (e.kind() == StandardWatchEventKind.ENTRY_DELETE) { 78 | Path context = (Path) e.context(); 79 | Path fullPath = dir.resolve(context); 80 | watched.fileDeleted(new File(fullPath.toString())); 81 | } else if (e.kind() == StandardWatchEventKind.ENTRY_MODIFY) { 82 | Path context = (Path) e.context(); 83 | Path fullPath = dir.resolve(context); 84 | watched.fileModified(new File(fullPath.toString())); 85 | } 86 | } 87 | } catch (Exception e) { 88 | throw new RuntimeException(e); 89 | } 90 | 91 | } 92 | } 93 | 94 | /** */ 95 | public void stopService() throws IOException { 96 | watchService.close(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/ServerTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertFalse; 7 | import static org.junit.Assert.assertNotSame; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | /** 11 | * @author lanyonm 12 | */ 13 | public class ServerTests { 14 | 15 | @Test 16 | public void testGetUrl() { 17 | // test with host and port 18 | Server server = Server.builder().setHost("mysys.mydomain").setPort("8004").build(); 19 | assertEquals("should be 'service:jmx:rmi:///jndi/rmi://mysys.mydomain:8004/jmxrmi'", "service:jmx:rmi:///jndi/rmi://mysys.mydomain:8004/jmxrmi", server.getUrl()); 20 | // test with url 21 | server = Server.builder() 22 | .setUrl("service:jmx:remoting-jmx://mysys.mydomain:8004") 23 | .build(); 24 | assertEquals("should be 'service:jmx:remoting-jmx://mysys.mydomain:8004'", "service:jmx:remoting-jmx://mysys.mydomain:8004", server.getUrl()); 25 | 26 | server = Server.builder() 27 | .setUrl("service:jmx:rmi:///jndi/rmi://mysys.mydomain:8004/jmxrmi") 28 | .build(); 29 | assertEquals("shold be 'service:jmx:rmi:///jndi/rmi://mysys.mydomain:8004/jmxrmi'", "service:jmx:rmi:///jndi/rmi://mysys.mydomain:8004/jmxrmi", server.getUrl()); 30 | } 31 | 32 | @Test 33 | public void testGetHostAndPortFromUrl() { 34 | Server server = Server.builder() 35 | .setUrl("service:jmx:remoting-jmx://mysys.mydomain:8004") 36 | .build(); 37 | assertEquals("server host should be 'mysys.mydomain'", "mysys.mydomain", server.getHost()); 38 | assertEquals("server port should be '8004'", "8004", server.getPort()); 39 | // test with a different url 40 | server = Server.builder() 41 | .setUrl("service:jmx:rmi:///jndi/rmi://mysys.mydomain:8004/jmxrmi") 42 | .build(); 43 | assertEquals("server host should be 'mysys.mydomain'", "mysys.mydomain", server.getHost()); 44 | assertEquals("server port should be '8004'", "8004", server.getPort()); 45 | } 46 | 47 | @Test 48 | public void testEquals() { 49 | Server s1 = Server.builder() 50 | .setAlias("alias") 51 | .setHost("host") 52 | .setPort("8008") 53 | .setCronExpression("cron") 54 | .setNumQueryThreads(123) 55 | .setPassword("pass") 56 | .setUsername("user") 57 | .build(); 58 | 59 | Server s2 = Server.builder() 60 | .setAlias("alias") 61 | .setHost("host") 62 | .setPort("8008") 63 | .setCronExpression("cron") 64 | .setNumQueryThreads(123) 65 | .setPassword("pass") 66 | .setUsername("user") 67 | .build(); 68 | 69 | Server s3 = Server.builder() 70 | .setAlias("alias") 71 | .setHost("host3") 72 | .setPort("8008") 73 | .setCronExpression("cron") 74 | .setNumQueryThreads(123) 75 | .setPassword("pass") 76 | .setUsername("user") 77 | .build(); 78 | 79 | assertFalse(s1.equals(null)); 80 | assertEquals(s1, s1); 81 | assertFalse(s1.equals("hi")); 82 | assertEquals(s1, s2); 83 | assertTrue(s1.equals(s2)); 84 | assertNotSame(s1, s3); 85 | } 86 | 87 | @Test 88 | public void testHashCode() { 89 | Server s1 = Server.builder() 90 | .setUrl("service:jmx:remoting-jmx://mysys.mydomain:8004") 91 | .build(); 92 | Server s2 = Server.builder() 93 | .setUrl("service:jmx:remoting-jmx://mysys.mydomain:8004") 94 | .build(); 95 | Server s3 = Server.builder() 96 | .setUrl("service:jmx:remoting-jmx://mysys3.mydomain:8004") 97 | .build(); 98 | assertEquals(s1.hashCode(), s2.hashCode()); 99 | assertFalse(s1.hashCode() == s3.hashCode()); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/example/TreeWalker.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.example; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.management.Attribute; 7 | import javax.management.AttributeList; 8 | import javax.management.MBeanAttributeInfo; 9 | import javax.management.MBeanInfo; 10 | import javax.management.MBeanServerConnection; 11 | import javax.management.ObjectName; 12 | import javax.management.openmbean.CompositeDataSupport; 13 | import javax.management.remote.JMXConnector; 14 | import java.io.IOException; 15 | import java.text.NumberFormat; 16 | import java.util.Arrays; 17 | import java.util.Set; 18 | 19 | import com.googlecode.jmxtrans.model.Server; 20 | 21 | /** 22 | * Walks a JMX tree and prints out all of the attribute values. 23 | * 24 | * Does not use the JmxTrans api. This is just more of a proof of concept and 25 | * shows how utterly broken and stupid the jmx api is. The fact that you have to 26 | * pass in null,null into MBeanServerConnection.queryNames() is utterly stupid. 27 | * 28 | * This code was borrowed from the munin jmxquery plugin which I had to jad 29 | * decompile since I couldn't find the source to it. 30 | * 31 | * @author jon 32 | */ 33 | public class TreeWalker { 34 | 35 | private static final Logger log = LoggerFactory.getLogger(TreeWalker.class); 36 | 37 | public static void main(String[] args) throws Exception { 38 | Server server = Server.builder().setHost("localhost").setPort("1099").build(); 39 | 40 | JMXConnector conn = null; 41 | try { 42 | conn = server.getServerConnection(); 43 | MBeanServerConnection mbeanServer = conn.getMBeanServerConnection(); 44 | 45 | TreeWalker tw = new TreeWalker(); 46 | tw.walkTree(mbeanServer); 47 | } catch (IOException e) { 48 | log.error("Problem processing queries for server: " + server.getHost() + ":" + server.getPort(), e); 49 | } finally { 50 | if (conn != null) { 51 | conn.close(); 52 | } 53 | } 54 | } 55 | 56 | public void walkTree(MBeanServerConnection connection) throws Exception { 57 | 58 | // key here is null, null returns everything! 59 | Set mbeans = connection.queryNames(null, null); 60 | for (ObjectName name : mbeans) { 61 | MBeanInfo info = connection.getMBeanInfo(name); 62 | MBeanAttributeInfo[] attrs = info.getAttributes(); 63 | String[] attrNames = new String[attrs.length]; 64 | for (int i = 0; i < attrs.length; i++) { 65 | attrNames[i] = attrs[i].getName(); 66 | } 67 | try { 68 | AttributeList attributes = connection.getAttributes(name, attrNames); 69 | for (Attribute attribute : attributes.asList()) { 70 | output(name.getCanonicalName() + "%" + attribute.getName(), attribute.getValue()); 71 | } 72 | } catch (Exception e) { 73 | log.error("error getting " + name + ":" + e.getMessage(), e); 74 | } 75 | } 76 | } 77 | 78 | public void output(String name, Object attr) { 79 | CompositeDataSupport cds; 80 | if ((attr instanceof CompositeDataSupport)) { 81 | cds = (CompositeDataSupport) attr; 82 | for (String key : cds.getCompositeType().keySet()) { 83 | log.info(name + "." + key + ".value " + format(cds.get(key))); 84 | } 85 | } else { 86 | log.info(name + ".value " + format(attr)); 87 | } 88 | } 89 | 90 | public String format(Object value) { 91 | if (value == null) { 92 | return null; 93 | } else if ((value instanceof String)) { 94 | return (String) value; 95 | } else if ((value instanceof Number)) { 96 | NumberFormat f = NumberFormat.getInstance(); 97 | f.setMaximumFractionDigits(2); 98 | f.setGroupingUsed(false); 99 | return f.format(value); 100 | } else if ((value instanceof Object[])) { 101 | return Integer.toString(Arrays.asList((Object[]) value).size()); 102 | } 103 | return value.toString(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/util/WatchDirTest.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.util; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Rule; 6 | import org.junit.Test; 7 | import org.junit.rules.TemporaryFolder; 8 | 9 | import java.io.File; 10 | import java.io.FileOutputStream; 11 | import java.io.IOException; 12 | import java.io.OutputStream; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.mockito.Mockito.atLeastOnce; 16 | import static org.mockito.Mockito.spy; 17 | import static org.mockito.Mockito.verify; 18 | 19 | public class WatchDirTest { 20 | 21 | /** 22 | * Wait time before assertions in milliseconds. 23 | * 24 | * Watch events can take some time to propagate. Synchronization is used to 25 | * signal when verify operations can occur. But in case of a failed test, 26 | * we will wait FILE_OPERATION_TIMEOUT before throwing an error. 27 | **/ 28 | private static final int FILE_OPERATION_TIMEOUT = 5000; 29 | 30 | @Rule 31 | public TemporaryFolder watchedDir = new TemporaryFolder(); 32 | 33 | private WatchDir watchDir; 34 | 35 | private WatchedCallback callback; 36 | private Object synchro; 37 | 38 | @Before 39 | public void createWatchedDir() throws IOException { 40 | synchro = new Object(); 41 | callback = spy(new MockWatchedCallback(synchro)); 42 | watchDir = new WatchDir(watchedDir.getRoot(), callback); 43 | watchDir.start(); 44 | } 45 | 46 | @Test 47 | public void createdFileIsDetected() throws Exception { 48 | File toCreate = watchedDir.newFile("created"); 49 | waitForFileOperation(); 50 | verify(callback).fileAdded(toCreate); 51 | } 52 | 53 | @Test 54 | public void deletedFileIsDetected() throws Exception { 55 | File toDelete = watchedDir.newFile("toDelete"); 56 | waitForFileOperation(); 57 | verify(callback).fileAdded(toDelete); 58 | 59 | toDelete.delete(); 60 | waitForFileOperation(); 61 | verify(callback).fileDeleted(toDelete); 62 | } 63 | 64 | @Test 65 | public void modifiedFileIsDetected() throws Exception { 66 | File toModify = watchedDir.newFile("toModify"); 67 | waitForFileOperation(); 68 | verify(callback).fileAdded(toModify); 69 | 70 | modifyFile(toModify); 71 | waitForFileOperation(); 72 | verify(callback, atLeastOnce()).fileModified(toModify); 73 | } 74 | 75 | @Test(expected = IOException.class) 76 | public void watchingFileIsNotPossible() throws Exception { 77 | try { 78 | new WatchDir(watchedDir.newFile("toWatch"), callback); 79 | } catch (IOException ioe) { 80 | assertThat(ioe).hasMessageEndingWith("is not a directory"); 81 | throw ioe; 82 | } 83 | } 84 | 85 | private void modifyFile(File toModify) throws IOException { 86 | OutputStream out = null; 87 | try { 88 | out = new FileOutputStream(toModify); 89 | out.write(1); 90 | } finally { 91 | if (out != null) { 92 | out.close(); 93 | } 94 | } 95 | } 96 | 97 | @After 98 | public void destroyWatchedDir() throws IOException { 99 | watchDir.stopService(); 100 | } 101 | 102 | private void waitForFileOperation() throws InterruptedException { 103 | synchronized (synchro) { 104 | synchro.wait(FILE_OPERATION_TIMEOUT); 105 | } 106 | } 107 | 108 | private static class MockWatchedCallback implements WatchedCallback { 109 | 110 | private final Object synchro; 111 | 112 | public MockWatchedCallback(Object synchro) { 113 | this.synchro = synchro; 114 | } 115 | 116 | @Override 117 | public void fileModified(File file) throws Exception { 118 | synchronized (synchro) { 119 | synchro.notifyAll(); 120 | } 121 | } 122 | 123 | @Override 124 | public void fileDeleted(File file) throws Exception { 125 | synchronized (synchro) { 126 | synchro.notifyAll(); 127 | } 128 | } 129 | 130 | @Override 131 | public void fileAdded(File file) throws Exception { 132 | synchronized (synchro) { 133 | synchro.notifyAll(); 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /javadoc/deprecated-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Deprecated List (jmxlogger javadoc) 7 | 8 | 9 | 10 | 11 | 17 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 35 |
36 | 63 | 64 |
65 |

Deprecated API

66 |

Contents

67 |
68 | 69 |
70 | 71 | 72 | 73 | 74 | 83 |
84 | 111 | 112 |

113 | Copyright © 2013 Jon Stevens and a gang of pencils. All Rights Reserved. Build version: 20130828-162948-517c4427f5

114 | 115 | 116 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/PropertyResolver.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import com.google.common.base.Function; 4 | import com.google.common.collect.ImmutableList; 5 | import com.google.common.collect.ImmutableMap; 6 | 7 | import javax.annotation.CheckReturnValue; 8 | import javax.annotation.Nonnull; 9 | import javax.annotation.Nullable; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static com.google.common.collect.FluentIterable.from; 14 | import static com.google.common.collect.ImmutableMap.copyOf; 15 | import static com.google.common.collect.Maps.transformValues; 16 | 17 | /*** 18 | * 19 | * Property Resolver 20 | * 21 | * @author henri 22 | * 23 | */ 24 | public class PropertyResolver { 25 | 26 | private static PropertyResolverFunc RESOLVE_PROPERTIES = new PropertyResolverFunc(); 27 | 28 | private static ObjectPropertyResolverFunc RESOLVE_OBJECT_PROPERTIES = new ObjectPropertyResolverFunc(); 29 | 30 | /** 31 | * Resolve a property from System Properties (aka ${key}) key:defval is 32 | * supported and if key not found on SysProps, defval will be returned 33 | * 34 | * @param s 35 | * @return resolved string or null if not found in System Properties and no 36 | * defval 37 | */ 38 | private static String resolveString(String s) { 39 | 40 | int pos = s.indexOf(":", 0); 41 | 42 | if (pos == -1) 43 | return (System.getProperty(s)); 44 | 45 | String key = s.substring(0, pos); 46 | String defval = s.substring(pos + 1); 47 | 48 | String val = System.getProperty(key); 49 | 50 | if (val != null) 51 | return val; 52 | else 53 | return defval; 54 | } 55 | 56 | /** 57 | * Parse a String and replace vars a la ant (${key} from System Properties 58 | * Support complex Strings like : 59 | * 60 | * "${myhost}" "${myhost:w2}" "${mybean:defbean}.${mybean2:defbean2}" 61 | * 62 | * @param s 63 | * @return resolved String 64 | */ 65 | public static String resolveProps(@Nullable String s) { 66 | if (s == null) { 67 | return null; 68 | } 69 | 70 | int ipos = 0; 71 | int pos = s.indexOf("${", ipos); 72 | 73 | if (pos == -1) 74 | return s; 75 | 76 | StringBuilder sb = new StringBuilder(); 77 | 78 | while (ipos < s.length()) { 79 | pos = s.indexOf("${", ipos); 80 | 81 | if (pos < 0) { 82 | sb.append(s.substring(ipos)); 83 | break; 84 | } 85 | 86 | if (pos != ipos) 87 | sb.append(s.substring(ipos, pos)); 88 | 89 | int end = s.indexOf('}', pos); 90 | 91 | if (end < 0) 92 | break; 93 | 94 | int start = pos + 2; 95 | pos = end + 1; 96 | 97 | String key = s.substring(start, end); 98 | String val = resolveString(key); 99 | 100 | if (val != null) 101 | sb.append(val); 102 | else 103 | sb.append("${").append(key).append("}"); 104 | 105 | ipos = end + 1; 106 | } 107 | 108 | return (sb.toString()); 109 | } 110 | 111 | /** 112 | * Parse Map and resolve Strings value with resolveProps 113 | */ 114 | @CheckReturnValue 115 | public static ImmutableMap resolveMap(@Nonnull Map map) { 116 | return copyOf(transformValues(map, RESOLVE_OBJECT_PROPERTIES)); 117 | } 118 | 119 | /** 120 | * Parse List and resolve Strings value with resolveProps 121 | */ 122 | @CheckReturnValue 123 | public static ImmutableList resolveList(@Nonnull List list) { 124 | return from(list) 125 | .transform(RESOLVE_PROPERTIES) 126 | .toList(); 127 | } 128 | 129 | private static class PropertyResolverFunc implements Function { 130 | @Nullable 131 | @Override 132 | public String apply(@Nullable String input) { 133 | return resolveProps(input); 134 | } 135 | } 136 | 137 | private static class ObjectPropertyResolverFunc implements Function { 138 | @Nullable 139 | @Override 140 | public Object apply(@Nullable Object input) { 141 | if (input instanceof String) { 142 | return resolveProps((String) input); 143 | } 144 | return input; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/model/output/RRDWriter.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model.output; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.google.common.base.MoreObjects; 6 | import com.google.common.collect.ImmutableList; 7 | import com.googlecode.jmxtrans.model.Query; 8 | import com.googlecode.jmxtrans.model.Result; 9 | import com.googlecode.jmxtrans.model.Server; 10 | import com.googlecode.jmxtrans.model.ValidationException; 11 | import org.apache.commons.io.FileUtils; 12 | import org.jrobin.core.RrdDb; 13 | import org.jrobin.core.RrdDef; 14 | import org.jrobin.core.RrdDefTemplate; 15 | import org.jrobin.core.Sample; 16 | 17 | import java.io.File; 18 | import java.util.Arrays; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.Map.Entry; 22 | 23 | import static com.google.common.base.Preconditions.checkState; 24 | 25 | /** 26 | * This takes a JRobin template.xml file and then creates the database if it 27 | * doesn't already exist. 28 | * 29 | * It will then write the contents of the Query (the Results) to the database. 30 | * 31 | * This uses the JRobin rrd format and is incompatible with the C version of 32 | * rrd. 33 | * 34 | * @author jon 35 | */ 36 | public class RRDWriter extends BaseOutputWriter { 37 | 38 | private final File outputFile; 39 | private final File templateFile; 40 | 41 | @JsonCreator 42 | public RRDWriter( 43 | @JsonProperty("typeNames") ImmutableList typeNames, 44 | @JsonProperty("debug") Boolean debugEnabled, 45 | @JsonProperty("outputFile") String outputFile, 46 | @JsonProperty("templateFile") String templateFile, 47 | @JsonProperty("settings") Map settings) { 48 | super(typeNames, debugEnabled, settings); 49 | this.outputFile = new File(MoreObjects.firstNonNull(outputFile, (String) getSettings().get(OUTPUT_FILE))); 50 | this.templateFile = new File(MoreObjects.firstNonNull(templateFile, (String) getSettings().get(TEMPLATE_FILE))); 51 | checkState(this.outputFile.exists(), "Output file must exist"); 52 | checkState(this.templateFile.exists(), "Template file must exist"); 53 | } 54 | 55 | public void validateSetup(Server server, Query query) throws ValidationException { 56 | } 57 | 58 | public void doWrite(Server server, Query query, ImmutableList results) throws Exception { 59 | RrdDb db = null; 60 | try { 61 | db = createOrOpenDatabase(); 62 | Sample sample = db.createSample(); 63 | List dsNames = Arrays.asList(db.getDsNames()); 64 | 65 | // go over all the results and look for datasource names that map to 66 | // keys from the result values 67 | for (Result res : results) { 68 | Map values = res.getValues(); 69 | if (values != null) { 70 | for (Entry entry : values.entrySet()) { 71 | if (dsNames.contains(entry.getKey()) && NumberUtils.isNumeric(entry.getValue())) { 72 | sample.setValue(entry.getKey(), Double.valueOf(entry.getValue().toString())); 73 | } 74 | } 75 | } 76 | } 77 | sample.update(); 78 | } finally { 79 | if (db != null) { 80 | db.close(); 81 | } 82 | } 83 | } 84 | 85 | /** 86 | * If the database file doesn't exist, it'll get created, otherwise, it'll 87 | * be returned in r/w mode. 88 | */ 89 | protected RrdDb createOrOpenDatabase() throws Exception { 90 | RrdDb result; 91 | if (!this.outputFile.exists()) { 92 | FileUtils.forceMkdir(this.outputFile.getParentFile()); 93 | RrdDefTemplate t = new RrdDefTemplate(this.templateFile); 94 | t.setVariable("database", this.outputFile.getCanonicalPath()); 95 | RrdDef def = t.getRrdDef(); 96 | result = new RrdDb(def); 97 | } else { 98 | result = new RrdDb(this.outputFile.getCanonicalPath()); 99 | } 100 | return result; 101 | } 102 | 103 | public String getTemplateFile() { 104 | return templateFile.getPath(); 105 | } 106 | 107 | public String getOutputFile() { 108 | return outputFile.getPath(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /test/com/googlecode/jmxtrans/model/MergingTests.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.model; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import static com.googlecode.jmxtrans.model.Server.mergeServerLists; 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | 11 | public class MergingTests { 12 | 13 | @Test 14 | public void mergeAlreadyExistingServerDoesNotModifyList() throws ValidationException { 15 | List existingServers = new ArrayList(); 16 | existingServers.add(ServerFixtures.createServerWithOneQuery("example.net", "123", "toto")); 17 | 18 | List newServers = new ArrayList(); 19 | newServers.add(ServerFixtures.createServerWithOneQuery("example.net", "123", "toto")); 20 | 21 | List merged = mergeServerLists(existingServers, newServers); 22 | 23 | assertThat(merged).hasSize(1); 24 | 25 | Server mergedServer = merged.get(0); 26 | assertThat(mergedServer.getQueries()).hasSize(1); 27 | } 28 | 29 | @Test 30 | public void sameServerWithTwoDifferentQueriesMergesQueries() throws ValidationException { 31 | List existingServers = new ArrayList(); 32 | existingServers.add(ServerFixtures.createServerWithOneQuery("example.net", "123", "toto")); 33 | 34 | List newServers = new ArrayList(); 35 | newServers.add(ServerFixtures.createServerWithOneQuery("example.net", "123", "tutu")); 36 | 37 | List merged = mergeServerLists(existingServers, newServers); 38 | 39 | assertThat(merged).hasSize(1); 40 | Server mergedServer = merged.get(0); 41 | assertThat(mergedServer.getQueries()).hasSize(2); 42 | } 43 | 44 | 45 | @Test 46 | public void testMerge() throws Exception { 47 | Query q1 = Query.builder() 48 | .setObj("obj") 49 | .addAttr("foo") 50 | .addAttr("bar") 51 | .addKey("key1") 52 | .addKey("key2") 53 | .setResultAlias("alias") 54 | .build(); 55 | 56 | // same as q1 57 | Query q2 = Query.builder() 58 | .setObj("obj") 59 | .addAttr("foo") 60 | .addAttr("bar") 61 | .addKey("key1") 62 | .addKey("key2") 63 | .setResultAlias("alias") 64 | .build(); 65 | 66 | // different than q1 and q2 67 | Query q3 = Query.builder() 68 | .setObj("obj3") 69 | .addAttr("foo") 70 | .addAttr("bar") 71 | .addKey("key1") 72 | .addKey("key2") 73 | .setResultAlias("alias") 74 | .build(); 75 | 76 | Server s1 = Server.builder() 77 | .setAlias("alias") 78 | .setHost("host") 79 | .setPort("8004") 80 | .setCronExpression("cron") 81 | .setNumQueryThreads(123) 82 | .setPassword("pass") 83 | .setUsername("user") 84 | .addQuery(q1) 85 | .addQuery(q2) 86 | .build(); 87 | 88 | // same as s1 89 | Server s2 = Server.builder() 90 | .setAlias("alias") 91 | .setHost("host") 92 | .setPort("8004") 93 | .setCronExpression("cron") 94 | .setNumQueryThreads(123) 95 | .setPassword("pass") 96 | .setUsername("user") 97 | .addQuery(q1) 98 | .addQuery(q2) 99 | .build(); 100 | 101 | Server s3 = Server.builder() 102 | .setAlias("alias") 103 | .setHost("host3") 104 | .setPort("8004") 105 | .setCronExpression("cron") 106 | .setNumQueryThreads(123) 107 | .setPassword("pass") 108 | .setUsername("user") 109 | .addQuery(q1) 110 | .addQuery(q2) 111 | .addQuery(q3) 112 | .build(); 113 | 114 | List existing = new ArrayList(); 115 | existing.add(s1); 116 | 117 | List adding = new ArrayList(); 118 | 119 | adding.add(s2); 120 | existing = mergeServerLists(existing, adding); 121 | 122 | // should only have one server with 1 query since we just added the same 123 | // server and same query. 124 | assertThat(existing).hasSize(1); 125 | assertThat(existing.get(0).getQueries()).hasSize(1); 126 | 127 | adding.add(s3); 128 | existing = mergeServerLists(existing, adding); 129 | 130 | assertThat(existing).hasSize(2); 131 | assertThat(existing.get(0).getQueries()).hasSize(1); 132 | assertThat(existing.get(1).getQueries()).hasSize(2); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/com/googlecode/jmxtrans/guice/JmxTransModule.java: -------------------------------------------------------------------------------- 1 | package com.googlecode.jmxtrans.guice; 2 | 3 | 4 | import com.google.common.io.Closer; 5 | import com.google.inject.AbstractModule; 6 | import com.google.inject.Inject; 7 | import com.google.inject.Provides; 8 | import com.google.inject.TypeLiteral; 9 | import org.apache.commons.pool.KeyedPoolableObjectFactory; 10 | import org.apache.commons.pool.impl.GenericKeyedObjectPool; 11 | import org.quartz.Scheduler; 12 | import org.quartz.SchedulerException; 13 | import org.quartz.impl.StdSchedulerFactory; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import javax.management.remote.JMXConnector; 18 | import java.io.FileInputStream; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.lang.management.ManagementFactory; 22 | import java.net.DatagramSocket; 23 | import java.net.InetSocketAddress; 24 | import java.net.Socket; 25 | import java.net.SocketAddress; 26 | 27 | import com.googlecode.jmxtrans.cli.JmxTransConfiguration; 28 | import com.googlecode.jmxtrans.connections.DatagramSocketFactory; 29 | import com.googlecode.jmxtrans.connections.JMXConnectionParams; 30 | import com.googlecode.jmxtrans.connections.JmxConnectionFactory; 31 | import com.googlecode.jmxtrans.connections.SocketFactory; 32 | import com.googlecode.jmxtrans.monitoring.ManagedGenericKeyedObjectPool; 33 | 34 | public class JmxTransModule extends AbstractModule { 35 | 36 | private final Logger log = LoggerFactory.getLogger(getClass()); 37 | 38 | private final JmxTransConfiguration configuration; 39 | 40 | public JmxTransModule(JmxTransConfiguration configuration) { 41 | this.configuration = configuration; 42 | } 43 | 44 | @Override 45 | protected void configure() { 46 | bind(new TypeLiteral>(){}) 47 | .toInstance(getObjectPool(new SocketFactory(), SocketFactory.class.getSimpleName())); 48 | bind(new TypeLiteral>(){}) 49 | .toInstance(getObjectPool(new JmxConnectionFactory(), JmxConnectionFactory.class.getSimpleName())); 50 | bind(new TypeLiteral>(){}) 51 | .toInstance(getObjectPool(new DatagramSocketFactory(), DatagramSocketFactory.class.getSimpleName())); 52 | } 53 | 54 | @Provides 55 | JmxTransConfiguration jmxTransConfiguration() { 56 | return configuration; 57 | } 58 | 59 | @Provides 60 | @Inject 61 | Scheduler scheduler(JmxTransConfiguration configuration, GuiceJobFactory jobFactory) throws SchedulerException, IOException { 62 | StdSchedulerFactory serverSchedFact = new StdSchedulerFactory(); 63 | Closer closer = Closer.create(); 64 | try { 65 | InputStream stream; 66 | if (configuration.getQuartPropertiesFile() == null) { 67 | stream = closer.register(JmxTransModule.class.getResourceAsStream("/quartz.server.properties")); 68 | } else { 69 | stream = closer.register(new FileInputStream(configuration.getQuartPropertiesFile())); 70 | } 71 | serverSchedFact.initialize(stream); 72 | } catch (Throwable t) { 73 | throw closer.rethrow(t); 74 | } finally { 75 | closer.close(); 76 | } 77 | Scheduler scheduler = serverSchedFact.getScheduler(); 78 | scheduler.setJobFactory(jobFactory); 79 | return scheduler; 80 | } 81 | 82 | private GenericKeyedObjectPool getObjectPool(KeyedPoolableObjectFactory factory, String poolName) { 83 | GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory); 84 | pool.setTestOnBorrow(true); 85 | pool.setMaxActive(-1); 86 | pool.setMaxIdle(-1); 87 | pool.setTimeBetweenEvictionRunsMillis(1000 * 60 * 5); 88 | pool.setMinEvictableIdleTimeMillis(1000 * 60 * 5); 89 | 90 | try { 91 | ManagedGenericKeyedObjectPool mbean = 92 | new ManagedGenericKeyedObjectPool( 93 | pool, 94 | poolName); 95 | ManagementFactory.getPlatformMBeanServer() 96 | .registerMBean(mbean, mbean.getObjectName()); 97 | } catch (Exception e) { 98 | log.error("Could not register mbean for pool [{}]", poolName, e); 99 | } 100 | 101 | return pool; 102 | } 103 | 104 | 105 | } 106 | --------------------------------------------------------------------------------