敲代碼有時候真的有點難,要考慮各類狀況。css
應用在執行中,會不斷生成日誌文件。html
假如要實現一個日誌收集的工具。不考慮其餘的分析功能,僅僅考慮收集,有哪些方面要考慮的?node
首先看下通常的log框架是怎樣輸出日誌的:mysql
多是這種:a.log.1, a.log.2, a.log.3, a.log.4, a.log.5 循環輸出。linux
多是這種: a.2014-5-5.log, a.2014-5-6.log, a.2014-5-7.log,天天生成一個日誌文件;git
多是這種:log.out。每次從新啓動都會生成一個新的log.out,覆蓋舊的文件。github
那麼,咱們有哪些方面要實現和注意的?redis
如下解釋下logstash是怎樣實現和處理上面的問題的:sql
可以配置path參數(Array),當中支持globs風格的匹配。如:ruby
path => [ "/var/log/messages", "/var/log/*.log" ]
可以配置exclude參數(Array),排除掉不需要的文件。如:
exclude => "*.gz"
logstash把進度保存到所謂的sincedb裏,實際上即這種一個文本文件,默認是放在home文件夾下的。如:
.sincedb_e794081d6134aace51b759aea8cc3be2
.sincedb_f7a0c8a0def03e0c572511ceea0b9f63
後面是日誌文件。即path的hash值。
這樣就區分了不一樣的文件名稱的日誌文件的進度保存問題。
sincedb文件中是類似這種內容:
6511055 0 2051 118617881
5495516 0 2051 155859036
6348913 0 2051 148511449
上面的4列各自是:
inode, major number, minor number, pos。
當中major number和minor number是設備相關的數字,參考:http://unix.stackexchange.com/questions/73988/linux-major-and-minor-device-numbers
inode是文件系統給文件分配的是一個號碼,參考:http://zh.wikipedia.org/wiki/Inode
所以logstash區分了設備。文件名稱,文件的不一樣版本號。
這裏引出了一個新問題。用inode來推斷文件的不一樣版本號,是否夠準確了?因爲inode是會回收再使用的。
比方依次執行如下的命令,可以發現。兩個文件的inode是同樣的:
touch test stat test rm test touch test stat test
但是因爲logstash是沒有close掉文件,因此是一直持有inode,因此新的同名的日誌文件會有一個新的inode。
也正是因爲這樣,假設logstash監視的日誌文件假設被刪除了,仍是可以繼續把刪除的文件的內容處理完。
利用inode這點特性,有時可以作一些補救工做,比方不當心把mysql的文件刪掉了,仍是可以把數據dump出來,因爲mysql進程還持有數據文件的inode。
另外,logstash默認是每隔1秒就嘗試讀取文件有沒有新內容,默認是15秒就掃描,檢查有沒有新文件。相應stat_interval和discover_interval參數。
另外一些小細節:
比方每次最多僅僅讀取出16394字節的數據,防止佔用過多的內存,每5秒推斷下是否需要保存新的pos。
假設日誌文件被刪除了,也會刪除sincedb文件。
當讀取到新文件內容時。pos會添加,在保存新的pos到sincedb時,logstash採用了暫時文件的辦法:
先創建一個暫時文件,寫入新內容。再調用操做系統提供的remane函數。原子性地替換原來的sincedb文件。
這種其實是比較常用的技巧了,redis也是這樣子作的。
很是遺憾。這是不能的,除非是分佈式事務。不然,總有可能丟失或者反覆發送數據。不論什麼日誌收集軟件或者消息隊列軟件都是如此。
詳細的實現代碼就不貼了,因爲比較易讀,當中logstash使用了filewatch這個庫。可以用gem來安裝。相關的代碼在線查看:
https://github.com/elasticsearch/logstash/blob/v1.4.1/lib/logstash/inputs/file.rb
https://github.com/jordansissel/ruby-filewatch/tree/master/lib/filewatch
fluentd也是一個很是流行的日誌收集工具。
簡單再看了下fluentd的in_tail插件,發現裏面還有本身當年提交的一個防止內存佔用過大的建議:)
https://github.com/fluent/fluentd/blob/master/lib/fluent/plugin/in_tail.rb
fluentd的in_tail插件的原理和logstash的file input是幾乎相同的,都是用inode來區分文件是否更新。
但是fluentd僅僅保存了inode和pos。沒有logstash那樣把設備都考慮進去了。
另外fluentd保存pos時,都是以文件追加的方式來保存的,沒有像logstash那樣是用rename文件來保存到新文件中。顯然logstash的實現更加合理。
扯遠一點。logstash部署要比fluentd方便。雖然二者都是用ruby寫的。不一樣的是logstash默認是jruby,僅僅要有JVM就可以跑,fluentd則要安裝ruby環境。比較麻煩。
logstash大有一統江湖之勢,這句話忘記在哪裏看到的了。在github上的logstash的start有2000多個。
logstash + elasticsearch + Kibana的日誌收集。搜索,展示的一條龍服務很是流行。
http://unix.stackexchange.com/questions/73988/linux-major-and-minor-device-numbers
http://zh.wikipedia.org/wiki/Inode
https://github.com/elasticsearch/logstash/blob/v1.4.1/lib/logstash/inputs/file.rb