你真的知道如何查看 Elasticsearch 的 Debug 日志吗?!
当我们遇到问题或者需要深入了解 Elasticsearch 的运行机制时,调整日志等级(
logging level
)到更详细的级别,比如
DEBUG
、
TRACE
,会是一个有效且必须要掌握的方法。
Elasticsearch 提供了如下的接口来支持动态变更 logging level,logger 后面是 package name 或者 class name。
PUT _cluster/settings
"persistent": {
"logger": {
"org.elasticsearch.action": "DEBUG"
当然,你也可以去修改配置目录下面的 log4j2.properties,然后重启节点,但这种方法太过笨重,建议你不要用。
如果后续想要调整回默认设置,操作也简单,如下所示:
PUT _cluster/settings
"persistent": {
"logger": {
"org.elasticsearch.action": null
上面的示例只是指定了一个 logger,当然也可以在一次请求中设定多个 logger,如下所示:
PUT _cluster/settings
"persistent": {
"logger": {
"_root": "INFO",
"org.elasticsearch.action": "DEBUG",
"org.elasticsearch.action.admin.cluster.health": "TRACE"
上面的设定中,调用者的意图可能如下:
-
root 的日志等级(默认所有 logger 的日志级别)设定为 INFO,虽然 log4j2.properties 中已经设定过了,保险起见,这里再指定一次。
-
设定 org.elasticsearch.action 这个 package 下所有 logger 的日志级别都为 DEBUG,需要查看下 transport action 的执行日志。
-
设定 org.elasticsearch.action.admin.cluster.health 这个 package 下所有 logger 的日志级别都为 TRACE,需要查看 Cluster Health 执行的更多日志。
但实际去运行时,Elasticsearch 并没有按照预期的结果去执行,没有相关
DEBUG
和
TRACE
级别的日志输出。这里直接给出原因和解决方案。
原因是 elasticsearch 在设定 logging level 时,会
优先采用
_root
和
parent logger
的设定,这里和 log4j2.properties 中的设定有所差异。
上面的调用,最终结果是采用 _root 的设定,所有 logger 都是
INFO
,其他的设定都无效了。
解决方案如下,去除 _root 设定和 parent logger 的设定。
PUT _cluster/settings
"persistent": {
"logger": {
"_root": null,
"org.elasticsearch.action": null,
"org.elasticsearch.action.admin.cluster.health": "TRACE"
下面就是 源码分析 了,感兴趣的可以继续看下去~
源码分析
相关实现逻辑在
ClusterSetting.LoggingSettingUpdater
里面,这里简单给下定位的思路,感兴趣的同学可以自己去翻下源码。
-
rest 请求的入口是
RestClusterUpdateSettingsAction
,这里会转发请求到 master 节点
-
master 处理的入口是
TransportClusterUpdateSettingsAction
,这里会去 update Cluster Setting,关键词为updater.updateSettings
。
-
在 updateSettings的时候会调用所有的 ClusterSettingUpdater,Logging 就是其中之一。
这里 apply setting 的代码如下:
for (String key : value.keySet()) {
assert loggerPredicate.test(key);
String component = key.substring("logger.".length());
if ("level".equals(component)) {
continue;
if ("_root".equals(component)) {
final String rootLevel = value.get(key);
if (rootLevel == null) {
Loggers.setLevel(LogManager.getRootLogger(), Loggers.LOG_DEFAULT_LEVEL_SETTING.get(settings));
} else {
Loggers.setLevel(LogManager.getRootLogger(), rootLevel);
} else {
Loggers.setLevel(LogManager.getLogger(component), value.get(key));
浅显易懂,不废话,而且这里的逻辑看起来很正常,那么继续来看下 Loggers.setLevel代码。
public static void setLevel(Logger logger, Level level) {
if (!LogManager.ROOT_LOGGER_NAME.equals(logger.getName())) {
Configurator.setLevel(logger.getName(), level);
} else {
final LoggerContext ctx = LoggerContext.getContext(false);
final Configuration config = ctx.getConfiguration();
final LoggerConfig loggerConfig = config.getLoggerConfig(logger.getName());
loggerConfig.setLevel(level);
ctx.updateLoggers();
// we have to descend the hierarchy
final LoggerContext ctx = LoggerContext.getContext(false);
for (final LoggerConfig loggerConfig : ctx.getConfiguration().getLoggers().values()) {