
com.github.jcustenborder.kafka.connect.jmx.JMXService Maven / Gradle / Ivy
The newest version!
/**
* Copyright © 2017 Jeremy Custenborder ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jcustenborder.kafka.connect.jmx;
import com.github.jcustenborder.kafka.connect.utils.data.SourceRecordConcurrentLinkedDeque;
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.AbstractScheduledService;
import org.apache.kafka.connect.data.Schema;
import org.apache.kafka.connect.data.SchemaBuilder;
import org.apache.kafka.connect.data.Struct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
class JMXService extends AbstractScheduledService {
private static final Logger log = LoggerFactory.getLogger(JMXService.class);
private final JMXSourceConnectorConfig config;
private final SourceRecordConcurrentLinkedDeque records;
ConnectorFactory factory = new ConnectorFactoryImpl();
JMXService(JMXSourceConnectorConfig config, SourceRecordConcurrentLinkedDeque records) {
this.config = config;
this.records = records;
}
static class CacheKey implements Comparable {
final JMXServiceURL serviceURL;
final ObjectName objectName;
CacheKey(JMXServiceURL serviceURL, ObjectName objectName) {
this.serviceURL = serviceURL;
this.objectName = objectName;
}
@Override
public int compareTo(CacheKey that) {
int result = this.serviceURL.toString().compareTo(that.serviceURL.toString());
if (result != 0) {
return result;
}
result = this.objectName.compareTo(that.objectName);
return result;
}
public static CacheKey of(JMXServiceURL serviceURL, ObjectName objectName) {
return new CacheKey(serviceURL, objectName);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof CacheKey) {
return false;
} else {
return 0 == compareTo((CacheKey) obj);
}
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("serviceUrl", this.serviceURL)
.add("objectName", this.objectName)
.toString();
}
}
Cache cache = CacheBuilder.newBuilder()
.build();
static final Schema KEY_SCHEMA = SchemaBuilder.struct()
.name("com.github.jcustenborder.kafka.connect.jmx.Key")
.field("host", Schema.STRING_SCHEMA)
.field("port", Schema.INT32_SCHEMA)
.field("objectName", Schema.STRING_SCHEMA)
.field("attributeName", Schema.STRING_SCHEMA)
.build();
static final Schema VALUE_SCHEMA = SchemaBuilder.struct()
.name("com.github.jcustenborder.kafka.connect.jmx.Value")
.field("host", Schema.STRING_SCHEMA)
.field("port", Schema.INT32_SCHEMA)
.field("objectName", Schema.STRING_SCHEMA)
.field("attributeName", Schema.STRING_SCHEMA)
.build();
@Override
protected void runOneIteration() throws Exception {
log.trace("runOneIteration() - ");
for (final JMXServiceURL jmxServiceURL : this.config.jmxServiceUrls) {
log.trace("runOneIteration() - Connecting to {}", jmxServiceURL);
try (final JMXConnector jmxConnector = this.factory.connect(jmxServiceURL, this.config.jmxEnvironment)) {
final MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
for (ObjectNameAndAttributes objectNameAndAttributes : this.config.jmxObjectNames) {
log.trace("runOneIteration() - Processing {}", objectNameAndAttributes);
CacheKey cacheKey = CacheKey.of(jmxServiceURL, objectNameAndAttributes.objectName);
final MBeanInfo mBeanInfo = this.cache.get(cacheKey, () -> {
log.trace("Querying for {}", cacheKey);
return mBeanServerConnection.getMBeanInfo(objectNameAndAttributes.objectName);
});
final MBeanAttributeInfo[] attributeInfos = mBeanInfo.getAttributes();
final Map retrieveAttributes = new LinkedHashMap<>(attributeInfos.length);
for (MBeanAttributeInfo attributeInfo : attributeInfos) {
if (objectNameAndAttributes.isWildCard || objectNameAndAttributes.attributes.contains(attributeInfo.getName())) {
log.trace("runOneIteration() - Adding name = '{}' type='{}'", attributeInfo.getName(), attributeInfo.getType());
retrieveAttributes.put(attributeInfo.getName(), attributeInfo);
}
}
final String[] attributeNames = retrieveAttributes.keySet().stream().toArray(String[]::new);
log.trace("runOneIteration() - Calling getAttributes({}, [{}])", objectNameAndAttributes.objectName, Joiner.on(", ").join(attributeNames));
AttributeList attributeValues = mBeanServerConnection.getAttributes(objectNameAndAttributes.objectName, attributeNames);
for (Attribute attribute : attributeValues.asList()) {
final Struct key = new Struct(KEY_SCHEMA)
.put("host", jmxServiceURL.getHost())
.put("port", jmxServiceURL.getPort())
.put("objectName", objectNameAndAttributes.objectName.getCanonicalName())
.put("attributeName", attribute.getName());
final Struct value = new Struct(VALUE_SCHEMA)
.put("host", jmxServiceURL.getHost())
.put("port", jmxServiceURL.getPort())
.put("objectName", objectNameAndAttributes.objectName.getCanonicalName())
.put("attributeName", attribute.getName());
}
}
} catch (IOException ex) {
log.error("Exception thrown while querying '{}'", jmxServiceURL, ex);
}
}
}
@Override
protected Scheduler scheduler() {
return Scheduler.newFixedDelaySchedule(this.config.pollDelayMs, this.config.pollScheduleMs, TimeUnit.MILLISECONDS);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy