001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import static org.apache.hadoop.hbase.util.Threads.isNonDaemonThreadRunning; 021 022import java.lang.management.ManagementFactory; 023import java.lang.management.RuntimeMXBean; 024import java.util.Arrays; 025import java.util.HashSet; 026import java.util.Locale; 027import java.util.Map.Entry; 028import java.util.Set; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.conf.Configured; 031import org.apache.hadoop.hbase.HBaseConfiguration; 032import org.apache.hadoop.hbase.HConstants; 033import org.apache.hadoop.util.Tool; 034import org.apache.hadoop.util.ToolRunner; 035import org.apache.yetus.audience.InterfaceAudience; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet; 040 041/** 042 * Base class for command lines that start up various HBase daemons. 043 */ 044@InterfaceAudience.Private 045public abstract class ServerCommandLine extends Configured implements Tool { 046 private static final Logger LOG = LoggerFactory.getLogger(ServerCommandLine.class); 047 048 private static final Set<String> DEFAULT_SKIP_WORDS = 049 ImmutableSet.of("secret", "passwd", "password", "credential"); 050 051 /** 052 * Implementing subclasses should return a usage string to print out. 053 */ 054 protected abstract String getUsage(); 055 056 /** 057 * Print usage information for this command line. 058 * @param message if not null, print this message before the usage info. 059 */ 060 protected void usage(String message) { 061 if (message != null) { 062 System.err.println(message); 063 System.err.println(""); 064 } 065 066 System.err.println(getUsage()); 067 } 068 069 /** 070 * Log information about the currently running JVM. 071 */ 072 public static void logJVMInfo() { 073 // Print out vm stats before starting up. 074 RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 075 if (runtime != null) { 076 LOG.info("vmName=" + runtime.getVmName() + ", vmVendor=" + runtime.getVmVendor() 077 + ", vmVersion=" + runtime.getVmVersion()); 078 LOG.info("vmInputArguments=" + runtime.getInputArguments()); 079 } 080 } 081 082 /** 083 * Print into log some of the important hbase attributes. 084 */ 085 private static void logHBaseConfigs(Configuration conf) { 086 final String[] keys = new String[] { 087 // Expand this list as you see fit. 088 "hbase.tmp.dir", HConstants.HBASE_DIR, HConstants.CLUSTER_DISTRIBUTED, 089 HConstants.ZOOKEEPER_QUORUM, 090 091 }; 092 for (String key : keys) { 093 LOG.info(key + ": " + conf.get(key)); 094 } 095 } 096 097 /** 098 * Logs information about the currently running JVM process including the environment variables. 099 * Logging of env vars can be disabled by setting {@code "hbase.envvars.logging.disabled"} to 100 * {@code "true"}. 101 * <p> 102 * If enabled, you can also exclude environment variables containing certain substrings by setting 103 * {@code "hbase.envvars.logging.skipwords"} to comma separated list of such substrings. 104 */ 105 public static void logProcessInfo(Configuration conf) { 106 logHBaseConfigs(conf); 107 108 // log environment variables unless asked not to 109 if (conf == null || !conf.getBoolean("hbase.envvars.logging.disabled", false)) { 110 Set<String> skipWords = new HashSet<>(DEFAULT_SKIP_WORDS); 111 if (conf != null) { 112 String[] confSkipWords = conf.getStrings("hbase.envvars.logging.skipwords"); 113 if (confSkipWords != null) { 114 skipWords.addAll(Arrays.asList(confSkipWords)); 115 } 116 } 117 118 nextEnv: for (Entry<String, String> entry : System.getenv().entrySet()) { 119 String key = entry.getKey().toLowerCase(Locale.ROOT); 120 String value = entry.getValue().toLowerCase(Locale.ROOT); 121 // exclude variables which may contain skip words 122 for (String skipWord : skipWords) { 123 if (key.contains(skipWord) || value.contains(skipWord)) continue nextEnv; 124 } 125 LOG.info("env:" + entry); 126 } 127 } 128 129 // and JVM info 130 logJVMInfo(); 131 } 132 133 /** 134 * Parse and run the given command line. This will exit the JVM with the exit code returned from 135 * <code>run()</code>. If return code is 0, wait for atmost 30 seconds for all non-daemon threads 136 * to quit, otherwise exit the jvm 137 */ 138 public void doMain(String args[]) { 139 try { 140 int ret = ToolRunner.run(HBaseConfiguration.create(), this, args); 141 if (ret != 0) { 142 System.exit(ret); 143 } 144 // Return code is 0 here. 145 boolean forceStop = false; 146 long startTime = EnvironmentEdgeManager.currentTime(); 147 while (isNonDaemonThreadRunning()) { 148 if (EnvironmentEdgeManager.currentTime() - startTime > 30 * 1000) { 149 forceStop = true; 150 break; 151 } 152 Thread.sleep(1000); 153 } 154 if (forceStop) { 155 LOG.error("Failed to stop all non-daemon threads, so terminating JVM"); 156 System.exit(-1); 157 } 158 } catch (Exception e) { 159 LOG.error("Failed to run", e); 160 System.exit(-1); 161 } 162 } 163}