共计 5677 个字符,预计需要花费 15 分钟才能阅读完成。
序
本文主要研究一下 ElasticsearchUncaughtExceptionHandler
ElasticsearchUncaughtExceptionHandler
class ElasticsearchUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {private static final Logger logger = LogManager.getLogger(ElasticsearchUncaughtExceptionHandler.class);
@Override
public void uncaughtException(Thread t, Throwable e) {if (isFatalUncaught(e)) {
try {onFatalUncaught(t.getName(), e);
} finally {
// we use specific error codes in case the above notification failed, at least we
// will have some indication of the error bringing us down
if (e instanceof InternalError) {halt(128);
} else if (e instanceof OutOfMemoryError) {halt(127);
} else if (e instanceof StackOverflowError) {halt(126);
} else if (e instanceof UnknownError) {halt(125);
} else if (e instanceof IOError) {halt(124);
} else {halt(1);
}
}
} else {onNonFatalUncaught(t.getName(), e);
}
}
static boolean isFatalUncaught(Throwable e) {return e instanceof Error;}
void onFatalUncaught(final String threadName, final Throwable t) {logger.error(() -> new ParameterizedMessage("fatal error in thread [{}], exiting", threadName), t);
}
void onNonFatalUncaught(final String threadName, final Throwable t) {logger.warn(() -> new ParameterizedMessage("uncaught exception in thread [{}]", threadName), t);
}
void halt(int status) {AccessController.doPrivileged(new PrivilegedHaltAction(status));
}
static class PrivilegedHaltAction implements PrivilegedAction<Void> {
private final int status;
private PrivilegedHaltAction(final int status) {this.status = status;}
@SuppressForbidden(reason = "halt")
@Override
public Void run() {
// we halt to prevent shutdown hooks from running
Runtime.getRuntime().halt(status);
return null;
}
}
}
- ElasticsearchUncaughtExceptionHandler 实现了 Thread.UncaughtExceptionHandler 接口
- uncaughtException 方法首先判断 throwable 是否是 Error 类型,是的话则执行 onFatalUncaught(
logger.error
),然后执行 halt 方法,不是则执行 onNonFatalUncaught(logger.warn
) - halt 方法 AccessController.doPrivileged 来执行对应 status 的 PrivilegedHaltAction,该 action 执行的是 Runtime.getRuntime().halt(status)
Bootstrap.init
elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java
final class Bootstrap {
private static volatile Bootstrap INSTANCE;
private volatile Node node;
private final CountDownLatch keepAliveLatch = new CountDownLatch(1);
private final Thread keepAliveThread;
private final Spawner spawner = new Spawner();
//......
static void init(
final boolean foreground,
final Path pidFile,
final boolean quiet,
final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException {
// force the class initializer for BootstrapInfo to run before
// the security manager is installed
BootstrapInfo.init();
INSTANCE = new Bootstrap();
final SecureSettings keystore = loadSecureSettings(initialEnv);
final Environment environment = createEnvironment(pidFile, keystore, initialEnv.settings(), initialEnv.configFile());
LogConfigurator.setNodeName(Node.NODE_NAME_SETTING.get(environment.settings()));
try {LogConfigurator.configure(environment);
} catch (IOException e) {throw new BootstrapException(e);
}
if (environment.pidFile() != null) {
try {PidFile.create(environment.pidFile(), true);
} catch (IOException e) {throw new BootstrapException(e);
}
}
final boolean closeStandardStreams = (foreground == false) || quiet;
try {if (closeStandardStreams) {final Logger rootLogger = LogManager.getRootLogger();
final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class);
if (maybeConsoleAppender != null) {Loggers.removeAppender(rootLogger, maybeConsoleAppender);
}
closeSystOut();}
// fail if somebody replaced the lucene jars
checkLucene();
// install the default uncaught exception handler; must be done before security is
// initialized as we do not want to grant the runtime permission
// setDefaultUncaughtExceptionHandler
Thread.setDefaultUncaughtExceptionHandler(new ElasticsearchUncaughtExceptionHandler());
INSTANCE.setup(true, environment);
try {
// any secure settings must be read during node construction
IOUtils.close(keystore);
} catch (IOException e) {throw new BootstrapException(e);
}
INSTANCE.start();
if (closeStandardStreams) {closeSysError();
}
} catch (NodeValidationException | RuntimeException e) {// disable console logging, so user does not see the exception twice (jvm will show it already)
final Logger rootLogger = LogManager.getRootLogger();
final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class);
if (foreground && maybeConsoleAppender != null) {Loggers.removeAppender(rootLogger, maybeConsoleAppender);
}
Logger logger = LogManager.getLogger(Bootstrap.class);
// HACK, it sucks to do this, but we will run users out of disk space otherwise
if (e instanceof CreationException) {
// guice: log the shortened exc to the log file
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = null;
try {ps = new PrintStream(os, false, "UTF-8");
} catch (UnsupportedEncodingException uee) {
assert false;
e.addSuppressed(uee);
}
new StartupException(e).printStackTrace(ps);
ps.flush();
try {logger.error("Guice Exception: {}", os.toString("UTF-8"));
} catch (UnsupportedEncodingException uee) {
assert false;
e.addSuppressed(uee);
}
} else if (e instanceof NodeValidationException) {logger.error("node validation exception\n{}", e.getMessage());
} else {
// full exception
logger.error("Exception", e);
}
// re-enable it if appropriate, so they can see any logging during the shutdown process
if (foreground && maybeConsoleAppender != null) {Loggers.addAppender(rootLogger, maybeConsoleAppender);
}
throw e;
}
}
//......
}
- Bootstrap 的 init 静态方法使用 Thread.setDefaultUncaughtExceptionHandler(new ElasticsearchUncaughtExceptionHandler()) 来给线程设置 defaultUncaughtExceptionHandler
小结
- ElasticsearchUncaughtExceptionHandler 实现了 Thread.UncaughtExceptionHandler 接口;uncaughtException 方法首先判断 throwable 是否是 Error 类型,是的话则执行 onFatalUncaught(
logger.error
),然后执行 halt 方法,不是则执行 onNonFatalUncaught(logger.warn
) - halt 方法 AccessController.doPrivileged 来执行对应 status 的 PrivilegedHaltAction,该 action 执行的是 Runtime.getRuntime().halt(status)
- Bootstrap 的 init 静态方法使用 Thread.setDefaultUncaughtExceptionHandler(new ElasticsearchUncaughtExceptionHandler()) 来给线程设置 defaultUncaughtExceptionHandler
doc
- ElasticsearchUncaughtExceptionHandler
正文完
发表至:无分类
2019-05-29