一文教您如何通過 Java 壓縮文件,打包一個 tar.gz Filebeat 採集器包

  • 2019 年 11 月 12 日
  • 筆記

歡迎關注筆者的公眾號: 小哈學Java, 專註於推送 Java 領域優質乾貨文章!!

個人網站: https://www.exception.site/essay/create-tar-gz-by-java

一、背景

最近,小哈主要在負責日誌中台的開發工作, 等等,啥是日誌中台?

俺只知道中台概念,這段時間的確很火,但是日誌中台又是用來幹啥的

這裡小哈盡量地通俗的說下日誌中台的職責,再說日誌中台之前,我們先扯點別的?

相信大家對集中式日誌平台 ELK 都知道一些,生產環境中, 稍複雜的架構,服務一般都是集群部署,這樣,日誌就會分散在每台伺服器上,一旦發生問題,想要查看日誌就會非常繁瑣,你需要登錄每台伺服器找日誌,因為你不確定請求被打到哪個節點上。另外,任由開發人員登錄伺服器查看日誌本身就存在安全隱患,不小心執行了 rm -rf * 咋辦?

通過 ELK , 我們可以方便的將日誌收集到一處(Elasticsearch 集群)來進行多維度的分析。

但是部署高性能、高可用的 ELK 是有門檻的,業務組想要快速的擁有集中式日誌分析的能力,往往需要經過前期的技術調研,測試,踩坑,才能將這個平台搭建起來。

日誌中台的使命就是讓業務線能夠快速擁有這種能力,只需傻瓜式的在日誌平台完成接入操作即可

臭嗨!說了這麼多,跟你這篇文章的主題有啥關係?

額,小哈這就進入主題。

既然想統一管理日誌,總得將這些分散的日誌採集起來吧,那麼,就需要一個日誌採集器,LogstashFilebeat 都有採集日誌的能力,但是 Filebeat 相較於 Logstash 的笨重, 它更輕量級,幾乎零佔用伺服器系統資源,這裡我們選型 Filebeat

業務組在日誌平台完成相關接入流程後,平台會提供一個採集器包。接入方需要做的就是,下載這個採集器包並扔到指定伺服器上,解壓運行,即可開始採集日誌,然後,就可以在日誌平台的管控頁面分析&搜索這些被收集的日誌了。

這個 Filebeat 採集器包裡面,包含了採集日誌文件路徑,輸出到 Kafka 集群,以及一些個性化的採集規則等等。

怎麼樣?是不是感覺很棒呢?

二、如何通過 Java 打包文件?

2.1 添加 Maven 依賴

<dependency>    <groupId>org.apache.commons</groupId>    <artifactId>commons-compress</artifactId>    <version>1.12</version>  </dependency>

2.2 打包核心程式碼

通過 Apache compress 工具打包思路大致如下:

  • ①:創建一個 FileOutputStream 到輸出文件(.tar.gz)文件。

  • ②:創建一個GZIPOutputStream,用來包裝FileOutputStream對象。

  • ③:創建一個TarArchiveOutputStream,用來包裝GZIPOutputStream對象。

  • ④:接著,讀取文件夾中的所有文件。

  • ⑤:如果是目錄,則將其添加到 TarArchiveEntry

  • ⑥:如果是文件,依然將其添加到 TarArchiveEntry 中,然後還需將文件內容寫入 TarArchiveOutputStream 中。

接下來,直接上程式碼:

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;  import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;  import org.apache.commons.io.IOUtils;    import java.io.*;  import java.util.zip.GZIPOutputStream;    /**   * @author 犬小哈 (公眾號: 小哈學Java)   * @date 2019-07-15   * @time 16:15   * @discription   **/  public class TarUtils {        /**       * 壓縮       * @param sourceFolder 指定打包的源目錄       * @param tarGzPath 指定目標 tar 包的位置       * @return       * @throws IOException       */      public static void compress(String sourceFolder, String tarGzPath) throws IOException {          createTarFile(sourceFolder, tarGzPath);      }        private static void createTarFile(String sourceFolder, String tarGzPath) {          TarArchiveOutputStream tarOs = null;          try {              // 創建一個 FileOutputStream 到輸出文件(.tar.gz)              FileOutputStream fos = new FileOutputStream(tarGzPath);              // 創建一個 GZIPOutputStream,用來包裝 FileOutputStream 對象              GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(fos));              // 創建一個 TarArchiveOutputStream,用來包裝 GZIPOutputStream 對象              tarOs = new TarArchiveOutputStream(gos);              // 若不設置此模式,當文件名超過 100 個位元組時會拋出異常,異常大致如下:              // is too long ( > 100 bytes)              // 具體可參考官方文檔: http://commons.apache.org/proper/commons-compress/tar.html#Long_File_Names              tarOs.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);              addFilesToTarGZ(sourceFolder, "", tarOs);          } catch (IOException e) {              e.printStackTrace();          }finally{              try {                  tarOs.close();              } catch (IOException e) {                  e.printStackTrace();              }          }      }        public static void addFilesToTarGZ(String filePath, String parent, TarArchiveOutputStream tarArchive) throws IOException {          File file = new File(filePath);          // Create entry name relative to parent file path          String entryName = parent + file.getName();          // 添加 tar ArchiveEntry          tarArchive.putArchiveEntry(new TarArchiveEntry(file, entryName));          if (file.isFile()) {              FileInputStream fis = new FileInputStream(file);              BufferedInputStream bis = new BufferedInputStream(fis);              // 寫入文件              IOUtils.copy(bis, tarArchive);              tarArchive.closeArchiveEntry();              bis.close();          } else if (file.isDirectory()) {              // 因為是個文件夾,無需寫入內容,關閉即可              tarArchive.closeArchiveEntry();              // 讀取文件夾下所有文件              for (File f : file.listFiles()) {                  // 遞歸                  addFilesToTarGZ(f.getAbsolutePath(), entryName + File.separator, tarArchive);              }          }      }        public static void main(String[] args) throws IOException {          // 測試一波,將 filebeat-7.1.0-linux-x86_64 打包成名為 filebeat-7.1.0-linux-x86_64.tar.gz 的 tar 包          compress("/Users/a123123/Work/filebeat-7.1.0-linux-x86_64", "/Users/a123123/Work/tmp_files/filebeat-7.1.0-linux-x86_64.tar.gz");      }    }

至於,程式碼每行的作用,小夥伴們可以看程式碼注釋,說的已經比較清楚了。

接下來,執行 main 方法,測試一下效果,看看打包是否成功:

生成採集器 tar.gz 包成功後,業務組只需將 tar.gz 下載下來,並扔到指定伺服器,解壓運行即可完成採集任務啦~

三、結語

本文主要還是介紹如何通過 Java 來完成打包功能,關於 ELK 相關的知識,小哈會在後續的文章中分享給大家,本文只是提及一下,歡迎小夥伴們持續關注喲,下期見~

四、Ref

歡迎關注微信公眾號: 小哈學Java

更多乾貨文章,請關注筆者公眾號: 小哈學Java (ID: xiaoha_java), 專註於分享Java領域乾貨文章, 不限於 BAT 面試題分享,Spring Boot, Spring Cloud, 高並發,JVM, 資料庫,Docker 容器, ELK 等相關知識,另外,關注回復「資源」,即可獲取全文最熱的 Java 面試&架構學習資源喲~

關注微信公眾號【小哈學Java】,回復【資源】,即可免費無套路領取資源鏈接哦