詳解如何查看Elasticsearch的Debug日志

正文

當我們遇到問題或者需要深入瞭解 Elasticsearch 的運行機制時,調整日志等級( logging level )到更詳細的級別,比如 DEBUGTRACE ,會是一個有效且必須要掌握的方法。

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()) {
        if (LogManager.ROOT_LOGGER_NAME.equals(logger.getName()) || loggerConfig.getName().startsWith(logger.getName() + ".")) {
            Configurator.setLevel(loggerConfig.getName(), level);
        }
    }
}

最後的處理邏輯會在每個 logger 設定完成後,去重新刷一遍現有的 logger,應用 root 或者 parent logger 的設定。

順著代碼的修改記錄,找到瞭當初的修改 PR 如下:

[https://github.com/elastic/el…]()

其中也描述瞭修改的原因:

Today when setting the logging level via the command-line or an API
call, the expectation is that the logging level should trickle down the
hiearchy to descendant loggers. However, this is not necessarily the
case. For example, if loggers x and x.y are already configured then
setting the logging level on x will not descend to x.y. This is because
the logging config for x.y has already been forked from the logging
config for x. Therefore, we must explicitly descend the hierarchy when
setting the logging level and that is what this commit does.

從這段描述看,當時要解決的問題是 x.y 沒有繼承 x logging level 的問題,所以加瞭這段顯示繼承的邏輯。

雖然這解決瞭繼承的問題,但其行為本身與 log4j2.properties 中 logger 的修改邏輯就不一致瞭,難免帶來困擾。

但考慮到這個配置是一個專傢級別的配置,很少用戶會使用,自己心裡明白正確的使用方法就好瞭^_^

以上就是詳解如何查看Elasticsearch的Debug日志的詳細內容,更多關於Elasticsearch Debug日志查看的資料請關註WalkonNet其它相關文章!

推薦閱讀: