content: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   *
   * 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.alibaba.druid.support.monitor;
  
  import com.alibaba.druid.pool.DruidDataSource;
  import com.alibaba.druid.pool.DruidDataSourceStatValue;
  import com.alibaba.druid.stat.DruidDataSourceStatManager;
  import com.alibaba.druid.stat.JdbcSqlStatValue;
  import com.alibaba.druid.support.http.stat.WebAppStat;
  import com.alibaba.druid.support.http.stat.WebAppStatManager;
  import com.alibaba.druid.support.http.stat.WebAppStatValue;
  import com.alibaba.druid.support.http.stat.WebURIStatValue;
  import com.alibaba.druid.support.logging.Log;
  import com.alibaba.druid.support.logging.LogFactory;
  import com.alibaba.druid.support.monitor.dao.MonitorDao;
  import com.alibaba.druid.support.spring.stat.SpringMethodStatValue;
  import com.alibaba.druid.support.spring.stat.SpringStat;
  import com.alibaba.druid.support.spring.stat.SpringStatManager;
  import com.alibaba.druid.util.StringUtils;
  import com.alibaba.druid.util.Utils;
  import com.alibaba.druid.wall.WallProviderStatValue;
  
  import java.lang.management.ManagementFactory;
  import java.net.InetAddress;
  import java.net.NetworkInterface;
  import java.util.*;
  import java.util.concurrent.ScheduledExecutorService;
  import java.util.concurrent.ScheduledThreadPoolExecutor;
  import java.util.concurrent.TimeUnit;
  
  import static com.alibaba.druid.util.Utils.getBoolean;
  import static com.alibaba.druid.util.Utils.getInteger;
  
  public class MonitorClient {
      private static final Log LOG = LogFactory.getLog(MonitorClient.class);
  
      private static final long DEFAULT_TIME_BETWEEN_COLLECT = 60 * 5;
  
      private ScheduledExecutorService scheduler;
      private int schedulerThreadSize = 1;
  
      private long timeBetweenSqlCollect = DEFAULT_TIME_BETWEEN_COLLECT;
      private long timeBetweenSpringCollect = DEFAULT_TIME_BETWEEN_COLLECT;
      private long timeBetweenWebUriCollect = DEFAULT_TIME_BETWEEN_COLLECT;
      private TimeUnit timeUnit = TimeUnit.SECONDS;
  
      private boolean collectSqlEnable = true;
      private boolean collectSqlWallEnable = true;
      private boolean collectSpringMethodEnable = true;
      private boolean collectWebAppEnable = true;
      private boolean collectWebURIEnable = true;
  
      private MonitorDao dao;
  
      private String domain;
      private String app;
      private String cluster;
      private String host;
      private String ip;
      private int pid;
  
      public MonitorClient() {
          String name = ManagementFactory.getRuntimeMXBean().getName();
  
          String[] items = name.split("@");
  
          pid = Integer.parseInt(items[0]);
          host = items[1];
          ip = getLocalIPAddress().getHostAddress();
  
          configFromProperty(System.getProperties());
      }
  
      public void configFromProperty(Properties properties) {
          {
              Integer value = getInteger(properties, "druid.monitor.client.schedulerThreadSize");
              if (value != null) {
                  this.setSchedulerThreadSize(value);
              }
          }
  
          {
              Integer value = getInteger(properties, "druid.monitor.client.timeBetweenSqlCollect");
              if (value != null) {
                  this.setTimeBetweenSqlCollect(value);
              }
          }
          {
              Integer value = getInteger(properties, "druid.monitor.client.timeBetweenSpringCollect");
              if (value != null) {
                  this.setTimeBetweenSpringCollect(value);
              }
          }
          {
              Integer value = getInteger(properties, "druid.monitor.client.timeBetweenWebUriCollect");
              if (value != null) {
                  this.setTimeBetweenWebUriCollect(value);
              }
          }
  
          {
              Boolean value = getBoolean(properties, "druid.monitor.client.collectSqlEnable");
              if (value != null) {
                  this.setCollectSqlEnable(value);
              }
          }
  
          {
              Boolean value = getBoolean(properties, "druid.monitor.client.collectSqlWallEnable");
              if (value != null) {
                  this.setCollectSqlWallEnable(value);
              }
          }
  
          {
              Boolean value = getBoolean(properties, "druid.monitor.client.collectSpringMethodEnable");
              if (value != null) {
                  this.setCollectSpringMethodEnable(value);
              }
          }
  
          {
              Boolean value = getBoolean(properties, "druid.monitor.client.collectWebAppEnable");
              if (value != null) {
                  this.setCollectWebAppEnable(value);
              }
          }
  
          {
              Boolean value = getBoolean(properties, "druid.monitor.client.collectWebURIEnable");
              if (value != null) {
                  this.setCollectWebURIEnable(value);
              }
          }
          {
              domain = properties.getProperty("druid.monitor.domain");
              if (StringUtils.isEmpty(domain)) {
                  domain = "default";
              }
          }
  
          {
              app = properties.getProperty("druid.monitor.app");
              if (StringUtils.isEmpty(app)) {
                  app = "default";
              }
          }
  
          {
              cluster = properties.getProperty("druid.monitor.cluster");
              if (StringUtils.isEmpty(cluster)) {
                  cluster = "default";
              }
          }
      }
  
      public void stop() {
      }
  
      public void start() {
          checkInst();
  
          if (scheduler == null) {
              scheduler = new ScheduledThreadPoolExecutor(schedulerThreadSize);
          }
  
          scheduler.scheduleAtFixedRate(new Runnable() {
              @Override
              public void run() {
                  collectSql();
              }
          }, timeBetweenSqlCollect, timeBetweenSqlCollect, timeUnit);
  
          scheduler.scheduleAtFixedRate(new Runnable() {
              @Override
              public void run() {
                  collectSpringMethod();
              }
          }, timeBetweenSpringCollect, timeBetweenSpringCollect, timeUnit);
  
          scheduler.scheduleAtFixedRate(new Runnable() {
              @Override
              public void run() {
                  collectWebURI();
              }
          }, timeBetweenWebUriCollect, timeBetweenWebUriCollect, timeUnit);
      }
  
      public ScheduledExecutorService getScheduler() {
          return scheduler;
      }
  
      public void setScheduler(ScheduledExecutorService scheduler) {
          this.scheduler = scheduler;
      }
  
      public void checkInst() {
          try {
              dao.insertAppIfNotExits(domain, app);
  
              dao.insertClusterIfNotExits(domain, app, cluster);
  
              dao.insertOrUpdateInstance(domain, app, cluster, host, ip, Utils.getStartTime(), pid);
          } catch (Exception ex) {
              LOG.error("checkInst error", ex);
          }
      }
  
      @SuppressWarnings("resource")
      public void collectSql() {
          if ((!collectSqlEnable) && !collectSqlWallEnable) {
              return;
          }
  
          Set<Object> dataSources = DruidDataSourceStatManager.getInstances().keySet();
  
          List<DruidDataSourceStatValue> statValueList = new ArrayList<DruidDataSourceStatValue>(dataSources.size());
          List<WallProviderStatValue> wallStatValueList = new ArrayList<WallProviderStatValue>();
  
          for (Object item : dataSources) {
              if (!(item instanceof DruidDataSource)) {
                  continue;
              }
  
              DruidDataSource dataSource = (DruidDataSource) item;
  
              if (collectSqlEnable) {
                  DruidDataSourceStatValue statValue = dataSource.getStatValueAndReset();
                  statValueList.add(statValue);
              }
  
              if (collectSqlWallEnable) {
                  WallProviderStatValue wallStatValue = dataSource.getWallStatValue(true);
                  if (wallStatValue != null && wallStatValue.getCheckCount() > 0) {
                      wallStatValueList.add(wallStatValue);
                  }
              }
          }
  
          MonitorContext ctx = createContext();
  
          if (statValueList.size() > 0) {
              dao.saveSql(ctx, statValueList);
          }
  
          if (wallStatValueList.size() > 0) {
              dao.saveSqlWall(ctx, wallStatValueList);
          }
      }
  
      private MonitorContext createContext() {
          MonitorContext ctx = new MonitorContext();
  
          ctx.setDomain(domain);
          ctx.setApp(app);
          ctx.setCluster(cluster);
  
          ctx.setCollectTime(new Date());
          ctx.setPID(pid);
          ctx.setHost(host);
          ctx.setCollectTime(Utils.getStartTime());
          return ctx;
      }
  
      private void collectSpringMethod() {
          if (!collectSpringMethodEnable) {
              return;
          }
  
          List<SpringMethodStatValue> statValueList = new ArrayList<SpringMethodStatValue>();
  
          Set<Object> stats = SpringStatManager.getInstance().getSpringStatSet();
  
          for (Object item : stats) {
              if (!(item instanceof SpringStat)) {
                  continue;
              }
  
              SpringStat sprintStat = (SpringStat) item;
              statValueList.addAll(sprintStat.getStatList(true));
          }
  
          if (statValueList.size() > 0) {
              MonitorContext ctx = createContext();
              dao.saveSpringMethod(ctx, statValueList);
          }
      }
  
      private void collectWebURI() {
          if ((!collectWebAppEnable) && !collectWebURIEnable) {
              return;
          }
  
          List<WebURIStatValue> webURIValueList = new ArrayList<WebURIStatValue>();
          List<WebAppStatValue> webAppStatValueList = new ArrayList<WebAppStatValue>();
  
          Set<Object> stats = WebAppStatManager.getInstance().getWebAppStatSet();
  
          for (Object item : stats) {
              if (!(item instanceof WebAppStat)) {
                  continue;
              }
  
              WebAppStat webAppStat = (WebAppStat) item;
  
              if (collectWebAppEnable) {
                  WebAppStatValue webAppStatValue = webAppStat.getStatValue(true);
                  webAppStatValueList.add(webAppStatValue);
              }
  
              if (collectWebURIEnable) {
                  webURIValueList.addAll(webAppStat.getURIStatValueList(true));
              }
          }
  
          MonitorContext ctx = createContext();
  
          if (webURIValueList.size() > 0) {
              dao.saveWebURI(ctx, webURIValueList);
          }
  
          if (webAppStatValueList.size() > 0) {
              dao.saveWebApp(ctx, webAppStatValueList);
          }
      }
  
      public List<JdbcSqlStatValue> loadSqlList(Map<String, Object> filters) {
          return dao.loadSqlList(filters);
      }
  
      public MonitorDao getDao() {
          return dao;
      }
  
      public void setDao(MonitorDao dao) {
          this.dao = dao;
      }
  
      public long getTimeBetweenSqlCollect() {
          return timeBetweenSqlCollect;
      }
  
      public void setTimeBetweenSqlCollect(long timeBetweenSqlCollect) {
          this.timeBetweenSqlCollect = timeBetweenSqlCollect;
      }
  
      public long getTimeBetweenSpringCollect() {
          return timeBetweenSpringCollect;
      }
  
      public void setTimeBetweenSpringCollect(long timeBetweenSpringCollect) {
          this.timeBetweenSpringCollect = timeBetweenSpringCollect;
      }
  
      public long getTimeBetweenWebUriCollect() {
          return timeBetweenWebUriCollect;
      }
  
      public void setTimeBetweenWebUriCollect(long timeBetweenWebUriCollect) {
          this.timeBetweenWebUriCollect = timeBetweenWebUriCollect;
      }
  
      public TimeUnit getTimeUnit() {
          return timeUnit;
      }
  
      public void setTimeUnit(TimeUnit timeUnit) {
          this.timeUnit = timeUnit;
      }
  
      public boolean isCollectSqlEnable() {
          return collectSqlEnable;
      }
  
      public void setCollectSqlEnable(boolean collectSqlEnable) {
          this.collectSqlEnable = collectSqlEnable;
      }
  
      public boolean isCollectSqlWallEnable() {
          return collectSqlWallEnable;
      }
  
      public void setCollectSqlWallEnable(boolean collectSqlWallEnable) {
          this.collectSqlWallEnable = collectSqlWallEnable;
      }
  
      public boolean isCollectSpringMethodEnable() {
          return collectSpringMethodEnable;
      }
  
      public void setCollectSpringMethodEnable(boolean collectSpringMethodEnable) {
          this.collectSpringMethodEnable = collectSpringMethodEnable;
      }
  
      public boolean isCollectWebAppEnable() {
          return collectWebAppEnable;
      }
  
      public void setCollectWebAppEnable(boolean collectWebAppEnable) {
          this.collectWebAppEnable = collectWebAppEnable;
      }
  
      public boolean isCollectWebURIEnable() {
          return collectWebURIEnable;
      }
  
      public void setCollectWebURIEnable(boolean collectWebURIEnable) {
          this.collectWebURIEnable = collectWebURIEnable;
      }
  
      public int getSchedulerThreadSize() {
          return schedulerThreadSize;
      }
  
      public void setSchedulerThreadSize(int schedulerThreadSize) {
          this.schedulerThreadSize = schedulerThreadSize;
      }
  
      public String getDomain() {
          return domain;
      }
  
      public void setDomain(String domain) {
          this.domain = domain;
      }
  
      public String getApp() {
          return app;
      }
  
      public void setApp(String app) {
          this.app = app;
      }
  
      public String getCluster() {
          return cluster;
      }
  
      public void setCluster(String cluster) {
          this.cluster = cluster;
      }
  
      public String getHost() {
          return host;
      }
  
      public void setHost(String host) {
          this.host = host;
      }
  
      public int getPid() {
          return pid;
      }
  
      public void setPid(int pid) {
          this.pid = pid;
      }
  
      public static InetAddress getLocalIPAddress() {
          try {
              Enumeration<?> netInterfaces = NetworkInterface.getNetworkInterfaces();
              InetAddress inetAddress = null;
              while (netInterfaces.hasMoreElements()) {
                  NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement();
                  Enumeration<?> e2 = ni.getInetAddresses();
                  while (e2.hasMoreElements()) {
                      inetAddress = (InetAddress) e2.nextElement();
                      if (!inetAddress.isLoopbackAddress() && !inetAddress.getHostAddress().contains(":")) {
                          return inetAddress;
                      }
                  }
              }
          } catch (Exception e) {
              LOG.error("getLocalIP error", e);
          }
  
          return null;
      }
  }
  