Elasticsearch 產品自發布以來,隨着功能不斷增強,其在各種互聯網產品、企業級應用產品中的應用也越來越廣泛。日常 Elasticsearch 集群運維過程中,我們需要了解集群都能夠輸出什么類型的日志、日志的存放位置以及日志配置修改的方式,閱讀本文,我們能夠了解以下知識點:
- Elasticsearch 日志輸出方式
- Elasticsearch 日志配置方法
- Elasticsearch 日志按類型輸出到不同的文件中
- Elasticsearch 慢查詢日志配置方法
希望通過本文,讓大家對 Elasticsearch 的日志有更深刻的認識,方便大家的運維開發工作。
本文所有代碼與配置在 Elasticsearch 7.1.1 中運行和驗證。
Elasticsearch 日志輸出方式
Elasticsearch 使用 Log4j2 作為默認的日志組件,其日志輸出的安裝及運行方式相關,對於 Docker 方式運行的 Elasticsearch 實例,默認會輸出到控制台中。對於 yum 或手工方式安裝運行的 Elasticsearch 實例,日志默認以文件形式保存在 $ES_HOME/logs
目錄下,我們可以通過修改 elasticsearch.yml
文件中的 path.logs
來指定日志保存的路徑。
Elasticsearch 的使用了 Log4j2 來進行日志記錄,如果不太熟悉
Log4j2
中的一些概念,可以通過 淺談Log4j2日志框架及使用 來進一步了解。
Elasticsearch 的日志配置
Elasticsearch 為我們提供了豐富的日志配置選項,當我們運維的 Elasticsearch 集群規模越來越大、訪問量越來越高時,正確的使用這些配置能夠方便我們快速的定位和分析生產運行中產生的各類問題。
在日志配置這個小節,將介紹以下幾個知識點:
- 如何配置日志輸出到文件
- 如何配置日志的滾動策略
- 如何調整日志的級別
- 常見的
無法加載插件
錯誤
如何配置日志輸出到文件
如果使用容器啟動 Elasticsearch 服務,日志文件默認會輸出的終端,如果希望將日志輸出到文件中,首先通過修改 elasticsearch.yml
文件中的 path.logs
參數定義保存的位置,默認為 /usr/share/elasticsearch/logs
。然后再通過修改 $ES_HOME/config/log4j2.properties
文件來配置相關的日志文件名生成規則。
Elasticsearch 提供了三個屬性,通過在日志配置文件中引用這三個屬性來自定義日志的輸出
${sys:es.logs.base_path}
在配置文件中將被解析為日志目錄${sys:es.logs.cluster_name}
在配置文件中將被解析為集群名稱${sys:es.logs.node_name}
在配置文件中將被解析為節點名稱${sys:file.separator}
將被解析為路徑分隔符
如下配置演示了 log4j2.properties
中如何使用這三個變量來定義我們的日志文件名
appender.transport.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_transport.json
appender.transport.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-transport-%i.json.gz
下面可以看到日志文件已經按照配置的規則生成了,如果日志文件的大小不斷增長怎么辦呢,會不會把文件系統撐爆,要不要設置日志文件清理策略,別着急下個小節告訴我們如何配置日志的滾動策略。
如何配置日志的滾動策略
日志滾動在日常運維中是非常常見的一種日志管理手段,通過日志滾動策略既保留了必要的日志內容,同時又防止日志數量超過本地文件系統的容量,並且防止單個日志文件變得太大而難於打開。
日志滾動通常有兩種策略,一種是根據時間,例如每天生成一個日志文件;另一種是根據文件大小,例如每100MB生成一個日志文件。在上一節中,我們通過 filePattern
參數決定了當日志文件發生滾動時,新文件的命名規則。
下面的配置根據文件大小和日期設置日志的滾動策略。
logger.transport.name = org.elasticsearch.transport
logger.transport.level = trace
logger.transport.appenderRef.rolling.ref = transport-rolling
appender.transport.type = RollingFile
appender.transport.name = transport-rolling
appender.transport.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_transport.json
appender.transport.layout.type = ESJsonLayout
appender.transport.layout.type_name = transport
appender.transport.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-transport-%i.json.gz
appender.transport.policies.type = Policies
appender.transport.policies.time.type = TimeBasedTriggeringPolicy
appender.transport.policies.time.interval = 1
appender.transport.policies.time.modulate = true
appender.transport.policies.size.type = SizeBasedTriggeringPolicy
appender.transport.policies.size.size = 10KB
可以看到實際的效果
文件大小並不是嚴格的10KB,我理解是因為這個值設置的比較小,當多一行日志會導致大小超過閾值時,提前做了文件滾動。
我們還可以指定滾動日志文件的保留策略,默認是對策略以外的文件進行刪除。
如下配置所示,日志保留策略監聽 basepath
文件夾下的文件,當文件的數量超過 5 個時,對之前產生的文件進行刪除。
logger.transport.name = org.elasticsearch.transport
logger.transport.level = trace
logger.transport.appenderRef.rolling.ref = transport-rolling
appender.transport.type = RollingFile
appender.transport.name = transport-rolling
appender.transport.fileName = ${sys:es.logs.base_path}${sys:file.separator}transport-logs${sys:file.separator}${sys:es.logs.cluster_name}_transport.json
appender.transport.layout.type = ESJsonLayout
appender.transport.layout.type_name = transport
appender.transport.filePattern = ${sys:es.logs.base_path}${sys:file.separator}transport-logs${sys:file.separator}${sys:es.logs.cluster_name}-transport-%d{yyyy-MM-dd}-%i.json.gz
# 決定日志的滾動策略
appender.transport.policies.type = Policies
appender.transport.policies.time.type = TimeBasedTriggeringPolicy
appender.transport.policies.time.interval = 1
appender.transport.policies.time.modulate = true
appender.transport.policies.size.type = SizeBasedTriggeringPolicy
appender.transport.policies.size.size = 10KB
# 決定日志的刪除策略
appender.transport.strategy.type = DefaultRolloverStrategy
appender.transport.strategy.fileIndex = nomax
appender.transport.strategy.action.type = Delete
appender.transport.strategy.action.basepath = ${sys:es.logs.base_path}${sys:file.separator}transport-logs
appender.transport.strategy.action.condition.type = IfAccumulatedFileCount
appender.transport.strategy.action.condition.glob = *-transport-*
appender.transport.strategy.action.condition.exceeds = 10
效果如下圖,可以看到當文件夾中的文件數量超過10個時,舊的文件自動被刪除了。
日常運維過程中,我們更常用的是根據文件夾文件大小或者按照固定日期周期確定文件的保留策略,對應的配置項為 IfAccumulatedFileSize
和 IfLastModified
,更詳細的說明可以參考 log4j2的官方文檔 。
按類型輸出到不同的文件中
Elasticsearch 軟件由很多模塊組成,通過日志配置,我們可以實現將不同模塊的日志輸出到不同的文件中,對於管理更精細的團隊來說,可能有需要分門別類的查看各自模塊的日志。
參考下面的配置,即可將 transport
、discovery
模塊的日志輸出到不同的文件中。
# 將日志輸出到 Console 中
appender.rolling.type = Console
appender.rolling.name = rolling
appender.rolling.layout.type = ESJsonLayout
appender.rolling.layout.type_name = server
logger.transport.name = org.elasticsearch.transport
logger.transport.level = trace
logger.transport.appenderRef.rolling.ref = transport-rolling
appender.transport.type = RollingFile
appender.transport.name = transport-rolling
appender.transport.fileName = ${sys:es.logs.base_path}${sys:file.separator}transport-logs${sys:file.separator}${sys:es.logs.cluster_name}_transport.json
appender.transport.layout.type = ESJsonLayout
appender.transport.layout.type_name = transport
appender.transport.filePattern = ${sys:es.logs.base_path}${sys:file.separator}transport-logs${sys:file.separator}${sys:es.logs.cluster_name}-transport-%d{yyyy-MM-dd}-%i.json.gz
# 決定日志的滾動策略
appender.transport.policies.type = Policies
appender.transport.policies.time.type = TimeBasedTriggeringPolicy
appender.transport.policies.time.interval = 1
appender.transport.policies.time.modulate = true
appender.transport.policies.size.type = SizeBasedTriggeringPolicy
appender.transport.policies.size.size = 10KB
# 決定日志的刪除策略
appender.transport.strategy.type = DefaultRolloverStrategy
appender.transport.strategy.fileIndex = nomax
appender.transport.strategy.action.type = Delete
appender.transport.strategy.action.basepath = ${sys:es.logs.base_path}${sys:file.separator}transport-logs
appender.transport.strategy.action.condition.type = IfAccumulatedFileCount
appender.transport.strategy.action.condition.glob = *-transport-*
appender.transport.strategy.action.condition.exceeds = 10
logger.discovery.name = org.elasticsearch.discovery
logger.discovery.level = trace
logger.discovery.appenderRef.rolling.ref = discovery-rolling
# 僅將 discover 的日志輸出到文件中
appender.discovery.type = RollingFile
appender.discovery.name = discovery-rolling
appender.discovery.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_discovery.json
appender.discovery.layout.type = ESJsonLayout
# appender.rolling.layout.type = PatternLayout
appender.discovery.layout.type_name = server
appender.discovery.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-%i-discovery.json.gz
appender.discovery.policies.type = Policies
appender.discovery.policies.time.type = TimeBasedTriggeringPolicy
appender.discovery.policies.time.interval = 1
appender.discovery.policies.time.modulate = true
appender.discovery.policies.size.type = SizeBasedTriggeringPolicy
appender.discovery.policies.size.size = 256MB
appender.discovery.strategy.type = DefaultRolloverStrategy
appender.discovery.strategy.fileIndex = nomax
appender.discovery.strategy.action.type = Delete
appender.discovery.strategy.action.basepath = ${sys:es.logs.base_path}
appender.discovery.strategy.action.condition.type = IfFileName
appender.discovery.strategy.action.condition.glob = ${sys:es.logs.cluster_name}-*
appender.discovery.strategy.action.condition.nested_condition.type = IfAccumulatedFileSize
appender.discovery.strategy.action.condition.nested_condition.exceeds = 2GB
如何調整日志級別
Elasticsearch
默認的日志級別為 INFO
,除此之外還提供了 TRACE
、DEBUG
、INFO
、WARN
等幾個日志級別,並且支持對不同的模塊設置日志級別。針對不同模塊設置日志策略的方法參考上面,通過 logger.action.name = org.elasticsearch.transport
即可指定。可以設置的模塊簡要列在下面,更詳細的模塊可以參考 Elasticsearch 源碼。
org.elasticsearch.discovery
如果只關心這個包下面更細節的日志,也可以設置org.elasticsearch.discovery.zen
org.elasticsearch.action
org.elasticsearch.cluster
org.elasticsearch.env
org.elasticsearch.indices
org.elasticsearch.gateway
org.elasticsearch.snapshots
org.elasticsearch.http
org.elasticsearch.transport
org.elasticsearch.search
Elasticsearch
提供了多種方式來調整日志的級別:
-
通過命令行啟動參數配置,語法是:
-E <name of logging hierarchy>=<level>
(例如:-E logger.org.elasticsearch.transport=trace
),比較適用於在單個節點上臨時調試問題的場景。 -
通過修改
elasticsearch.yml
配置文件,語法為:elasticsearch.yml
:<name of logging hierarchy>: <level>
(例如:logger.org.elasticsearch.transport: trace),適用場景是沒有通過命令行啟動,但是又想臨時調試一個問題。 -
修改
log4j2.properties
配置文件,這種方式需要重啟服務。通過rootLogger.level
可以設定全局的日志級別,通過logger.transport.level
設置單個模塊的日志界別。適合需要更加細化的進行日志配置的場景。 -
通過API進行日志級別的動態修改。通過下面的命令可以動態調整全局的日志級別。
PUT /_cluster/settings {"transient":{"logger._root":"DEBUG"}}
常見的 無法加載插件
錯誤
如果啟動的時候發現下面的報錯,無法加載各種插件,請檢查配置文件相關的行尾是否有空格,我遇到這種錯誤就是因為配置文件的內容從網上拷貝的時候,行尾帶了空格。
elasticsearch_1 | OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
elasticsearch_1 | 2020-09-08 11:28:45,379 main ERROR Unable to locate plugin type for TimeBasedTriggeringPolicy
elasticsearch_1 | 2020-09-08 11:28:45,381 main ERROR Unable to locate plugin type for SizeBasedTriggeringPolicy
elasticsearch_1 | 2020-09-08 11:28:45,382 main ERROR Unable to locate plugin type for Delete
elasticsearch_1 | 2020-09-08 11:28:45,473 main ERROR Unable to locate plugin for TimeBasedTriggeringPolicy
官方文檔也給出了友情提示。
Log4j’s configuration parsing gets confused by any extraneous whitespace; if you copy and paste any Log4j settings on this page, or enter any Log4j configuration in general, be sure to trim any leading and trailing whitespace.
寫在最后
我編寫了一套 docker-compose
的編排文件,支持一鍵式的創建一個單獨的 Elasticsearch
實例和一個單獨的 Kibana
實例,通過 docker 可以方便的按照文檔中的示例進行反復的實驗,關於 docker 及 docker-compose 的介紹,大家可以參考我之前的兩篇文章:Docker入門介紹 和 Docker Composer使用介紹。
參考資料
- Elasticsearch調優篇-慢查詢分析筆記
- Elasticsearch 官方文檔
- ES慢查詢收集總結
- log4j.properties 配置詳解
- Elasticsearch搭建和日志配置
- Elasticsearch 集群優化-盡可能全面詳細
- Elasticsearch 7.0 之日志配置
- Elasticsearch document : Logging configuration
- elasticsearch – 錯誤無法找到插件類型[用於RollingFile和TimeBasedTriggeringPolicy]
- Elasticsearch Logging Secrets
- 淺談Log4j2日志框架及使用
- log4j2 appender
- Elasitcsearch 7.0 之日志配置