├── .classpath
├── .gitignore
├── .project
├── .travis.yml
├── COPYING
├── README
├── etc
├── jmxetric.xml
└── logging.properties
├── pom.xml
└── src
├── main
├── assembly
│ └── bin.xml
├── java
│ └── info
│ │ └── ganglia
│ │ └── jmxetric
│ │ ├── CommandLineArgs.java
│ │ ├── GangliaXmlConfigurationService.java
│ │ ├── JMXetricAgent.java
│ │ ├── JMXetricXmlConfigurationService.java
│ │ ├── MBeanAttribute.java
│ │ ├── MBeanHolder.java
│ │ ├── MBeanSampler.java
│ │ ├── MBeanScanner.java
│ │ ├── XMLConfigurationService.java
│ │ └── package.html
└── resources
│ └── META-INF
│ └── MANIFEST.MF
└── test
├── java
└── info
│ └── ganglia
│ └── jmxetric
│ ├── CommandLineArgsTest.java
│ ├── Example.java
│ ├── ExampleComposite.java
│ ├── GangliaXmlConfigurationServiceTest.java
│ ├── JMXetricAgentIT.java
│ ├── JMXetricXmlConfigurationServiceTest.java
│ ├── MBeanSamplerTest.java
│ └── TestExampleMXBean.java
└── resources
└── jmxetric_test.xml
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | /.settings
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | jmxetric
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.maven.ide.eclipse.maven2Builder
15 |
16 |
17 |
18 |
19 | org.eclipse.m2e.core.maven2Builder
20 |
21 |
22 |
23 |
24 |
25 | org.eclipse.m2e.core.maven2Nature
26 | org.maven.ide.eclipse.maven2Nature
27 | org.eclipse.jdt.core.javanature
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk7
4 | - openjdk6
5 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2011 Jasper Humphrey
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Name
2 | jmxetric - jvm instrumentation to ganglia
3 |
4 | Version
5 | The latest version of this software and document will be found at
6 | https://github.com/ganglia/jmxetric
7 |
8 | Synopsis
9 | JMXetric is a 100% java, configurable JVM agent that periodically polls
10 | MBean attributes and reports their values to Ganglia.
11 |
12 | Project goals are that JMXetric should be
13 | * configurable (xml)
14 | * lightweight (small memory and cpu footprint)
15 | * standalone (not depend on third party libraries)
16 |
17 | The gmetric protocol implementation uses classes generated by the LGPL
18 | remotetea project (http://remotetea.sf.net).
19 |
20 | Installation
21 |
22 | Unzip the archive
23 | Add the following to your JVM
24 | java -javaagent:/jmxetric.jar=host="",port="",config="",process="" usual.java.main.class
25 |
26 | Demo / Quickstart
27 | Check the matching version of gmetric4j.jar in the pom.xml
28 | 1) Ensure you have a gmond running on localhost:8649
29 | $ pgrep gmond # should return a valid PID
30 | $ nc localhost 8649 # dumps some XML to stdout
31 | 2) $ git clone https://github.com/ganglia/jmxetric.git
32 | 3) Download jmxetric.jar, gmetric4j.jar and remotetea-oncrpc.jar
33 | all into the same directory.
34 | 4) $ cd jmxetric
35 | 5) In bash do:
36 | $ export config="host=localhost,port=8649,wireformat31x=true,config=etc/jmxetric.xml"
37 | $ java -Djava.util.logging.config.file=etc/logging.properties \
38 | -cp gmetric4j.jar:remotetea-oncrpc.jar:jmxetric.jar \
39 | -javaagent:jmxetric.jar=$config info.ganglia.jmxetric.JMXetricAgent
40 |
41 | Configuration
42 | The configuration of JMXetric is loaded from an xml file in the working
43 | directory of the shell, or specified as an argument to the JVM agent
44 | ("config"). The JVM agent arguments can also be used to specify the
45 | following:
46 |
47 | host, port The multicast address that is used to publish metrics to the
48 | ganglia gmond process
49 |
50 | config The full path to the config file (jmxetric.xml)
51 |
52 | mode The UDP addressing mode, either multicast or unicast (default multicast)
53 |
54 | wireformat31x True if the ganglia v3.1.x wire format should be used (default false)
55 |
56 | spoof An IP:hostname pair that will be used to spoof the metric host information.
57 | (default: no spoofing, i.e., local hostname reported by OS)
58 |
59 | process A name that is prefixed to the metric name before publication
60 | (so that metrics from different JVMs on the same host can be
61 | determined)
62 |
63 | XML Configuation File
64 |
65 | JMXetric schedules a number of "samples", that queries a list of "mbeans",
66 | that have "attributes".
67 |
68 | Element/Attribute Description
69 | mbean/name The name of the mbean to query
70 | mbean/pname The metric name for this mbean. This should always be
71 | used as ganglia/rrdtool misbehaves if the filename is
72 | "unusual".
73 | attribute/nam The name of the attribute. This can have two levels
74 | for the case of a composite key see below example for
75 | attribute "HeapMemoryUsage", key "used"
76 | attribute/type The type used for the metric in ganglia
77 | attribute/units The units used for the metric in ganglia
78 | attribute/pname The metric name for this attribute
79 |
80 | An example file:
81 |
82 |
83 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | ]>
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | Support/Queries
141 | I'm sure there are bugs and I'm sure there are some mbeans that can't be
142 | sampled currently. If you find some, then let me know jasper521 at gmail
143 |
144 | If you are using this at all, then I'd love to know!
145 |
146 | Copyright
147 | Copyright (C) 2008-2011 Jasper Humphrey, jasper521@gmail.com
148 | Copyright (C) 2011-2015 Daniel Pocock, http://danielpocock.com
149 |
150 |
--------------------------------------------------------------------------------
/etc/jmxetric.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ]>
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
70 |
71 |
72 |
75 |
76 |
77 |
81 |
82 |
83 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/etc/logging.properties:
--------------------------------------------------------------------------------
1 | ############################################################
2 | # Default Logging Configuration File
3 | #
4 | # You can use a different file by specifying a filename
5 | # with the java.util.logging.config.file system property.
6 | # For example java -Djava.util.logging.config.file=myfile
7 | ############################################################
8 |
9 | handlers= java.util.logging.ConsoleHandler
10 |
11 | .level=INFO
12 |
13 | java.util.logging.ConsoleHandler.level = ALL
14 | java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
15 |
16 | info.ganglia.jmxetric.level=ALL
17 | info.ganglia.gmetric4j.level=ALL
18 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | info.ganglia.jmxetric
5 | jmxetric
6 | JMXetric
7 | jar
8 | 1.0.8
9 | JVM instrumentation to Ganglia
10 | http://github.com/ganglia/jmxetric
11 |
12 |
13 | The MIT License
14 | http://www.opensource.org/licenses/mit-license.php
15 | repo
16 |
17 |
18 |
19 | scm:git:git@github.com:ganglia/jmxetric.git
20 | scm:git:git@github.com:ganglia/jmxetric.git
21 | scm:git:git@github.com:ganglia/jmxetric.git
22 |
23 |
24 |
25 | humphrej
26 | Jasper Humphrey
27 | jasper521@googlemail.com
28 |
29 |
30 | pocock
31 | Daniel Pocock
32 | daniel@pocock.pro
33 | http://danielpocock.com
34 |
35 |
36 |
37 | 1.0.10
38 |
39 |
40 |
41 | info.ganglia.gmetric4j
42 | gmetric4j
43 | ${gmetric4j.version}
44 | jar
45 |
46 |
47 | info.ganglia.gmetric4j
48 | gmetric4j
49 | ${gmetric4j.version}
50 | test-jar
51 | test
52 |
53 |
54 | junit
55 | junit
56 | 4.1
57 | jar
58 | test
59 |
60 |
61 |
62 | org.sonatype.oss
63 | oss-parent
64 | 7
65 |
66 |
67 |
68 |
69 | src/main/resources
70 | true
71 |
72 |
73 |
74 |
75 | org.apache.maven.plugins
76 | maven-compiler-plugin
77 | 2.5.1
78 |
79 | 1.5
80 | 1.5
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-jar-plugin
86 | 2.4
87 |
88 |
89 | target/classes/META-INF/MANIFEST.MF
90 |
91 |
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-source-plugin
96 |
97 |
98 | attach-sources
99 |
100 | jar
101 |
102 |
103 |
104 |
105 |
106 | org.apache.maven.plugins
107 | maven-javadoc-plugin
108 |
109 |
110 | attach-javadocs
111 |
112 | jar
113 |
114 |
115 |
116 |
117 |
118 | org.apache.maven.plugins
119 | maven-assembly-plugin
120 | 2.3
121 |
122 |
123 | src/main/assembly/bin.xml
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | org.codehaus.mojo
133 | findbugs-maven-plugin
134 | 2.5.2
135 |
136 |
137 | org.apache.maven.plugins
138 | maven-javadoc-plugin
139 |
140 |
141 |
142 |
143 |
144 | release-sign-artifacts
145 |
146 |
147 | performRelease
148 | true
149 |
150 |
151 |
152 |
153 |
154 | org.apache.maven.plugins
155 | maven-gpg-plugin
156 | 1.4
157 |
158 |
159 | sign-artifacts
160 | verify
161 |
162 | sign
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/src/main/assembly/bin.xml:
--------------------------------------------------------------------------------
1 |
2 | bin
3 |
4 | zip
5 |
6 | true
7 |
8 |
9 | false
10 |
11 |
12 |
13 |
14 |
15 | etc/*
16 | README*
17 | LICENSE*
18 | NOTICE*
19 | COPYING*
20 | CHANGES*
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/CommandLineArgs.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | public class CommandLineArgs {
7 | public static final String DEFAULT_CONFIG = "jmxetric.xml";
8 | private final static Pattern pattern = Pattern.compile("(\\S+?)\\=(\\S*)");
9 |
10 | private String host = null;
11 | private String port = null;
12 | private String config = null;
13 | private String mode = null;
14 | private String wireformat = null;
15 | private String processName = null;
16 | private String spoof = null;
17 |
18 | public CommandLineArgs(String arguments) {
19 | String commandLine = arguments == null ? "" : arguments;
20 | String[] args = commandLine.split(",");
21 |
22 | host = getTagValue("host", args, null);
23 | port = getTagValue("port", args, null);
24 | config = getTagValue("config", args, DEFAULT_CONFIG);
25 | mode = getTagValue("mode", args, null);
26 | wireformat = getTagValue("wireformat31x", args, null);
27 | processName = getTagValue("process", args, null);
28 | spoof = getTagValue("spoof", args, null);
29 | }
30 |
31 | public String getHost() {
32 | return host;
33 | }
34 |
35 | public String getPort() {
36 | return port;
37 | }
38 |
39 | public String getConfig() {
40 | return config;
41 | }
42 |
43 | public String getMode() {
44 | return mode;
45 | }
46 |
47 | public String getWireformat() {
48 | return wireformat;
49 | }
50 |
51 | public String getProcessName() {
52 | return processName;
53 | }
54 |
55 | public String getSpoof() {
56 | return spoof;
57 | }
58 |
59 | /*
60 | * Parses the string array, input, looking for a pattern tag=value
61 | *
62 | * @param tag the tag to search for
63 | *
64 | * @param input the array list
65 | *
66 | * @param defaultValue the default value if tag is not found
67 | *
68 | * @return tha value
69 | */
70 | private String getTagValue(String tag, String[] input, String defaultValue) {
71 | for (String arg : input) {
72 | Matcher matcher = CommandLineArgs.pattern.matcher(arg);
73 | // Get tagname and contents of tag
74 | if (matcher.find()) {
75 | String tagname = matcher.group(1);
76 | if (tag.equals(tagname)) {
77 | return matcher.group(2);
78 | }
79 | }
80 | }
81 | return defaultValue;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/GangliaXmlConfigurationService.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import info.ganglia.gmetric4j.gmetric.GMetric;
4 | import info.ganglia.gmetric4j.gmetric.GMetric.UDPAddressingMode;
5 |
6 | import java.io.IOException;
7 | import java.util.logging.Logger;
8 |
9 | import javax.xml.xpath.XPathExpressionException;
10 |
11 | import org.w3c.dom.Node;
12 | import org.xml.sax.InputSource;
13 |
14 | /**
15 | * Configures JMXetricAgent based on command line arguments and parameters
16 | * specified in the XML configuration source.
17 | *
18 | */
19 | class GangliaXmlConfigurationService extends XMLConfigurationService {
20 | private static Logger log = Logger.getLogger(JMXetricAgent.class.getName());
21 |
22 | /**
23 | * default host name gmond is running on
24 | */
25 | private static final String DEFAULT_HOSTNAME = "localhost";
26 |
27 | /**
28 | * default port gmond listens to
29 | */
30 | private static final String DEFAULT_PORT = "8649";
31 |
32 | /**
33 | * default transport mode
34 | */
35 | private static final String DEFAULT_MODE = "multicast";
36 |
37 | /**
38 | * default multicast TTL = 5 (same site)
39 | */
40 | private static final int DEFAULT_TTL = 5;
41 |
42 | /**
43 | * the XML configuration file source
44 | */
45 | private final InputSource inputSource;
46 |
47 | /**
48 | * command line arguments that was passed in
49 | */
50 | private final CommandLineArgs args;
51 |
52 | private Node ganglia;
53 |
54 | public GangliaXmlConfigurationService(InputSource inputSource,
55 | CommandLineArgs args) {
56 | this.inputSource = inputSource;
57 | this.args = args;
58 | }
59 |
60 | /**
61 | * Creates a GMetric attribute on the JMXetricAgent from the XML config
62 | *
63 | * @return
64 | * @throws IOException
65 | * @throws XPathExpressionException
66 | */
67 | public GMetric getConfig() throws IOException, XPathExpressionException {
68 | // TODO what happens when the node cannot be found? do we use all
69 | // default values?
70 | ganglia = getXmlNode("/jmxetric-config/ganglia", inputSource);
71 | // Gets the config for ganglia
72 | // Note that the ganglia config needs to be found before the samplers
73 | // are created.
74 | GMetric gmetric = makeGMetricFromXml();
75 | return gmetric;
76 | }
77 |
78 | /**
79 | * Makes a GMetric object that can be use to define configuration for an
80 | * agent.
81 | *
82 | * @return GMetric object with the configuration
83 | * @throws IOException
84 | */
85 | GMetric makeGMetricFromXml() throws IOException {
86 | String hostname = getHostName();
87 | int port = getPort();
88 | UDPAddressingMode addressingMode = getAddressingMode();
89 | boolean v31x = getV31();
90 | String spoof = getSpoof();
91 |
92 | StringBuilder buf = new StringBuilder();
93 | buf.append("GMetric host=").append(hostname);
94 | buf.append(" port=").append(port);
95 | buf.append(" mode=").append(addressingMode);
96 | buf.append(" v31x=").append(v31x);
97 | buf.append(" spoof=").append(spoof);
98 | log.fine(buf.toString());
99 | System.out.println(buf.toString());
100 | return new GMetric(hostname, port, addressingMode, DEFAULT_TTL, v31x,
101 | null, spoof);
102 | }
103 |
104 | /**
105 | * Gets the name of the host to be reported to.
106 | *
107 | * @return name of host, defaults to "localhost"
108 | */
109 | private String getHostName() {
110 | return getGangliaConfig(args.getHost(), ganglia, "hostname",
111 | DEFAULT_HOSTNAME);
112 | }
113 |
114 | /**
115 | * Gets the port that JMXetric will announce to, this is usually the port
116 | * gmond is running on
117 | *
118 | * @return port number, defaults to 8649
119 | */
120 | private int getPort() {
121 | String port = getGangliaConfig(args.getPort(), ganglia, "port",
122 | DEFAULT_PORT);
123 | return Integer.parseInt(port);
124 | }
125 |
126 | /**
127 | * UDPAddressingMode to use for reporting
128 | *
129 | * @return {@link info.ganglia.gmetric4j.gmetric.UDPAddressingMode.UNICAST}
130 | * or
131 | * {@link info.ganglia.gmetric4j.gmetric.UDPAddressingMode.MULTICAST}
132 | */
133 | private UDPAddressingMode getAddressingMode() {
134 | String mode = getGangliaConfig(args.getMode(), ganglia, "mode",
135 | DEFAULT_MODE);
136 | if (mode.toLowerCase().equals("unicast")) {
137 | return UDPAddressingMode.UNICAST;
138 | } else {
139 | return UDPAddressingMode.MULTICAST;
140 | }
141 | }
142 |
143 | /**
144 | * Whether the reporting be done on the new wire format 31.
145 | *
146 | * @return true if new format is to be used
147 | */
148 | private boolean getV31() {
149 | String stringv31x = getGangliaConfig(args.getWireformat(), ganglia,
150 | "wireformat31x", "false");
151 | return Boolean.parseBoolean(stringv31x);
152 | }
153 |
154 | /**
155 | * Gets the value of the spoof parameter.
156 | *
157 | * @return value of spoof
158 | */
159 | private String getSpoof() {
160 | return getGangliaConfig(args.getSpoof(), ganglia, "spoof", null);
161 | }
162 |
163 | /**
164 | * Gets a configuration parameter for Ganglia. First checks if it was given
165 | * on the command line arguments. If it is not available, it looks for the
166 | * value in the XML node.
167 | *
168 | * @param cmdLine
169 | * command line value for this attribute
170 | * @param ganglia
171 | * the XML node
172 | * @param attributeName
173 | * name of the attribute
174 | * @param defaultValue
175 | * default value if this attribute cannot be found
176 | * @return the string value of the specified attribute
177 | */
178 | private String getGangliaConfig(String cmdLine, Node ganglia,
179 | String attributeName, String defaultValue) {
180 | if (cmdLine == null) {
181 | return selectParameterFromNode(ganglia, attributeName, defaultValue);
182 | } else {
183 | return cmdLine;
184 | }
185 | }
186 |
187 | /**
188 | * Method used by tests to print out the read in configuration.
189 | *
190 | * @return string representation of configuration
191 | * @throws XPathExpressionException
192 | */
193 | String getConfigString() throws XPathExpressionException {
194 | ganglia = getXmlNode("/jmxetric-config/ganglia", inputSource);
195 | String hostname = getHostName();
196 | int port = getPort();
197 | UDPAddressingMode addressingMode = getAddressingMode();
198 | boolean v31x = getV31();
199 | String spoof = getSpoof();
200 |
201 | StringBuilder buf = new StringBuilder();
202 | buf.append("GMetric host=").append(hostname);
203 | buf.append(" port=").append(port);
204 | buf.append(" mode=").append(addressingMode);
205 | buf.append(" v31x=").append(v31x);
206 | buf.append(" spoof=").append(spoof);
207 | return buf.toString();
208 | }
209 | }
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/JMXetricAgent.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 |
4 | import info.ganglia.gmetric4j.GMonitor;
5 |
6 | import java.lang.instrument.Instrumentation;
7 | // import java.util.logging.Logger;
8 |
9 | /**
10 | * JMXetricAgent is a JVM agent that will sample MBean attributes on a periodic basis,
11 | * publishing the value of those attributes to the Ganglia gmond process.
12 | *
13 | * Use:
14 | * java -javaagent:path/jmxetric.jar=args yourmainclass
15 | *
16 | * Example:
17 | * java -javaagent:/opt/jmxetric_0_1/jmxetric.jar=host="localhost",port="8649",config=/opt/jmxetric_0_1/jmxetric.xml yourmainclass
18 | *
19 | * Arguments can be:
20 | *
21 | * Argument | Default | Description |
22 | * host | | Host address for ganglia |
23 | * port | | Port for ganglia |
24 | * config | jmxetric.xml | Config file path |
25 | *
26 | */
27 | public class JMXetricAgent extends GMonitor {
28 | // private static Logger log =
29 | // Logger.getLogger(JMXetricAgent.class.getName());
30 | /**
31 | * A log running, trivial main method for test purposes
32 | * premain method
33 | * @param args Not used
34 | */
35 | public static void main(String[] args) throws Exception {
36 | while( true ) {
37 | Thread.sleep(1000*60*5);
38 | System.out.println("Test wakeup");
39 | }
40 | }
41 | /**
42 | * The JVM agent entry point
43 | * @param agentArgs
44 | * @param inst
45 | */
46 | public static void premain(String agentArgs, Instrumentation inst) {
47 | System.out.println(STARTUP_NOTICE) ;
48 | JMXetricAgent a = null ;
49 | try {
50 | a = new JMXetricAgent();
51 | XMLConfigurationService.configure(a, agentArgs);
52 | a.start();
53 | } catch ( Exception ex ) {
54 | // log.severe("Exception starting JMXetricAgent");
55 | ex.printStackTrace();
56 | }
57 | }
58 |
59 | private static final String STARTUP_NOTICE="JMXetricAgent instrumented JVM, see https://github.com/ganglia/jmxetric";
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/JMXetricXmlConfigurationService.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import info.ganglia.gmetric4j.gmetric.GMetricSlope;
4 | import info.ganglia.gmetric4j.gmetric.GMetricType;
5 |
6 | import java.util.List;
7 | import java.util.Vector;
8 | import java.util.logging.Logger;
9 |
10 | import javax.xml.xpath.XPathExpressionException;
11 |
12 | import org.w3c.dom.Node;
13 | import org.w3c.dom.NodeList;
14 | import org.xml.sax.InputSource;
15 |
16 | /**
17 | * Configures JMXetric using an XML file. The XML file is read and MBeanSamplers
18 | * are created based on what the file specifies. These MBeanSamplers are then
19 | * added to the JMXetricAgent.
20 | */
21 | public class JMXetricXmlConfigurationService extends XMLConfigurationService {
22 | private static Logger log = Logger.getLogger(JMXetricAgent.class.getName());
23 |
24 | /**
25 | * agent that is configured using the XML file
26 | */
27 | private JMXetricAgent agent;
28 |
29 | /**
30 | * XML configuration source
31 | */
32 | private InputSource inputSource;
33 |
34 | /**
35 | * name that is associated with all declared metrics
36 | */
37 | private String processName;
38 |
39 | public JMXetricXmlConfigurationService(JMXetricAgent agent,
40 | InputSource inputSource, String processName) {
41 | this.agent = agent;
42 | this.inputSource = inputSource;
43 | this.processName = processName;
44 | }
45 |
46 | /**
47 | * Configures {@link info.ganglia.jmxetric.JMXetricAgent} using XML source
48 | *
49 | * @throws Exception
50 | */
51 | void configure() throws Exception {
52 | configureProcessName();
53 | configureJMXetricAgent();
54 | }
55 |
56 | /**
57 | * The XML file may specify a processName to be used, which can be different
58 | * from the one used in the constructor. The name in XML takes priority.
59 | *
60 | * @throws XPathExpressionException
61 | */
62 | private void configureProcessName() throws XPathExpressionException {
63 | if (processName != null) {
64 | return;
65 | }
66 | processName = "";
67 | Node jvm = getXmlNode("/jmxetric-config/jvm", inputSource);
68 | if (jvm != null) {
69 | processName = jvm.getAttributes().getNamedItem("process")
70 | .getNodeValue();
71 | }
72 | }
73 |
74 | /**
75 | * Use the XML source to configure the agent. Source is read for
76 | * nodes, each node corresponds to a MBeanSampler to be added to the agent.
77 | *
78 | * @throws XPathExpressionException
79 | * @throws Exception
80 | */
81 | private void configureJMXetricAgent() throws XPathExpressionException,
82 | Exception {
83 | // Gets the config for the samplers
84 | NodeList samples = getXmlNodeList("/jmxetric-config/sample",
85 | inputSource);
86 | for (int i = 0; i < samples.getLength(); i++) {
87 | Node sample = samples.item(i);
88 | MBeanSampler mbSampler = makeMBeanSampler(sample);
89 | agent.addSampler(mbSampler);
90 | }
91 | }
92 |
93 | /**
94 | * A node from the XML source is parsed to make an MBeanSampler.
95 | *
96 | * @param sample
97 | * @return
98 | * @throws Exception
99 | */
100 | private MBeanSampler makeMBeanSampler(Node sample) throws Exception {
101 | String delayString = selectParameterFromNode(sample, "delay", "60");
102 | int delay = Integer.parseInt(delayString);
103 |
104 | String initialDelayString = selectParameterFromNode(sample,
105 | "initialdelay", "0");
106 | int initialDelay = Integer.parseInt(initialDelayString);
107 |
108 | String sampleDMax = selectParameterFromNode(sample, "dmax", "0");
109 |
110 | MBeanSampler mBeanSampler = new MBeanSampler(initialDelay, delay,
111 | processName);
112 |
113 | NodeList mBeans = getXmlNodeSet("mbean", sample);
114 | for (int j = 0; j < mBeans.getLength(); j++) {
115 | Node mBean = mBeans.item(j);
116 | String mBeanName = selectParameterFromNode(mBean, "name", null);
117 | List attributes = getAttributesForMBean(mBean,
118 | sampleDMax);
119 | for (MBeanAttribute mBeanAttribute : attributes) {
120 | addMBeanAttributeToSampler(mBeanSampler, mBeanName,
121 | mBeanAttribute);
122 | }
123 | }
124 | return mBeanSampler;
125 | }
126 |
127 | /**
128 | * Adds a MBeanAttribute to an MBeanSampler. This also checks if the
129 | * MBeanAttribute to be added already has a MBeanSampler set, if not it will
130 | * set it.
131 | *
132 | * @param mBeanSampler
133 | * @param mBeanName
134 | * @param mBeanAttribute
135 | * @throws Exception
136 | */
137 | private void addMBeanAttributeToSampler(MBeanSampler mBeanSampler,
138 | String mBeanName, MBeanAttribute mBeanAttribute) throws Exception {
139 | if (mBeanAttribute.getSampler() == null) {
140 | mBeanAttribute.setSampler(mBeanSampler);
141 | }
142 | mBeanSampler.addMBeanAttribute(mBeanName, mBeanAttribute);
143 | }
144 |
145 | /**
146 | * Gets a list of MBeanAttributes for a single , they correspond to
147 | * the tags in the XML file.
148 | *
149 | * @param mBean
150 | * the node
151 | * @param sampleDMax
152 | * value of dmax passed down from
153 | * @return a list of attributes associated to the mbean
154 | * @throws Exception
155 | */
156 | List getAttributesForMBean(Node mBean, String sampleDMax)
157 | throws Exception {
158 | String mBeanName = selectParameterFromNode(mBean, "name", null);
159 | String mBeanPublishName = selectParameterFromNode(mBean, "pname", "");
160 | String mBeanDMax = selectParameterFromNode(mBean, "dmax", sampleDMax);
161 | log.finer("Mbean is " + mBeanName);
162 |
163 | NodeList attrs = getXmlNodeSet("attribute", mBean);
164 | List attributes = new Vector();
165 |
166 | for (int i = 0; i < attrs.getLength(); i++) {
167 | Node attr = attrs.item(i);
168 | if (isComposite(attr)) {
169 | attributes.addAll(makeCompositeAttributes(attr, mBeanName,
170 | mBeanPublishName, mBeanDMax));
171 | } else {
172 | attributes.add(makeSimpleAttribute(attr, mBeanName,
173 | mBeanPublishName, mBeanDMax));
174 | }
175 | }
176 | return attributes;
177 | }
178 |
179 | /**
180 | * Checks if the node is an attribute containing composites
181 | *
182 | * @param node
183 | * @return true if the node is an attribute containing composites
184 | */
185 | private boolean isComposite(Node node) {
186 | return node.getNodeName().equals("attribute")
187 | && node.getChildNodes().getLength() > 0;
188 | }
189 |
190 | /**
191 | * Makes a {@link MBeanAttribute} that corresponds to a simple
192 | * tag.
193 | *
194 | * @param attr
195 | * the node
196 | * @param mBeanName
197 | * name of the parent mbean
198 | * @param mBeanPublishName
199 | * publish name of the parent mbean
200 | * @param mBeanDMax
201 | * value of dmax specified by parent mbean
202 | * @return
203 | */
204 | private MBeanAttribute makeSimpleAttribute(Node attr, String mBeanName,
205 | String mBeanPublishName, String mBeanDMax) {
206 | MBeanAttribute mba = makeMBeanSimpleAttribute(attr, mBeanName,
207 | mBeanPublishName, mBeanDMax);
208 | return mba;
209 | }
210 |
211 | /**
212 | * Makes a list of {@link MBeanAttribute} that corresponds to an
213 | * node that contains multiple nodes.
214 | *
215 | * @param attr
216 | * the node
217 | * @param mBeanName
218 | * name of the parent mbean
219 | * @param mBeanPublishName
220 | * publish name of the parent mbean
221 | * @param mBeanDMax
222 | * value of dmax specified by parent mbean
223 | * @return list of {@link MBeanAttribute}, one for each
224 | * @throws XPathExpressionException
225 | */
226 | private List makeCompositeAttributes(Node attr,
227 | String mBeanName, String mBeanPublishName, String mBeanDMax)
228 | throws XPathExpressionException {
229 | List mbas = new Vector();
230 | MBeanAttribute mba = null;
231 | NodeList composites = getXmlNodeSet("composite", attr);
232 | String name = selectParameterFromNode(attr, "name", "NULL");
233 | for (int l = 0; l < composites.getLength(); l++) {
234 | Node composite = composites.item(l);
235 | mba = makeMBeanCompositeAttribute(composite, mBeanName,
236 | mBeanPublishName, mBeanDMax, name);
237 | log.finer("Attr is " + name);
238 | mbas.add(mba);
239 | }
240 | return mbas;
241 | }
242 |
243 | private MBeanAttribute makeMBeanSimpleAttribute(Node attr,
244 | String mBeanName, String mBeanPublishName, String mBeanDMax) {
245 | return makeMBeanAttribute(attr, mBeanName, mBeanPublishName, mBeanDMax,
246 | null);
247 | }
248 |
249 | private MBeanAttribute makeMBeanCompositeAttribute(Node composite,
250 | String mBeanName, String mBeanPublishName, String mBeanDMax,
251 | String attrName) {
252 | return makeMBeanAttribute(composite, mBeanName, mBeanPublishName,
253 | mBeanDMax, attrName);
254 | }
255 |
256 | private MBeanAttribute makeMBeanAttribute(Node attr, String mBeanName,
257 | String mBeanPublishName, String mBeanDMax, String attrName) {
258 | String name = selectParameterFromNode(attr, "name", "NULL");
259 | String units = selectParameterFromNode(attr, "units", "");
260 | String pname = selectParameterFromNode(attr, "pname", "");
261 | String slope = selectParameterFromNode(attr, "slope", "");
262 | String dMax = selectParameterFromNode(attr, "dmax", mBeanDMax);
263 | String type = selectParameterFromNode(attr, "type", "");
264 | GMetricType gType = GMetricType.valueOf(type.toUpperCase());
265 | GMetricSlope gSlope = GMetricSlope.valueOf(slope.toUpperCase());
266 | int dMaxInt = parseDMax(dMax);
267 | String metricName = buildMetricName(processName, mBeanName,
268 | mBeanPublishName, name, pname);
269 |
270 | if (attrName == null) {
271 | return new MBeanAttribute(processName, name, null, gType, units,
272 | gSlope, metricName, dMaxInt);
273 | } else {
274 | return new MBeanAttribute(processName, attrName, name, gType,
275 | units, gSlope, metricName, dMaxInt);
276 | }
277 | }
278 |
279 | /**
280 | * Parses dMaxString, which is the value of dmax read in from a
281 | * configuration file.
282 | *
283 | * @param dMaxString
284 | * value read in from configuration
285 | * @return int value of dMaxString if parse is successful, 0 (default value)
286 | * otherwise
287 | */
288 | private int parseDMax(String dMaxString) {
289 | int dMax;
290 | try {
291 | dMax = Integer.parseInt(dMaxString);
292 | } catch (NumberFormatException e) {
293 | dMax = 0;
294 | }
295 | return dMax;
296 | }
297 |
298 | /**
299 | * Builds the metric name in ganglia
300 | *
301 | * @param process
302 | * the process name, or null if not used
303 | * @param mbeanName
304 | * the mbean name
305 | * @param mbeanPublishName
306 | * the mbean publish name, or null if not used
307 | * @param attribute
308 | * the mbean attribute name
309 | * @param attrPublishName
310 | * the mbean attribute publish name
311 | * @return the metric name
312 | */
313 | private String buildMetricName(String process, String mbeanName,
314 | String mbeanPublishName, String attribute, String attrPublishName) {
315 | StringBuilder buf = new StringBuilder();
316 | if (process != null) {
317 | buf.append(process);
318 | buf.append("_");
319 | }
320 | if (mbeanPublishName != null) {
321 | buf.append(mbeanPublishName);
322 | } else {
323 | buf.append(mbeanName);
324 | }
325 | buf.append("_");
326 | if (!"".equals(attrPublishName)) {
327 | buf.append(attrPublishName);
328 | } else {
329 | buf.append(attribute);
330 | }
331 | return buf.toString();
332 | }
333 |
334 | }
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/MBeanAttribute.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import info.ganglia.gmetric4j.Publisher;
4 | import info.ganglia.gmetric4j.gmetric.GMetricSlope;
5 | import info.ganglia.gmetric4j.gmetric.GMetricType;
6 |
7 | import java.lang.management.ManagementFactory;
8 | import java.util.logging.Level;
9 | import java.util.logging.Logger;
10 |
11 | import javax.management.MBeanServer;
12 | import javax.management.ObjectName;
13 | import javax.management.openmbean.CompositeData;
14 |
15 | /**
16 | * Data structure used to sample one attribute
17 | */
18 | class MBeanAttribute {
19 | private static Logger log = Logger.getLogger(JMXetricAgent.class.getName());
20 |
21 | private String process;
22 | private String attributeName;
23 | private String key;
24 | private String canonicalName;
25 | private String units;
26 | private GMetricType type;
27 | private GMetricSlope slope;
28 | private String publishName;
29 | private int dmax;
30 | private MBeanServer mbs;
31 | private MBeanSampler sampler;
32 |
33 | public MBeanAttribute(MBeanSampler sampler, String process,
34 | String attributeName, String compositeKey, GMetricType type,
35 | String units, GMetricSlope slope, String publishName, int dmax) {
36 | this.sampler = sampler;
37 | this.process = process;
38 | this.key = compositeKey;
39 | this.canonicalName = attributeName + "." + compositeKey;
40 | this.attributeName = attributeName;
41 | this.units = units;
42 | this.type = type;
43 | this.slope = slope;
44 | this.publishName = publishName;
45 | this.dmax = dmax;
46 | }
47 |
48 | public MBeanAttribute(String process, String attributeName,
49 | String compositeKey, GMetricType type, String units,
50 | GMetricSlope slope, String publishName, int dmax) {
51 | this(null, process, attributeName, compositeKey, type, units, slope,
52 | publishName, dmax);
53 | }
54 |
55 | public MBeanAttribute(String process, String attributeName,
56 | GMetricType type, String units, GMetricSlope slope,
57 | String publishName, int dmax) {
58 | this(process, attributeName, null, type, units, slope, publishName,
59 | dmax);
60 | }
61 |
62 | public void publish(ObjectName objectName) {
63 | try {
64 | String value = null;
65 | if (mbs == null) {
66 | mbs = ManagementFactory.getPlatformMBeanServer();
67 | }
68 | Object o = mbs.getAttribute(objectName, attributeName);
69 | if (o instanceof CompositeData) {
70 | CompositeData cd = (CompositeData) o;
71 | if (key != null) {
72 | Object val = cd.get(key);
73 | log.fine("Sampling " + objectName + " attribute "
74 | + canonicalName + ":" + val);
75 | value = val.toString();
76 | }
77 | } else {
78 | if (null != o) {
79 | value = o.toString();
80 | log.fine("Sampling " + objectName + " attribute "
81 | + canonicalName + ":" + o);
82 | } else {
83 | log.fine("Not sampling " + objectName + " attribute "
84 | + canonicalName + " as value is null");
85 | }
86 | }
87 | if (null != value) {
88 | Publisher gm = sampler.getPublisher();
89 | // log.finer("Announcing metric " + this.toString() + " value="
90 | // + value );
91 | gm.publish(process, publishName, value, getType(), getSlope(),
92 | sampler.getDelay(), getDMax(), getUnits());
93 | }
94 |
95 | } catch (javax.management.InstanceNotFoundException ex) {
96 | log.warning("Exception when getting " + objectName + " "
97 | + canonicalName);
98 | } catch (Exception ex) {
99 | log.log(Level.WARNING, "Exception when getting " + objectName + " "
100 | + canonicalName, ex);
101 | }
102 | }
103 |
104 | public String getAttributeName() {
105 | return attributeName;
106 | }
107 |
108 | public String getCanonicalName() {
109 | return canonicalName;
110 | }
111 |
112 | public String getUnits() {
113 | return units;
114 | }
115 |
116 | public GMetricType getType() {
117 | return type;
118 | }
119 |
120 | public GMetricSlope getSlope() {
121 | return slope;
122 | }
123 |
124 | public String getKey() {
125 | return key;
126 | }
127 |
128 | public int getDMax() {
129 | return dmax;
130 | }
131 |
132 | public MBeanSampler getSampler() {
133 | return sampler;
134 | }
135 |
136 | public void setSampler(MBeanSampler mBeanSampler) {
137 | sampler = mBeanSampler;
138 | }
139 |
140 | @Override
141 | public String toString() {
142 | StringBuilder buf = new StringBuilder();
143 | buf.append("attributeName=").append(attributeName);
144 | buf.append(" canonicalName=").append(canonicalName);
145 | buf.append(" units=").append(units);
146 | buf.append(" type=").append(type);
147 | buf.append(" slope=").append(slope);
148 | buf.append(" publishName=").append(publishName);
149 | buf.append(" dmax=").append(dmax);
150 | return buf.toString();
151 | }
152 |
153 | @Override
154 | public boolean equals(Object obj) {
155 | if (obj == null)
156 | return false;
157 | if (obj == this)
158 | return true;
159 | if (this.getClass() != obj.getClass())
160 | return false;
161 | MBeanAttribute attribute = (MBeanAttribute) obj;
162 | return canonicalName.equals(attribute.getCanonicalName());
163 | }
164 |
165 | @Override
166 | public int hashCode() {
167 | int hash = 7;
168 | hash = 79
169 | * hash
170 | + (this.canonicalName != null ? this.canonicalName.hashCode()
171 | : 0);
172 | return hash;
173 | }
174 | }
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/MBeanHolder.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import info.ganglia.gmetric4j.gmetric.GMetricSlope;
4 | import info.ganglia.gmetric4j.gmetric.GMetricType;
5 |
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | import javax.management.ObjectName;
10 |
11 | /**
12 | * Data structure to hold and query mbean
13 | */
14 | class MBeanHolder {
15 | /**
16 | *
17 | */
18 | private final MBeanSampler mBeanSampler;
19 | private String process;
20 | private ObjectName objectName;
21 | private Set attributes = new HashSet();
22 |
23 | public MBeanHolder(MBeanSampler mBeanSampler, String process, String name)
24 | throws Exception {
25 | this.mBeanSampler = mBeanSampler;
26 | this.process = process;
27 | objectName = new ObjectName(name);
28 | }
29 |
30 | public void addAttribute(String attributeName, String compositeName,
31 | GMetricType type, GMetricSlope slope, String units,
32 | String publishName, int dmax) {
33 | attributes.add(new MBeanAttribute(mBeanSampler, process, attributeName,
34 | compositeName, type, units, slope, publishName, dmax));
35 | }
36 |
37 | public void addAttribute(MBeanAttribute attr) {
38 | attributes.add(attr);
39 | }
40 |
41 | public void publish() {
42 | for (MBeanAttribute attr : attributes) {
43 | try {
44 | attr.publish(objectName);
45 | } catch (Exception ex) {
46 | ex.printStackTrace();
47 | }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/MBeanSampler.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import info.ganglia.gmetric4j.GSampler;
4 | import info.ganglia.gmetric4j.gmetric.GMetricSlope;
5 | import info.ganglia.gmetric4j.gmetric.GMetricType;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 | import java.util.logging.Logger;
10 |
11 | /**
12 | * A class that samples MBeans and publishes attributes to Ganglia. This
13 | * classes' run method will be called periodically to sample the mbeans.
14 | */
15 | public class MBeanSampler extends GSampler {
16 |
17 | private static Logger log = Logger.getLogger(JMXetricAgent.class.getName());
18 |
19 | /*
20 | * The internal data structure is a hashmap of key=mbean name
21 | */
22 | private Map mbeanMap = new HashMap();
23 |
24 | /**
25 | * Creates an MBeanSampler
26 | *
27 | * @param delay
28 | * the sample interval in seconds
29 | * @param process
30 | * the process name that is appended to metrics
31 | */
32 | public MBeanSampler(int initialDelay, int delay, String process) {
33 | super(initialDelay, delay, process);
34 | }
35 |
36 | /**
37 | * Adds a mbean name/attribute pair to be sampled
38 | *
39 | * @param mbean
40 | * the name of the mbean
41 | * @param attribute
42 | * the name of the attribute
43 | * @param composite
44 | * the name of the composite
45 | * @param publishName
46 | * the name to publish this attribute on
47 | * @param tmax
48 | * maximum time (in seconds) between gmetric calls
49 | * @param dmax
50 | * lifetime (in seconds) of this metric (use 0 for always alive)
51 | * @throws java.lang.Exception
52 | */
53 | public void addMBeanAttribute(String mbean, String attribute,
54 | String composite, GMetricType type, String units,
55 | GMetricSlope slope, String publishName, int dmax) throws Exception {
56 | MBeanAttribute mba = new MBeanAttribute(this, process, attribute,
57 | composite, type, units, slope, publishName, dmax);
58 | addMBeanAttribute(mbean, mba);
59 | }
60 |
61 | /**
62 | * Adds a mbean name/attribute pair to be sampled
63 | *
64 | * @param mbean
65 | * the name of the mbean
66 | * @param attribute
67 | * the name of the attribute
68 | * @param composite
69 | * the name of the composite
70 | * @param publishName
71 | * the name to publish this attribute on
72 | * @throws java.lang.Exception
73 | */
74 | public void addMBeanAttribute(String mbean, String attribute,
75 | String composite, GMetricType type, String units,
76 | GMetricSlope slope, String publishName) throws Exception {
77 | addMBeanAttribute(mbean, attribute, composite, type, units, slope,
78 | publishName, 0);
79 | }
80 |
81 | /**
82 | * Adds a mbean name/attribute pair to be sampled
83 | *
84 | * @param mbean
85 | * the name of the mbean
86 | * @param attribute
87 | * the name of the attribute
88 | * @param publishName
89 | * the name to publish this attribute on
90 | * @throws java.lang.Exception
91 | */
92 | public void addMBeanAttribute(String mbean, String attribute,
93 | GMetricType type, String units, GMetricSlope slope,
94 | String publishName) throws Exception {
95 | addMBeanAttribute(mbean, attribute, null, type, units, slope,
96 | publishName);
97 | }
98 |
99 | /**
100 | * Adds an {@link info.ganglia.jmxetric.MBeanAttribute} to be sampled.
101 | *
102 | * @param mbean
103 | * name of the mbean
104 | * @param attr
105 | * attribute to be sample
106 | * @throws Exception
107 | */
108 | public void addMBeanAttribute(String mbean, MBeanAttribute attr)
109 | throws Exception {
110 | MBeanHolder mbeanHolder = mbeanMap.get(mbean);
111 | if (mbeanHolder == null) {
112 | mbeanHolder = new MBeanHolder(this, process, mbean);
113 | mbeanMap.put(mbean, mbeanHolder);
114 | }
115 | mbeanHolder.addAttribute(attr);
116 | log.info("Added attribute " + attr + " to " + mbean);
117 | }
118 |
119 | /**
120 | * Called by the JMXAgent periodically to sample the mbeans
121 | */
122 | public void run() {
123 | try {
124 | for (String mbean : mbeanMap.keySet()) {
125 | MBeanHolder h = mbeanMap.get(mbean);
126 | h.publish();
127 | }
128 | } catch (Exception ex) {
129 | // Robust exception to prevent thread death
130 | log.warning("Exception thrown sampling Mbeans");
131 | log.throwing(this.getClass().getName(),
132 | "Exception thrown sampling Mbeans:", ex);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/MBeanScanner.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 | import java.io.PrintStream;
6 | import java.lang.management.ManagementFactory;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.Set;
11 | import java.util.Vector;
12 |
13 | import javax.management.AttributeNotFoundException;
14 | import javax.management.InstanceNotFoundException;
15 | import javax.management.IntrospectionException;
16 | import javax.management.MBeanAttributeInfo;
17 | import javax.management.MBeanException;
18 | import javax.management.MBeanInfo;
19 | import javax.management.MBeanServer;
20 | import javax.management.ObjectInstance;
21 | import javax.management.ObjectName;
22 | import javax.management.ReflectionException;
23 | import javax.management.RuntimeMBeanException;
24 | import javax.management.openmbean.CompositeData;
25 | import javax.management.openmbean.CompositeType;
26 |
27 | /**
28 | * A utility class that scans the platform MBeanServer for registered
29 | * MBeans/MXBeans. The MBeans are queried and represented as private objects
30 | * These objects are then written using ConfigWriter to a
31 | * {@link java.io.PrintStream}.
32 | *
33 | */
34 | public class MBeanScanner {
35 | private static final String ERR_FILE = "%s can not be written to, using System.out instead.\n";
36 | private final MBeanServer mBeanServer = ManagementFactory
37 | .getPlatformMBeanServer();
38 |
39 | /**
40 | * Used mainly for testing purposed to output a test configuration file to
41 | * System.out. Also shows how to use this class.
42 | *
43 | * @param args
44 | */
45 | public static void main(String[] args) {
46 | PrintStream out = System.out;
47 | if (args.length > 0) {
48 | try {
49 | out = new PrintStream(new File(args[0]));
50 | } catch (FileNotFoundException e) {
51 | System.out.printf(ERR_FILE, args[0]);
52 | }
53 | }
54 | MBeanScanner mBeanScanner = new MBeanScanner();
55 | List configs = mBeanScanner.scan();
56 | ConfigWriter cw;
57 | cw = new ConfigWriter(out, configs);
58 | cw.write();
59 | }
60 |
61 | /**
62 | * Scans the platform MBean server for registered MBeans, creating
63 | * see Config objects to represent these MBeans.
64 | */
65 | public List scan() {
66 | Set mBeanObjects = mBeanServer.queryMBeans(null, null);
67 | List configs = getConfigForAllMBeans(mBeanObjects);
68 | return configs;
69 | }
70 |
71 | /**
72 | * Constructs a configuration for all MBeans.
73 | *
74 | * @param mBeanObjects
75 | * @return a list of Config for the MBeans
76 | */
77 | private List getConfigForAllMBeans(Set mBeanObjects) {
78 | List configs = new Vector();
79 | for (ObjectInstance objectInstance : mBeanObjects) {
80 | Config configMB = scanOneMBeanObject(objectInstance);
81 | configs.add(configMB);
82 | }
83 | return configs;
84 | }
85 |
86 | /**
87 | * Constructs the configuration for a single MBean. The configuration
88 | * includes the name, e.g. "java.util.loggin:type=Logging", and the
89 | * attributes belonging to that MBean.
90 | *
91 | * @param objectInstance
92 | * MBean object instance
93 | * @return configuration representing this MBean
94 | */
95 | private Config scanOneMBeanObject(ObjectInstance objectInstance) {
96 | MBeanConfig mBeanConfig = new MBeanConfig();
97 | ObjectName objectName = objectInstance.getObjectName();
98 | mBeanConfig.addField("name", objectName.getCanonicalName());
99 | scanMBeanAttributes(mBeanConfig, objectName);
100 | return mBeanConfig;
101 | }
102 |
103 | /**
104 | * Stores all attributes of an MBean into its MBeanConfig object
105 | *
106 | * @param mBeanConfig
107 | * the configuration object to store the attributes into
108 | * @param mBeanName
109 | * the name of the MBean object we are getting the attributes
110 | * from
111 | */
112 | private void scanMBeanAttributes(MBeanConfig mBeanConfig,
113 | ObjectName mBeanName) {
114 | MBeanInfo mBeanInfo;
115 | try {
116 | mBeanInfo = mBeanServer.getMBeanInfo(mBeanName);
117 | MBeanAttributeInfo[] infos = mBeanInfo.getAttributes();
118 | for (int i = 0; i < infos.length; i++) {
119 | MBeanAttributeConfig cMBAttr = makeConfigMBeanAttribute(
120 | mBeanName, infos[i]);
121 | mBeanConfig.addChild(cMBAttr);
122 | }
123 | } catch (IntrospectionException e) {
124 | System.err.println(e.getMessage());
125 | } catch (InstanceNotFoundException e) {
126 | System.err.println(e.getMessage());
127 | } catch (ReflectionException e) {
128 | System.err.println(e.getMessage());
129 | }
130 | }
131 |
132 | /**
133 | * Creates an object to represent a single attribute of an MBean. An
134 | * attribute can be a simple attribute, or made up composites.
135 | *
136 | * @param mBeanName
137 | * @param attributeInfo
138 | * @return an AttributeConfig for this MBean
139 | */
140 | private MBeanAttributeConfig makeConfigMBeanAttribute(ObjectName mBeanName,
141 | MBeanAttributeInfo attributeInfo) {
142 | // type determines if this should be composite
143 | Object attr;
144 | try {
145 | attr = mBeanServer.getAttribute(mBeanName,
146 | attributeInfo.getName());
147 | MBeanAttributeConfig config = new MBeanAttributeConfig();
148 | config.addField("name", attributeInfo.getName());
149 |
150 | if (attr == null) {
151 | return null;
152 | } else if (attr instanceof CompositeData) {
153 | addComposites(config, (CompositeData) attr);
154 | } else {
155 | config.addField("type",
156 | translateDataType(attributeInfo.getType()));
157 | }
158 | return config;
159 | } catch (RuntimeMBeanException e) {
160 | System.err.println(e.getMessage());
161 | } catch (AttributeNotFoundException e) {
162 | System.err.println(e.getMessage());
163 | } catch (InstanceNotFoundException e) {
164 | System.err.println(e.getMessage());
165 | } catch (MBeanException e) {
166 | System.err.println(e.getMessage());
167 | } catch (ReflectionException e) {
168 | System.err.println(e.getMessage());
169 | }
170 | return null;
171 | }
172 |
173 | /**
174 | * Adds the composite data of an MBean's attribute to an
175 | * MBeanAttributeConfig
176 | *
177 | * @param config
178 | * configuration which the composite belongs to
179 | * @param compositeData
180 | * object representing the composite data
181 | */
182 | private void addComposites(MBeanAttributeConfig config,
183 | CompositeData compositeData) {
184 | CompositeType compositeType = compositeData.getCompositeType();
185 | for (String key : compositeType.keySet()) {
186 | config.addChild(makeComposite(compositeType, key));
187 | }
188 | }
189 |
190 | /**
191 | * Makes a configuration for JMXetric that represents the composite tag
192 | *
193 | * @param compositeType
194 | * @param name
195 | * @return a CompositeConfig for a composite MBean
196 | */
197 | private MBeanCompositeConfig makeComposite(CompositeType compositeType,
198 | String name) {
199 | MBeanCompositeConfig config = new MBeanCompositeConfig();
200 | config.addField("name", name);
201 | String rawType = compositeType.getType(name).toString();
202 | config.addField("type", translateDataType(rawType));
203 | return config;
204 | }
205 |
206 | /**
207 | * The date types returned by JMX calls are no the same as those accepted by
208 | * JMXetric and Ganglia. This methods provides the translation. e.g.
209 | * java.lang.Long -> int8
210 | *
211 | * @param possibleData
212 | * the data type string returned by Java JMX methods
213 | * @return a data type string that Ganglia recognizes
214 | */
215 | private String translateDataType(String possibleData) {
216 | if (possibleData.equals("string") | possibleData.equals("int8")
217 | | possibleData.equals("uint8") | possibleData.equals("int16")
218 | | possibleData.equals("unit16") | possibleData.equals("int32")
219 | | possibleData.equals("uint32") | possibleData.equals("float")
220 | | possibleData.equals("double")) {
221 | return possibleData;
222 | }
223 | if (possibleData.contains("java.lang.Long")) {
224 | return "int8";
225 | } else if (possibleData.contains("java.lang.Integer")) {
226 | return "int32";
227 | } else if (possibleData.contains("java.lang.Float")) {
228 | return "int32";
229 | }
230 | return "string";
231 | }
232 |
233 | /* Data types that represent the MBean configuration */
234 |
235 | /**
236 | * Config is a super class that represents a type of configuration that is
237 | * fed into JMXetric.
238 | */
239 | private class Config {
240 | /* name of this Config, this is the name of the XML tag */
241 | String name;
242 | /* used to determine the XML tag will be self-closing */
243 | boolean hasChildren = false;
244 | /* a map of the parameters in the tag, e.g. delay, name, pname */
245 | Map fields = new HashMap();
246 | /* a list of inner/children Config */
247 | List children = new Vector();
248 |
249 | /* Users are not supposed to instantiate this class */
250 | private Config() {
251 | };
252 |
253 | /**
254 | * Adds a new field to this Config. This is written as a parameter in
255 | * this XML tag.
256 | *
257 | * @param key
258 | * the name of this key, e.g. "delay", "name"
259 | * @param value
260 | * value of this key, e.g. "0", "60", "java.lang:type=Memory"
261 | */
262 | void addField(String key, String value) {
263 | fields.put(key, value);
264 | }
265 |
266 | /**
267 | * Adds a Config to the list of children this Config has
268 | *
269 | * @param config
270 | * child Config to be added to this
271 | */
272 | void addChild(Config config) {
273 | if (config == null) {
274 | return; // ensure that the children contains no null values
275 | }
276 | if (hasChildren == false) {
277 | hasChildren = true;
278 | }
279 | children.add(config);
280 | }
281 |
282 | /**
283 | * A String representation of this Config, includes the name and the
284 | * fields.
285 | */
286 | @Override
287 | public String toString() {
288 | return name + " " + fieldsToString();
289 | }
290 |
291 | /**
292 | * Printable representation of all the fields of this Config
293 | *
294 | * @return A String with all the fields in this format =""
295 | */
296 | public String fieldsToString() {
297 | String result = "";
298 | for (String key : fields.keySet()) {
299 | result += key + "=\"" + fields.get(key) + "\" ";
300 | }
301 | // remove the trailing whitespace
302 | return result.substring(0, result.length() - 1);
303 | }
304 | }
305 |
306 | /**
307 | * Represents a configuration with the name "mbean". This is the ""
308 | * tag in the XML configuration file.
309 | */
310 | private class MBeanConfig extends Config {
311 | public MBeanConfig() {
312 | this.name = "mbean";
313 | }
314 | }
315 |
316 | /**
317 | * Represents a configuration with the name "attribute". This is the
318 | * "" tag in the XML configuration file.
319 | */
320 | private class MBeanAttributeConfig extends Config {
321 | public MBeanAttributeConfig() {
322 | this.name = "attribute";
323 | }
324 | }
325 |
326 | /**
327 | * Represents a configuration with the name "composite". This is the
328 | * "" tag in the XML configuration file.
329 | */
330 | private class MBeanCompositeConfig extends Config {
331 | public MBeanCompositeConfig() {
332 | this.name = "composite";
333 | }
334 | }
335 |
336 | /**
337 | * Writes the configuration to a {@link java.io.PrintStream}. The output is
338 | * in the XML format, which is what JMXetric reads in.
339 | */
340 | private static class ConfigWriter {
341 | /* The output stream that the configuration will be written to. */
342 | private final PrintStream out;
343 | /* The list of configurations to be written. */
344 | private final List configs;
345 | /* System-specific new-line separator. */
346 | private static final String NL = System.getProperty("line.separator");
347 | /* XML Declaration used by JMXetric */
348 | private static final String XML_DECL = "";
349 | /* XML Doctype used by JMXetric */
350 | private static final String XML_DOCTYPE = ""
352 | + NL + " " + NL
353 | + " " + NL
354 | + " " + NL
355 | + " " + NL
356 | + " " + NL
357 | + " " + NL
358 | + " " + NL
359 | + " "
360 | + " " + NL
361 | + " " + NL
362 | + " " + NL
363 | + " " + NL
364 | + " " + NL
365 | + " " + NL
366 | + " " + NL
367 | + " " + NL
368 | + " " + NL
369 | + " " + NL
370 | + " " + NL
371 | + " " + NL
372 | + " " + NL
373 | + " " + NL
374 | + " " + NL
375 | + " " + NL
376 | + " " + NL
377 | + " " + NL
378 | + " " + NL
379 | + " " + NL
380 | + " " + NL + "]>";
381 |
382 | public ConfigWriter(PrintStream outputStream, List config) {
383 | this.out = outputStream;
384 | this.configs = config;
385 | }
386 |
387 | /**
388 | * Write the configuration out to the PrintStream out.
389 | */
390 | public void write() {
391 | if (configs == null)
392 | return;
393 | StringBuilder sb = new StringBuilder();
394 | sb.append(XML_DECL + NL);
395 | sb.append(XML_DOCTYPE + NL);
396 | sb.append("" + NL);
397 | sb.append(" " + NL);
398 | sb.append(" " + NL);
399 | String output = buildXmlTagsFromList(configs, " ");
400 | sb.append(output);
401 | sb.append(" " + NL);
402 | sb.append("" + NL);
403 | out.print(sb.toString());
404 | }
405 |
406 | /**
407 | * Builds a String of XML tags out of a list of Config. Each Config is
408 | * built by {@link buildConfig} and the result is interspersed with new
409 | * lines for readability.
410 | *
411 | * @param configs
412 | * list of Config to be converted to XML tags
413 | * @param indent
414 | * string that is prefixed to each XML tag
415 | * @return string of XML tags for list
416 | */
417 | public String buildXmlTagsFromList(List configs, String indent) {
418 | StringBuilder sb = new StringBuilder();
419 | for (Config config : configs) {
420 | sb.append(buildXmlTag(config, indent) + NL);
421 | }
422 | return sb.toString();
423 | }
424 |
425 | /**
426 | * Builds a XML tag for config. The tag with have indent prefixed.
427 | *
428 | * @param config
429 | * to be converted to an XML tag
430 | * @param indent
431 | * indentation string that is prefixed to the tag
432 | * @return XML tag for this config
433 | */
434 | private String buildXmlTag(Config config, String indent) {
435 | StringBuffer sb = new StringBuffer();
436 | sb.append(indent + "<" + config.name + " "
437 | + config.fieldsToString());
438 | if (!config.hasChildren) {
439 | // self-closing XML tag
440 | sb.append("/>");
441 | } else {
442 | sb.append(">" + NL);
443 | sb.append(buildXmlTagsFromList(config.children, " " + indent));
444 | sb.append(indent + "" + config.name + ">");
445 | }
446 | return sb.toString();
447 | }
448 | }
449 | }
450 |
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/XMLConfigurationService.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import info.ganglia.gmetric4j.gmetric.GMetric;
4 |
5 | import java.io.IOException;
6 |
7 | import javax.xml.xpath.XPath;
8 | import javax.xml.xpath.XPathConstants;
9 | import javax.xml.xpath.XPathExpressionException;
10 | import javax.xml.xpath.XPathFactory;
11 |
12 | import org.w3c.dom.Node;
13 | import org.w3c.dom.NodeList;
14 | import org.xml.sax.InputSource;
15 |
16 | /**
17 | * Configures the JMXetricAgent based on the XML config file
18 | */
19 | public class XMLConfigurationService {
20 |
21 | private final static XPath xpath = XPathFactory.newInstance().newXPath();
22 |
23 | /**
24 | * Configures the JMXetricAgent based on the supplied agentArgs Command line
25 | * arguments overwrites XML arguments. Any arguments that is required but no
26 | * supplied will be defaulted.
27 | *
28 | * @param agent
29 | * the agent to configure
30 | * @param agentArgs
31 | * the agent arguments list
32 | * @throws java.lang.Exception
33 | */
34 | public static void configure(JMXetricAgent agent, String agentArgs)
35 | throws Exception {
36 | CommandLineArgs args = new CommandLineArgs(agentArgs);
37 | InputSource inputSource = new InputSource(args.getConfig());
38 |
39 | configureGanglia(agent, inputSource, args);
40 |
41 | configureJMXetric(agent, inputSource, args);
42 | }
43 |
44 | private static void configureGanglia(JMXetricAgent agent,
45 | InputSource inputSource, CommandLineArgs args) throws IOException,
46 | XPathExpressionException {
47 | GangliaXmlConfigurationService gangliaConfigService = new GangliaXmlConfigurationService(
48 | inputSource, args);
49 | GMetric gmetric = gangliaConfigService.getConfig();
50 | agent.setGmetric(gmetric);
51 | }
52 |
53 | private static void configureJMXetric(JMXetricAgent agent,
54 | InputSource inputSource, CommandLineArgs args) throws Exception {
55 | JMXetricXmlConfigurationService jmxetricConfigService = new JMXetricXmlConfigurationService(
56 | agent, inputSource, args.getProcessName());
57 | jmxetricConfigService.configure();
58 | }
59 |
60 | String selectParameterFromNode(Node ganglia, String attributeName,
61 | String defaultValue) {
62 | if (ganglia == null) {
63 | return defaultValue;
64 | }
65 | Node node = ganglia.getAttributes().getNamedItem(attributeName);
66 | if (node == null) {
67 | return defaultValue;
68 | }
69 | String value = node.getNodeValue();
70 | if (value == null) {
71 | return defaultValue;
72 | }
73 | return value;
74 | }
75 |
76 | protected static Node getXmlNode(String expr, InputSource inputSource)
77 | throws XPathExpressionException {
78 | return (Node) xpath.evaluate(expr, inputSource, XPathConstants.NODE);
79 | }
80 |
81 | NodeList getXmlNodeList(String expression, InputSource inputSource)
82 | throws XPathExpressionException {
83 | NodeList samples = (NodeList) xpath.evaluate(expression, inputSource,
84 | XPathConstants.NODESET);
85 | return samples;
86 | }
87 |
88 | NodeList getXmlNodeSet(String expression, Node node)
89 | throws XPathExpressionException {
90 | NodeList samples = (NodeList) xpath.evaluate(expression, node,
91 | XPathConstants.NODESET);
92 | return samples;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/info/ganglia/jmxetric/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Provides a JVM agent that polls MBeans periodically and publishes the results to Ganglia
8 |
9 | Package Specification
10 |
11 | Related Documentation
12 |
13 | For a description of Ganglia, please see:
14 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Premain-Class: info.ganglia.jmxetric.JMXetricAgent
3 | Boot-Class-Path: remotetea-oncrpc.jar gmetric4j.jar
4 | Can-Redefine-Classes: false
5 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/CommandLineArgsTest.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | public class CommandLineArgsTest {
8 | private CommandLineArgs commandLineArgs;
9 |
10 | /**
11 | * IMPT: Take note of this special case. When the `config` parameter is
12 | * missing from the command line, we cannot return null. We need a default
13 | * location for the XML file to be able to read configuration from.
14 | */
15 | private static final String DEFAULT_CONFIG = "jmxetric.xml";
16 |
17 | @Test
18 | public void testCommandLineArgs_emptyOrNullArguments() {
19 | commandLineArgs = new CommandLineArgs(null);
20 | assertCommandLineArgs(null, null, DEFAULT_CONFIG, null, null, null,
21 | null);
22 |
23 | commandLineArgs = new CommandLineArgs("");
24 | assertCommandLineArgs(null, null, DEFAULT_CONFIG, null, null, null,
25 | null);
26 | }
27 |
28 | @Test
29 | public void testCommandLineArgs_allParamsPresent() {
30 | String args = "host=localhost,port=8649,config=etc/jmxetric.xml,mode=multicast,wireformat31x=true,process=ProcessName,spoof=SpoofName";
31 | commandLineArgs = new CommandLineArgs(args);
32 | assertCommandLineArgs("localhost", "8649", "etc/jmxetric.xml",
33 | "multicast", "true", "ProcessName", "SpoofName");
34 | }
35 |
36 | @Test
37 | public void testCommandLineArgs_missingHost() {
38 | String args = "port=8649,config=etc/jmxetric.xml,mode=multicast,wireformat31x=true,process=ProcessName,spoof=SpoofName";
39 | commandLineArgs = new CommandLineArgs(args);
40 | assertCommandLineArgs(null, "8649", "etc/jmxetric.xml", "multicast",
41 | "true", "ProcessName", "SpoofName");
42 | }
43 |
44 | @Test
45 | public void testCommandLineArgs_missingPort() {
46 | String args = "host=localhost,config=etc/jmxetric.xml,mode=multicast,wireformat31x=true,process=ProcessName,spoof=SpoofName";
47 | commandLineArgs = new CommandLineArgs(args);
48 | assertCommandLineArgs("localhost", null, "etc/jmxetric.xml",
49 | "multicast", "true", "ProcessName", "SpoofName");
50 | }
51 |
52 | @Test
53 | public void testCommandLineArgs_missingConfig() {
54 | String args = "host=localhost,port=8649,mode=multicast,wireformat31x=true,process=ProcessName,spoof=SpoofName";
55 | commandLineArgs = new CommandLineArgs(args);
56 | assertCommandLineArgs("localhost", "8649", DEFAULT_CONFIG, "multicast",
57 | "true", "ProcessName", "SpoofName");
58 | }
59 |
60 | @Test
61 | public void testCommandLineArgs_missingMode() {
62 | String args = "host=localhost,port=8649,config=etc/jmxetric.xml,wireformat31x=true,process=ProcessName,spoof=SpoofName";
63 | commandLineArgs = new CommandLineArgs(args);
64 | assertCommandLineArgs("localhost", "8649", "etc/jmxetric.xml", null,
65 | "true", "ProcessName", "SpoofName");
66 | }
67 |
68 | @Test
69 | public void testCommandLineArgs_missingWireformat() {
70 | String args = "host=localhost,port=8649,config=etc/jmxetric.xml,mode=multicast,process=ProcessName,spoof=SpoofName";
71 | commandLineArgs = new CommandLineArgs(args);
72 | assertCommandLineArgs("localhost", "8649", "etc/jmxetric.xml",
73 | "multicast", null, "ProcessName", "SpoofName");
74 | }
75 |
76 | @Test
77 | public void testCommandLineArgs_missingProcessName() {
78 | String args = "host=localhost,port=8649,config=etc/jmxetric.xml,mode=multicast,wireformat31x=true,spoof=SpoofName";
79 | commandLineArgs = new CommandLineArgs(args);
80 | assertCommandLineArgs("localhost", "8649", "etc/jmxetric.xml",
81 | "multicast", "true", null, "SpoofName");
82 | }
83 |
84 | @Test
85 | public void testCommandLineArgs_missingSpoofName() {
86 | String args = "host=localhost,port=8649,config=etc/jmxetric.xml,mode=multicast,wireformat31x=true,process=ProcessName";
87 | commandLineArgs = new CommandLineArgs(args);
88 | assertCommandLineArgs("localhost", "8649", "etc/jmxetric.xml",
89 | "multicast", "true", "ProcessName", null);
90 | }
91 |
92 | private void assertCommandLineArgs(String host, String port, String config,
93 | String mode, String wireformat, String processName, String spoof) {
94 | assertEquals(host, commandLineArgs.getHost());
95 | assertEquals(port, commandLineArgs.getPort());
96 | assertEquals(config, commandLineArgs.getConfig());
97 | assertEquals(mode, commandLineArgs.getMode());
98 | assertEquals(wireformat, commandLineArgs.getWireformat());
99 | assertEquals(processName, commandLineArgs.getProcessName());
100 | assertEquals(spoof, commandLineArgs.getSpoof());
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/Example.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import java.lang.management.ManagementFactory;
4 | import java.util.concurrent.Executors;
5 | import java.util.concurrent.ScheduledExecutorService;
6 | import java.util.concurrent.ThreadFactory;
7 | import java.util.concurrent.TimeUnit;
8 | import java.util.concurrent.atomic.AtomicInteger;
9 |
10 | import javax.management.MBeanServer;
11 | import javax.management.ObjectName;
12 |
13 | /**
14 | * MXBean implementation used for testing
15 | * @author humphrej
16 | *
17 | */
18 | public class Example implements TestExampleMXBean {
19 | private AtomicInteger counter = new AtomicInteger(0);
20 | private ScheduledExecutorService executor = null ;
21 |
22 | public Example() {
23 | executor = Executors.newSingleThreadScheduledExecutor( new ThreadFactory() {
24 | public Thread newThread(Runnable r) {
25 | Thread t = new Thread( r );
26 | t.setName("ExampleMBean");
27 | return t ;
28 | }
29 | });
30 | }
31 |
32 | public void start() {
33 | executor.scheduleAtFixedRate( new Runnable() {
34 | public void run() {
35 | counter.incrementAndGet();
36 | }
37 | }, 0, 1, TimeUnit.SECONDS);
38 | }
39 |
40 | public void stop() {
41 | executor.shutdown();
42 | }
43 | public double getDouble() {
44 | return DOUBLE_VALUE ;
45 | }
46 | public float getFloat() {
47 | return FLOAT_VALUE;
48 | }
49 | public int getInt() {
50 | return INT_VALUE;
51 | }
52 | public long getLong() {
53 | return LONG_VALUE;
54 | }
55 | public String getString() {
56 | return STRING_VALUE;
57 | }
58 | public int getCounter() {
59 | return counter.get();
60 | }
61 | public ExampleComposite getComposite() {
62 | return new ExampleComposite(ExampleComposite.DATE_VALUE,
63 | ExampleComposite.INT_VALUE,
64 | ExampleComposite.STRING_VALUE);
65 | }
66 | public static void register() {
67 | try {
68 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
69 | ObjectName name = new ObjectName("jmxetric:type=TestExample");
70 | Example mbean = new Example();
71 | mbs.registerMBean(mbean, name);
72 | } catch (Exception ex ){
73 | ex.printStackTrace();
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/ExampleComposite.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import java.beans.ConstructorProperties;
4 | import java.util.Date;
5 |
6 | /**
7 | * Class used to test composite attribute of an MXBean
8 | * @author humphrej
9 | *
10 | */
11 | public class ExampleComposite {
12 |
13 | public static final Date DATE_VALUE=new Date(1000);
14 | public static final int INT_VALUE=29111974;
15 | public static final String STRING_VALUE="WIBBLE";
16 |
17 | private final Date date;
18 | private final int integer;
19 | private final String name;
20 |
21 | @ConstructorProperties({"date", "integer", "name"})
22 | public ExampleComposite(Date date, int integer, String name) {
23 | this.date = date;
24 | this.integer = integer;
25 | this.name = name;
26 | }
27 |
28 | public Date getDate() {
29 | return date;
30 | }
31 |
32 | public int getInteger() {
33 | return integer;
34 | }
35 |
36 | public String getName() {
37 | return name;
38 | }
39 |
40 | }
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/GangliaXmlConfigurationServiceTest.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import javax.xml.xpath.XPathExpressionException;
6 |
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.xml.sax.InputSource;
10 |
11 | public class GangliaXmlConfigurationServiceTest {
12 |
13 | private final String ARGS1 = "host=localhost,port=8649,wireformat31x=true,config=etc/jmxetric.xml";
14 | private final String ARGS1_EXPECTED = "GMetric host=localhost port=8649 mode=MULTICAST v31x=true spoof=null";
15 | private final String ARGS2 = "host=info.ganglia.com,port=9999,wireformat31x=false,config=etc/config/jmxetric.xml";
16 | private final String ARGS2_EXPECTED = "GMetric host=info.ganglia.com port=9999 mode=MULTICAST v31x=false spoof=null";
17 |
18 | private final String BAD_PORT = "host=info.ganglia.com,port=abcd,wireformat31x=false,config=etc/config/jmxetric.xml";
19 |
20 | private final String BAD_WIRE = "host=localhost,port=8649,wireformat31x=123,config=etc/jmxetric.xml";
21 | private final String BAD_WIRE_EXPECTED = "GMetric host=localhost port=8649 mode=MULTICAST v31x=false spoof=null";
22 |
23 | private InputSource inputSource;
24 | private CommandLineArgs args;
25 | private GangliaXmlConfigurationService g;
26 |
27 | @Before
28 | public void setUp() {
29 | inputSource = new InputSource("etc/jmxetric.xml");
30 | }
31 |
32 | @Test
33 | public void testGetConfig_withNoCommandLineArguments() throws Exception {
34 | args = new CommandLineArgs(null);
35 | g = new GangliaXmlConfigurationService(inputSource, args);
36 | try {
37 | assertEquals(ARGS1_EXPECTED, g.getConfigString());
38 | } catch (XPathExpressionException e) {
39 | e.printStackTrace();
40 | }
41 |
42 | args = new CommandLineArgs("");
43 | g = new GangliaXmlConfigurationService(inputSource, args);
44 | try {
45 | assertEquals(ARGS1_EXPECTED, g.getConfigString());
46 | } catch (XPathExpressionException e) {
47 | e.printStackTrace();
48 | }
49 | }
50 |
51 | @Test
52 | public void testGetConfig_withValidArguments() {
53 | args = new CommandLineArgs(ARGS1);
54 | g = new GangliaXmlConfigurationService(inputSource, args);
55 | try {
56 | assertEquals(ARGS1_EXPECTED, g.getConfigString());
57 | } catch (XPathExpressionException e) {
58 | e.printStackTrace();
59 | }
60 |
61 | args = new CommandLineArgs(ARGS2);
62 | g = new GangliaXmlConfigurationService(inputSource, args);
63 | try {
64 | assertEquals(ARGS2_EXPECTED, g.getConfigString());
65 | } catch (XPathExpressionException e) {
66 | e.printStackTrace();
67 | }
68 | }
69 |
70 | @Test(expected=NumberFormatException.class)
71 | public void testGetConfig_withBadPort() throws Exception {
72 | args = new CommandLineArgs(BAD_PORT);
73 | g = new GangliaXmlConfigurationService(inputSource, args);
74 | try {
75 | assertEquals(ARGS2_EXPECTED, g.getConfigString());
76 | } catch (XPathExpressionException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 |
81 | @Test
82 | public void testGetConfig_withBadWireFormat() throws Exception {
83 | args = new CommandLineArgs(BAD_WIRE);
84 | g = new GangliaXmlConfigurationService(inputSource, args);
85 | try {
86 | assertEquals(BAD_WIRE_EXPECTED, g.getConfigString());
87 | } catch (XPathExpressionException e) {
88 | e.printStackTrace();
89 | }
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/JMXetricAgentIT.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import static org.junit.Assert.*;
4 |
5 |
6 | import info.ganglia.gmetric4j.gmetric.GMetricResult;
7 | import info.ganglia.jmxetric.JMXetricAgent;
8 | import info.ganglia.jmxetric.XMLConfigurationService;
9 |
10 | import java.lang.management.ManagementFactory;
11 |
12 | import javax.management.MBeanServer;
13 | import javax.management.ObjectName;
14 |
15 | import org.junit.Before;
16 | import org.junit.Test;
17 | /**
18 | *
19 | */
20 | public class JMXetricAgentIT {
21 |
22 | @Before
23 | public void setUp() throws Exception {
24 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
25 | ObjectName name = new ObjectName("jmxetric:type=TestExample");
26 | Example mbean = new Example();
27 | mbs.registerMBean(mbean, name);
28 | }
29 |
30 | @Test
31 | public void testRun() {
32 | JMXetricAgent a = null ;
33 | try {
34 | a = new JMXetricAgent();
35 | XMLConfigurationService.configure(a, "host=localhost,port=8649,wireformat31x=true,config=src/test/resources/jmxetric_test.xml");
36 | a.start();
37 | Thread.sleep(5000);
38 | GMetricResult.GMetricDetail floatResult = GMetricResult.getGMetric("ProcessName_TestExample_Float");
39 | assertEquals( Float.toString( Example.FLOAT_VALUE) , floatResult.value);
40 | assertEquals( "both", floatResult.slope);
41 | // TODO Add asserts
42 | } catch ( Exception ex ) {
43 | ex.printStackTrace();
44 | fail("Exception thrown");
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/JMXetricXmlConfigurationServiceTest.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import static org.junit.Assert.*;
4 | import info.ganglia.gmetric4j.gmetric.GMetricType;
5 |
6 | import java.util.List;
7 |
8 | import javax.xml.xpath.XPath;
9 | import javax.xml.xpath.XPathConstants;
10 | import javax.xml.xpath.XPathExpressionException;
11 | import javax.xml.xpath.XPathFactory;
12 |
13 | import org.junit.Before;
14 | import org.junit.Test;
15 | import org.w3c.dom.Node;
16 | import org.w3c.dom.NodeList;
17 | import org.xml.sax.InputSource;
18 |
19 | public class JMXetricXmlConfigurationServiceTest {
20 | private JMXetricXmlConfigurationService jmxetric;
21 | private InputSource inputSource = new InputSource(
22 | "src/test/resources/jmxetric_test.xml");
23 | private XPath xpath = XPathFactory.newInstance().newXPath();
24 | @Before
25 | public void setUp() {
26 | jmxetric = new JMXetricXmlConfigurationService(null, inputSource,
27 | "TestProcessName");
28 | }
29 |
30 | @Test
31 | public void testAll() throws XPathExpressionException {
32 | NodeList samples = (NodeList) xpath.evaluate("/jmxetric-config/sample",
33 | inputSource, XPathConstants.NODESET);
34 | Node firstSample = samples.item(0);
35 | Node secondSample = samples.item(1);
36 |
37 | NodeList firstMBeans = (NodeList) xpath.evaluate("mbean", firstSample,
38 | XPathConstants.NODESET);
39 | NodeList secondMBeans = (NodeList) xpath.evaluate("mbean",
40 | secondSample, XPathConstants.NODESET);
41 |
42 | Node mBeanWithCompositeAttributes = firstMBeans.item(0);
43 | Node mBeanWithSimpleAttributes = secondMBeans.item(1);
44 | Node mBeanWithBoth = secondMBeans.item(0);
45 |
46 | try {
47 | testMBeanWithSimpleAttributes(mBeanWithSimpleAttributes);
48 | testMBeanWithCompositeAttributes(mBeanWithCompositeAttributes);
49 | testMBeanWithBothKinds(mBeanWithBoth);
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 | }
54 |
55 | private void testMBeanWithBothKinds(Node mBeanWithBoth) throws Exception {
56 | List attributes = jmxetric.getAttributesForMBean(
57 | mBeanWithBoth, "1");
58 |
59 | assertEquals(9, attributes.size());
60 | assertAttribute(attributes.get(0), "Int", "Int.null", 0,
61 | GMetricType.INT32, "");
62 | assertAttribute(attributes.get(1), "Long", "Long.null", 0,
63 | GMetricType.INT32, "");
64 | assertAttribute(attributes.get(6), "Composite", "Composite.date", 0,
65 | GMetricType.STRING, "bytes");
66 | assertAttribute(attributes.get(7), "Composite", "Composite.integer", 4,
67 | GMetricType.INT32, "bytes");
68 | assertAttribute(attributes.get(8), "Composite", "Composite.name", 0,
69 | GMetricType.INT32, "bytes");
70 |
71 | }
72 |
73 | private void assertAttribute(MBeanAttribute mBeanAttribute, String name,
74 | String canonicalName, int dMax, GMetricType type, String units) {
75 | assertEquals(name, mBeanAttribute.getAttributeName());
76 | assertEquals(canonicalName, mBeanAttribute.getCanonicalName());
77 | assertEquals(dMax, mBeanAttribute.getDMax());
78 | assertEquals(type, mBeanAttribute.getType());
79 | assertEquals(units, mBeanAttribute.getUnits());
80 | }
81 |
82 | private void testMBeanWithSimpleAttributes(Node mBeanWithSimpleAttributes)
83 | throws XPathExpressionException, Exception {
84 | List mbas = jmxetric.getAttributesForMBean(
85 | mBeanWithSimpleAttributes, "");
86 |
87 | assertEquals(2, mbas.size());
88 | assertAttribute(mbas.get(0), "ThreadCount", "ThreadCount.null", 0,
89 | GMetricType.INT16, "");
90 | assertAttribute(mbas.get(1), "DaemonThreadCount",
91 | "DaemonThreadCount.null", 0, GMetricType.INT16, "");
92 | }
93 |
94 | private void testMBeanWithCompositeAttributes(
95 | Node mBeanWithCompositeAttributes) throws XPathExpressionException,
96 | Exception {
97 | List mbas = jmxetric.getAttributesForMBean(
98 | mBeanWithCompositeAttributes, "");
99 | assertEquals(8, mbas.size());
100 |
101 | assertAttribute(mbas.get(0), "HeapMemoryUsage", "HeapMemoryUsage.init",
102 | 0, GMetricType.INT32, "bytes");
103 |
104 | assertAttribute(mbas.get(0), "HeapMemoryUsage", "HeapMemoryUsage.init",
105 | 0, GMetricType.INT32, "bytes");
106 |
107 | assertAttribute(mbas.get(1), "HeapMemoryUsage",
108 | "HeapMemoryUsage.committed", 0, GMetricType.INT32, "bytes");
109 |
110 | assertAttribute(mbas.get(2), "HeapMemoryUsage", "HeapMemoryUsage.used",
111 | 0, GMetricType.INT32, "bytes");
112 |
113 | assertAttribute(mbas.get(3), "HeapMemoryUsage", "HeapMemoryUsage.max",
114 | 0, GMetricType.INT32, "bytes");
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/MBeanSamplerTest.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import info.ganglia.gmetric4j.Publisher;
6 | import info.ganglia.gmetric4j.gmetric.GMetricSlope;
7 | import info.ganglia.gmetric4j.gmetric.GMetricType;
8 | import info.ganglia.gmetric4j.gmetric.GangliaException;
9 | import info.ganglia.jmxetric.MBeanSampler;
10 |
11 | import java.lang.management.ManagementFactory;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 |
15 | import javax.management.MBeanServer;
16 | import javax.management.ObjectName;
17 |
18 | import org.junit.After;
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | /**
23 | *
24 | */
25 | public class MBeanSamplerTest {
26 |
27 | public static String BEAN_NAME="jmxetric:type=Test.Example";
28 | private class MyPublisher implements Publisher
29 | {
30 | Map results = new HashMap();
31 |
32 | public void publish(String processName, String attributeName,
33 | String value, GMetricType type, GMetricSlope slope, String units)
34 | throws GangliaException {
35 | results.put(attributeName, value);
36 | }
37 |
38 | @Override
39 | public void publish(String processName, String attributeName,
40 | String value, GMetricType type, GMetricSlope slope, int delay,
41 | int lifetime, String units) throws GangliaException {
42 | results.put(attributeName, value);
43 | }
44 |
45 | public String getResult( String attributeName ) {
46 | return results.get(attributeName);
47 | }
48 |
49 | }
50 | @Before
51 | public void setUp() throws Exception {
52 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
53 | ObjectName name = new ObjectName(BEAN_NAME);
54 | Example mbean = new Example();
55 | mbs.registerMBean(mbean, name);
56 | }
57 | @After
58 | public void tearDown() throws Exception {
59 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
60 | ObjectName name = new ObjectName(BEAN_NAME);
61 | mbs.unregisterMBean(name);
62 | }
63 | /**
64 | * Test of attribute sample, type Long
65 | */
66 | @Test
67 | public void sampleLong() throws Exception {
68 | MBeanSampler sampler = new MBeanSampler(0, 30000, "TEST") ;
69 | MyPublisher publisher = new MyPublisher() ;
70 | sampler.setPublisher(publisher);
71 | sampler.addMBeanAttribute(BEAN_NAME, "Long", GMetricType.INT32,
72 | "bytes", GMetricSlope.BOTH, "Longer");
73 | sampler.run() ;
74 | String value = publisher.getResult("Longer");
75 | assertEquals( Example.LONG_VALUE, Long.valueOf(value ));
76 | }
77 | /**
78 | * Test of attribute sample, type String
79 | */
80 | @Test
81 | public void sampleComposite() throws Exception {
82 | MBeanSampler sampler = new MBeanSampler(0, 30000, "TEST") ;
83 | MyPublisher publisher = new MyPublisher() ;
84 | sampler.setPublisher(publisher);
85 |
86 | String compNamePublishName = "compName";
87 | sampler.addMBeanAttribute(BEAN_NAME,
88 | "Composite",
89 | "name",
90 | GMetricType.STRING,
91 | "bytes",
92 | GMetricSlope.BOTH,
93 | compNamePublishName);
94 |
95 | String compIntPublishName = "compInt";
96 | sampler.addMBeanAttribute(BEAN_NAME,
97 | "Composite",
98 | "integer",
99 | GMetricType.STRING,
100 | "bytes",
101 | GMetricSlope.BOTH,
102 | compIntPublishName);
103 |
104 | String compDatePublishName = "compDate";
105 | sampler.addMBeanAttribute(BEAN_NAME,
106 | "Composite",
107 | "date",
108 | GMetricType.STRING,
109 | "bytes",
110 | GMetricSlope.BOTH,
111 | compDatePublishName);
112 |
113 | sampler.run();
114 |
115 | assertEquals( ExampleComposite.STRING_VALUE,
116 | publisher.getResult(compNamePublishName) );
117 |
118 | assertEquals( "" + ExampleComposite.INT_VALUE,
119 | publisher.getResult(compIntPublishName) );
120 |
121 | assertEquals( "" + ExampleComposite.DATE_VALUE,
122 | publisher.getResult(compDatePublishName) );
123 | }
124 | /**
125 | * Test of attribute sample, type int, slope positive
126 | */
127 | @Test
128 | public void sampleCounter() throws Exception {
129 | MBeanSampler sampler = new MBeanSampler(0, 1, "TEST") ;
130 | MyPublisher publisher = new MyPublisher() ;
131 | sampler.setPublisher(publisher);
132 | sampler.addMBeanAttribute(BEAN_NAME, "Counter", GMetricType.INT32,
133 | "units", GMetricSlope.POSITIVE, "counter");
134 | sampler.run() ;
135 | String value = publisher.getResult("counter");
136 | assertTrue( Integer.valueOf(value) >= 0);
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/src/test/java/info/ganglia/jmxetric/TestExampleMXBean.java:
--------------------------------------------------------------------------------
1 | package info.ganglia.jmxetric;
2 |
3 | /**
4 | * MXBean definition used for testing
5 | * @author humphrej
6 | *
7 | */
8 | public interface TestExampleMXBean {
9 |
10 | final int INT_VALUE=1234 ;
11 | final long LONG_VALUE=43210L ;
12 | final double DOUBLE_VALUE=123.45D ;
13 | final float FLOAT_VALUE=543.21F ;
14 | final String STRING_VALUE="STRING" ;
15 |
16 | int getInt() ;
17 | long getLong() ;
18 | String getString() ;
19 | double getDouble() ;
20 | float getFloat() ;
21 | ExampleComposite getComposite();
22 | int getCounter() ;
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/test/resources/jmxetric_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ]>
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------