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 039/** 040 * Base class for command lines that start up various HBase daemons. 041 */ 042@InterfaceAudience.Private 043public abstract class ServerCommandLine extends Configured implements Tool { 044 private static final Logger LOG = LoggerFactory.getLogger(ServerCommandLine.class); 045 @SuppressWarnings("serial") 046 private static final Set<String> DEFAULT_SKIP_WORDS = new HashSet<String>() { 047 { 048 add("secret"); 049 add("passwd"); 050 add("password"); 051 add("credential"); 052 } 053 }; 054 055 /** 056 * Implementing subclasses should return a usage string to print out. 057 */ 058 protected abstract String getUsage(); 059 060 /** 061 * Print usage information for this command line. 062 * @param message if not null, print this message before the usage info. 063 */ 064 protected void usage(String message) { 065 if (message != null) { 066 System.err.println(message); 067 System.err.println(""); 068 } 069 070 System.err.println(getUsage()); 071 } 072 073 /** 074 * Log information about the currently running JVM. 075 */ 076 public static void logJVMInfo() { 077 // Print out vm stats before starting up. 078 RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 079 if (runtime != null) { 080 LOG.info("vmName=" + runtime.getVmName() + ", vmVendor=" + runtime.getVmVendor() 081 + ", vmVersion=" + runtime.getVmVersion()); 082 LOG.info("vmInputArguments=" + runtime.getInputArguments()); 083 } 084 } 085 086 /** 087 * Print into log some of the important hbase attributes. 088 */ 089 private static void logHBaseConfigs(Configuration conf) { 090 final String[] keys = new String[] { 091 // Expand this list as you see fit. 092 "hbase.tmp.dir", HConstants.HBASE_DIR, HConstants.CLUSTER_DISTRIBUTED, 093 HConstants.ZOOKEEPER_QUORUM, 094 095 }; 096 for (String key : keys) { 097 LOG.info(key + ": " + conf.get(key)); 098 } 099 } 100 101 /** 102 * Logs information about the currently running JVM process including the environment variables. 103 * Logging of env vars can be disabled by setting {@code "hbase.envvars.logging.disabled"} to 104 * {@code "true"}. 105 * <p> 106 * If enabled, you can also exclude environment variables containing certain substrings by setting 107 * {@code "hbase.envvars.logging.skipwords"} to comma separated list of such substrings. 108 */ 109 public static void logProcessInfo(Configuration conf) { 110 logHBaseConfigs(conf); 111 112 // log environment variables unless asked not to 113 if (conf == null || !conf.getBoolean("hbase.envvars.logging.disabled", false)) { 114 Set<String> skipWords = new HashSet<>(DEFAULT_SKIP_WORDS); 115 if (conf != null) { 116 String[] confSkipWords = conf.getStrings("hbase.envvars.logging.skipwords"); 117 if (confSkipWords != null) { 118 skipWords.addAll(Arrays.asList(confSkipWords)); 119 } 120 } 121 122 nextEnv: for (Entry<String, String> entry : System.getenv().entrySet()) { 123 String key = entry.getKey().toLowerCase(Locale.ROOT); 124 String value = entry.getValue().toLowerCase(Locale.ROOT); 125 // exclude variables which may contain skip words 126 for (String skipWord : skipWords) { 127 if (key.contains(skipWord) || value.contains(skipWord)) continue nextEnv; 128 } 129 LOG.info("env:" + entry); 130 } 131 } 132 133 // and JVM info 134 logJVMInfo(); 135 } 136 137 /** 138 * Parse and run the given command line. This will exit the JVM with the exit code returned from 139 * <code>run()</code>. If return code is 0, wait for atmost 30 seconds for all non-daemon threads 140 * to quit, otherwise exit the jvm 141 */ 142 public void doMain(String args[]) { 143 try { 144 int ret = ToolRunner.run(HBaseConfiguration.create(), this, args); 145 if (ret != 0) { 146 System.exit(ret); 147 } 148 // Return code is 0 here. 149 boolean forceStop = false; 150 long startTime = EnvironmentEdgeManager.currentTime(); 151 while (isNonDaemonThreadRunning()) { 152 if (EnvironmentEdgeManager.currentTime() - startTime > 30 * 1000) { 153 forceStop = true; 154 break; 155 } 156 Thread.sleep(1000); 157 } 158 if (forceStop) { 159 LOG.error("Failed to stop all non-daemon threads, so terminating JVM"); 160 System.exit(-1); 161 } 162 } catch (Exception e) { 163 LOG.error("Failed to run", e); 164 System.exit(-1); 165 } 166 } 167}