All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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