企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 使用 Java 在 Linux 中管理不超过 N GB 的系统日志文件 > 原文: [https://howtodoinjava.com/linux/manage-system-log-files-in-linux-using-java/](https://howtodoinjava.com/linux/manage-system-log-files-in-linux-using-java/) 如今,大多数应用程序都需要管理自己的日志文件,包括在达到特定大小限制时将其删除。 在本文中,我将尝试为这种日志文件管理提出一种解决方案。 我还将建议捕获 [*linux*](https://en.wikipedia.org/wiki/Linux "Linux") 进程的输出并将其记录到一些单独的日志文件中的方法。 本文是我上一篇文章的延续:[自动重载配置](//howtodoinjava.com/java-7/auto-reload-of-configuration-when-any-change-happen/ "Auto reload of configuration when any change happen"),其中我讨论了只要有人在文件系统中更改配置文件,应用程序如何无需重新启动应用程序即可完成其配置重载的工作 。 **这篇文章中的部分:** * 确定方法 * 编写 bash 脚本 * 编写脚本执行器 * 添加食流者 * 查看全部 ## 确定方法 我相信,要把工作做好,我们肯定需要一个 bash 脚本。 Linux 有一些非常有用的内置命令,通过命令窗口执行时,这些命令可以立即执行此工作。 bash 脚本的优势包括将实际应用程序的文件处理程序代码解耦,如果需要任何特定于平台的更改,可以对其进行修改。 ## 编写 bash 脚本 我已经编写了一个演示脚本。 您可以根据需要使用它: ```java #!/bin/bash ############################################################################### # # discCleanUp.sh # ################################################################################ DIR_PATH=$1 NUM_OF_DAYS=$2 DIR_SIZE=$3 SIZE=1024 DIR_SIZE=$(($DIR_SIZE * $SIZE * $SIZE)) # Command to find the File older then NUM_OF_DAYS and removing them from directory DIR_PATH find $DIR_PATH -mtime +$NUM_OF_DAYS -exec rm {} ; #Go to specified directory cd $DIR_PATH # Command to get the current directory size. CURR_DIR_SIZE=`du -sk | cut -f1` while [[ $CURR_DIR_SIZE -gt DIR_SIZE ]]; do echo $CURR_DIR_SIZE FILE=`ls -1tra | head -1` rm -rf $FILE # Command to get the current directory size. CURR_DIR_SIZE=`du -sk | cut -f1` done exit 0 ``` 在上面的脚本中,`DIR_PATH`,`NUM_OF_DAYS`和`DIR_SIZE`是命令行参数。 而`SIZE`是用于计算目的的常数。 在上面的脚本中,**行号 16** 将删除 n 天之前的日志文件。 在**行号 22** 中,脚本使用[*`du`命令*](http://linux.about.com/library/cmd/blcmdl1_du.htm "Linux du command")检查目录的当前大小。 如果大小超过`DIR_SIZE`(以 GB 为单位),脚本将开始使用`ls -1tra | head -1`命令并开始将它们一个一个地删除。 它将继续直到目录大小未达到所需的限制。 ## 编写脚本执行器 至于本文,核心组件将保留在 bash 脚本之上,但仍然需要一种从应用程序运行`.sh`文件的方法。 最好的方法是使用线程(如果需要,可以使用[执行器](https://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorService.html "Executor Service"))。 该线程将以可配置的速率定期执行以上 bash 脚本。 我不会写那部分代码。 如果执行代码时遇到任何问题,请写下注释。 让我给你一个示例代码:: ```java package corejava.dischandler; import java.io.IOException; /** * Title: DiskFileManager.java * Description :- This class provides API to check file size and file time threshold and * if threshold is crossed then deletes file to come within threshold. */ public final class DiskFileManager { private static DiskFileManager diskFileManager=new DiskFileManager(); private DiskFileManager() { } /** * <pre> * <b>checkAndDeleteFiles</b> * <b>Description:This method is called to clean the files from the file system.</b> * </pre> * @throws InterruptedException * @throws IOException * @throws InstantiationException */ public   void checkAndDeleteFiles() throws InterruptedException, IOException, InstantiationException { try { StringBuffer outStr = new StringBuffer(); StringBuffer errStr = new StringBuffer(); String scriptFileName = "./discfilehandler.sh"; String command = scriptFileName + "/logs 1 1"; System.out.println("Command to be executed  :- " + command); Process output = Runtime.getRuntime().exec(command); StreamEater errorEater = new StreamEater(output.getErrorStream(),errStr); StreamEater outputEater = new StreamEater(output.getInputStream(),outStr); errorEater.start(); outputEater.start(); try { int ret = output.waitFor(); errorEater.join(); outputEater.join(); System.out.println(); //logger.info("execute(): Error Stream:" + errStr + " ; execute(): Output Stream:" + outStr + " ; execute(): ExitValue:" + ret); } catch (InterruptedException e) { throw e; } } catch (IOException e) { throw e; } } /** * <pre> * <b>getInstance</b> * <b>Description:This method is used to get the instance of Disk File Manager.</b> * </pre> * @return */ public static DiskFileManager getInstance() { return diskFileManager; } } ``` 上面的代码将在类路径中找到脚本文件,并传递所需的参数。 在我们的例子中,`/logs 1 1`是 3 个参数,这意味着 * 要监视的目录是`/logs`, * 删除一天的日志文件,然后 * 请勿在任何时候存储超过 1 GB 的日志文件。 ## 添加`StreamEater` 因此,我们已经添加了一个 bash 脚本和一个用于运行脚本的执行器代码。 您必须编写自己的线程才能在执行器上方定期运行。 现在,我们将研究`StreamEater`,它实际上收集命令输出并提供给您的应用程序代码,因此应用程序可以记录它或执行所需的任何操作。 我们已经在上面的执行器中使用过`StreamEater`,现在我给出其代码: ```java package corejava.dischandler; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; public class StreamEater extends Thread { /** * Stream Eater thread to eat up every thing that is the output to the * execute command */ private InputStream  iStream; public InputStream getiStream() { return iStream; } public void setiStream(InputStream iStream) { this.iStream = iStream; } private StringBuffer stringBuffer; public StringBuffer getStringBuffer() { return stringBuffer; } public void setStringBuffer(StringBuffer stringBuffer) { this.stringBuffer = stringBuffer; } /** * This is the constructor. * * @param is - It is the input stream * @param type - type of input stream * @param redirect - string buffer to contain the output. * @throws InstantiationException */ public StreamEater(InputStream is, StringBuffer redirect) throws InstantiationException { this.iStream = is; if (redirect == null) { throw new InstantiationException("String Buffer Reference , second param can not be null"); } this.stringBuffer = redirect; } /** * This is method called when the thread is started. It captures the stream * output and and store it into the buffer. */ public void run() { InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(iStream); br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { stringBuffer.append(line).append(System.getProperty("line.separator")); } } catch (Exception ex) { ex.printStackTrace(); } finally { if (isr != null) { try { isr.close(); } catch (Exception e) { e.printStackTrace(); } } if (br != null) { try { br.close(); } catch (Exception e) { e.printStackTrace(); } } } } } ``` 如您所见,这些都是等待收集进程输出的小线程。 ## 查看全部 使用上述类和给定的 bash 脚本,您可以轻松开发一些应用程序组件,以确保日志文件的大小不超过某些预定义的数目。 当您的应用程序负责删除实际的日志文件时,可以在任何级别对​​其进行自定义。 希望您在这篇文章中得到一些有用的信息。 如果需要任何帮助或有任何疑问,请给我留言。 学习愉快!