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

org.apache.druid.server.metrics.MetricsModule Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.druid.server.metrics;

import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.inject.Binder;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.name.Names;
import io.timeandspace.cronscheduler.CronScheduler;
import org.apache.druid.discovery.NodeRole;
import org.apache.druid.guice.DruidBinders;
import org.apache.druid.guice.JsonConfigProvider;
import org.apache.druid.guice.LazySingleton;
import org.apache.druid.guice.ManageLifecycle;
import org.apache.druid.guice.annotations.Self;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.java.util.common.concurrent.Execs;
import org.apache.druid.java.util.common.logger.Logger;
import org.apache.druid.java.util.emitter.service.ServiceEmitter;
import org.apache.druid.java.util.metrics.BasicMonitorScheduler;
import org.apache.druid.java.util.metrics.ClockDriftSafeMonitorScheduler;
import org.apache.druid.java.util.metrics.DruidMonitorSchedulerConfig;
import org.apache.druid.java.util.metrics.JvmCpuMonitor;
import org.apache.druid.java.util.metrics.JvmMonitor;
import org.apache.druid.java.util.metrics.JvmThreadsMonitor;
import org.apache.druid.java.util.metrics.Monitor;
import org.apache.druid.java.util.metrics.MonitorScheduler;
import org.apache.druid.java.util.metrics.NoopOshiSysMonitor;
import org.apache.druid.java.util.metrics.NoopSysMonitor;
import org.apache.druid.java.util.metrics.OshiSysMonitor;
import org.apache.druid.java.util.metrics.SysMonitor;
import org.apache.druid.query.ExecutorServiceMonitor;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Sets up the {@link MonitorScheduler} to monitor things on a regular schedule.  {@link Monitor}s must be explicitly
 * bound in order to be loaded.
 */
public class MetricsModule implements Module
{
  static final String MONITORING_PROPERTY_PREFIX = "druid.monitoring";
  private static final Logger log = new Logger(MetricsModule.class);
  private Set nodeRoles;

  @Inject
  public void setNodeRoles(@Self Set nodeRoles)
  {
    this.nodeRoles = nodeRoles;
  }

  public static void register(Binder binder, Class monitorClazz)
  {
    DruidBinders.metricMonitorBinder(binder).addBinding().toInstance(monitorClazz);
  }

  @Override
  public void configure(Binder binder)
  {
    JsonConfigProvider.bind(binder, MONITORING_PROPERTY_PREFIX, DruidMonitorSchedulerConfig.class);
    JsonConfigProvider.bind(binder, MONITORING_PROPERTY_PREFIX, MonitorsConfig.class);

    DruidBinders.metricMonitorBinder(binder); // get the binder so that it will inject the empty set at a minimum.

    binder.bind(DataSourceTaskIdHolder.class).in(LazySingleton.class);

    binder.bind(ExecutorServiceMonitor.class).in(LazySingleton.class);

    // Instantiate eagerly so that we get everything registered and put into the Lifecycle
    binder.bind(Key.get(MonitorScheduler.class, Names.named("ForTheEagerness")))
          .to(MonitorScheduler.class)
          .asEagerSingleton();
  }

  @Provides
  @ManageLifecycle
  public MonitorScheduler getMonitorScheduler(
      Supplier config,
      MonitorsConfig monitorsConfig,
      Set> monitorSet,
      ServiceEmitter emitter,
      Injector injector
  )
  {
    List monitors = new ArrayList<>();
    // HACK: when ServiceStatusMonitor is the first to be loaded, it introduces a circular dependency between
    // CliPeon.runTask and CliPeon.getDataSourceFromTask/CliPeon.getTaskIDFromTask. The reason for this is unclear
    // but by injecting DataSourceTaskIdHolder early this cycle is avoided.
    injector.getInstance(DataSourceTaskIdHolder.class);
    for (Class monitorClass : Iterables.concat(monitorsConfig.getMonitors(), monitorSet)) {
      monitors.add(injector.getInstance(monitorClass));
    }

    if (!monitors.isEmpty()) {
      log.info(
          "Loaded %d monitors: %s",
          monitors.size(),
          monitors.stream().map(monitor -> monitor.getClass().getName()).collect(Collectors.joining(", "))
      );
    }

    if (ClockDriftSafeMonitorScheduler.class.getName().equals(config.get().getSchedulerClassName())) {
      return new ClockDriftSafeMonitorScheduler(
          config.get(),
          emitter,
          monitors,
          CronScheduler.newBuilder(Duration.ofSeconds(1L)).setThreadName("MonitorScheduler").build(),
          Execs.singleThreaded("MonitorRunner")
      );
    } else if (BasicMonitorScheduler.class.getName().equals(config.get().getSchedulerClassName())) {
      return new BasicMonitorScheduler(
          config.get(),
          emitter,
          monitors,
          Execs.scheduledSingleThreaded("MonitorScheduler-%s")
      );
    } else {
      throw new IAE("Unknown monitor scheduler[%s]", config.get().getSchedulerClassName());
    }
  }

  @Provides
  @ManageLifecycle
  public JvmMonitor getJvmMonitor(
      DataSourceTaskIdHolder dataSourceTaskIdHolder
  )
  {
    Map dimensions = MonitorsConfig.mapOfDatasourceAndTaskID(
        dataSourceTaskIdHolder.getDataSource(),
        dataSourceTaskIdHolder.getTaskId()
    );
    return new JvmMonitor(dimensions);
  }

  @Provides
  @ManageLifecycle
  public JvmCpuMonitor getJvmCpuMonitor(
      DataSourceTaskIdHolder dataSourceTaskIdHolder
  )
  {
    Map dimensions = MonitorsConfig.mapOfDatasourceAndTaskID(
        dataSourceTaskIdHolder.getDataSource(),
        dataSourceTaskIdHolder.getTaskId()
    );
    return new JvmCpuMonitor(dimensions);
  }

  @Provides
  @ManageLifecycle
  public JvmThreadsMonitor getJvmThreadsMonitor(DataSourceTaskIdHolder dataSourceTaskIdHolder)
  {
    Map dimensions = MonitorsConfig.mapOfDatasourceAndTaskID(
        dataSourceTaskIdHolder.getDataSource(),
        dataSourceTaskIdHolder.getTaskId()
    );
    return new JvmThreadsMonitor(dimensions);
  }

  @Provides
  @ManageLifecycle
  public SysMonitor getSysMonitor(DataSourceTaskIdHolder dataSourceTaskIdHolder, @Self Set nodeRoles)
  {
    if (nodeRoles.contains(NodeRole.PEON)) {
      return new NoopSysMonitor();
    } else {
      Map dimensions = MonitorsConfig.mapOfDatasourceAndTaskID(
          dataSourceTaskIdHolder.getDataSource(),
          dataSourceTaskIdHolder.getTaskId()
      );
      return new SysMonitor(dimensions);
    }
  }

  @Provides
  @ManageLifecycle
  public OshiSysMonitor getOshiSysMonitor(DataSourceTaskIdHolder dataSourceTaskIdHolder, @Self Set nodeRoles)
  {
    if (nodeRoles.contains(NodeRole.PEON)) {
      return new NoopOshiSysMonitor();
    } else {
      Map dimensions = MonitorsConfig.mapOfDatasourceAndTaskID(
          dataSourceTaskIdHolder.getDataSource(),
          dataSourceTaskIdHolder.getTaskId()
      );
      return new OshiSysMonitor(dimensions);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy