原文: https://howtodoinjava.com/linux/manage-system-log-files-in-linux-using-java/

如今,大多数应用都需要管理自己的日志文件,包括在达到特定大小限制时将其删除。 在本文中,我将尝试为这种日志文件管理提出一种解决方案。 我还将建议捕获 linux 进程的输出并将其记录到一些单独的日志文件中的方法。

本文是我上一篇文章的延续:自动重载配置,其中我讨论了只要有人在文件系统中更改配置文件,应用如何无需重新启动应用即可完成其配置重载的工作。 。

这篇文章中的部分

  • 确定方法
  • 编写 bash 脚本
  • 编写脚本执行器
  • 添加StreamEater
  • 查看全部

确定方法

我相信,要把工作做好,我们肯定需要一个 bash 脚本。 Linux 具有一些非常有用的内置命令,这些命令在通过命令窗口执行时可以立即执行此工作。 bash 脚本的优势包括将实际应用的文件处理器代码解耦,如果需要任何特定于平台的更改,可以对其进行修改。

编写 bash 脚本

我已经编写了一个演示脚本。 您可以根据需要使用它:

  1. #!/bin/bash
  2. ###############################################################################
  3. #
  4. # discCleanUp.sh
  5. #
  6. ################################################################################
  7. DIR_PATH=$1
  8. NUM_OF_DAYS=$2
  9. DIR_SIZE=$3
  10. SIZE=1024
  11. DIR_SIZE=$(($DIR_SIZE * $SIZE * $SIZE))
  12. # Command to find the File older then NUM_OF_DAYS and removing them from directory DIR_PATH
  13. find $DIR_PATH -mtime +$NUM_OF_DAYS -exec rm {} ;
  14. #Go to specified directory
  15. cd $DIR_PATH
  16. # Command to get the current directory size.
  17. CURR_DIR_SIZE=`du -sk | cut -f1`
  18. while [[ $CURR_DIR_SIZE -gt DIR_SIZE ]];
  19. do
  20. echo $CURR_DIR_SIZE
  21. FILE=`ls -1tra | head -1`
  22. rm -rf $FILE
  23. # Command to get the current directory size.
  24. CURR_DIR_SIZE=`du -sk | cut -f1`
  25. done
  26. exit 0

在上面的脚本中,DIR_PATHNUM_OF_DAYSDIR_SIZE是命令行参数。 而SIZE是用于计算目的的常数。 在上面的脚本中,行号 16 将删除 n 天之前的日志文件。

行号 22 中,脚本使用du命令检查目录的当前大小。 如果大小超过DIR_SIZE(以 GB 为单位),脚本将开始使用ls -1tra | head -1命令并开始将它们一个一个地删除。 它将继续直到目录大小未达到所需的限制。

编写脚本执行器

至于本文,核心组件将保留在 bash 脚本之上,但仍然需要一种从应用运行*.sh文件的方法。 最好的方法是使用线程(如果需要,可以使用执行器)。 该线程将以可配置的速率定期执行以上 bash 脚本。 我不会写那部分代码。 如果执行代码时遇到任何问题,请写下评论。

让我给你一个示例代码::

  1. package corejava.dischandler;
  2. import java.io.IOException;
  3. /**
  4. * Title: DiskFileManager.java
  5. * Description :- This class provides API to check file size and file time threshold and
  6. * if threshold is crossed then deletes file to come within threshold.
  7. */
  8. public final class DiskFileManager
  9. {
  10. private static DiskFileManager diskFileManager=new DiskFileManager();
  11. private DiskFileManager()
  12. {
  13. }
  14. /**
  15. *
  16. <pre>
  17. * <b>checkAndDeleteFiles</b>
  18. * <b>Description:This method is called to clean the files from the file system.</b>
  19. * </pre>
  20. * @throws InterruptedException
  21. * @throws IOException
  22. * @throws InstantiationException
  23. */
  24. public void checkAndDeleteFiles() throws InterruptedException, IOException, InstantiationException
  25. {
  26. try
  27. {
  28. StringBuffer outStr = new StringBuffer();
  29. StringBuffer errStr = new StringBuffer();
  30. String scriptFileName = "./discfilehandler.sh";
  31. String command = scriptFileName + "/logs 1 1";
  32. System.out.println("Command to be executed :- " + command);
  33. Process output = Runtime.getRuntime().exec(command);
  34. StreamEater errorEater = new StreamEater(output.getErrorStream(),errStr);
  35. StreamEater outputEater = new StreamEater(output.getInputStream(),outStr);
  36. errorEater.start();
  37. outputEater.start();
  38. try
  39. {
  40. int ret = output.waitFor();
  41. errorEater.join();
  42. outputEater.join();
  43. System.out.println();
  44. //logger.info("execute(): Error Stream:" + errStr + " ; execute(): Output Stream:" + outStr + " ; execute(): ExitValue:" + ret);
  45. } catch (InterruptedException e)
  46. {
  47. throw e;
  48. }
  49. } catch (IOException e)
  50. {
  51. throw e;
  52. }
  53. }
  54. /**
  55. *
  56. <pre>
  57. * <b>getInstance</b>
  58. * <b>Description:This method is used to get the instance of Disk File Manager.</b>
  59. * </pre>
  60. * @return
  61. */
  62. public static DiskFileManager getInstance()
  63. {
  64. return diskFileManager;
  65. }
  66. }

上面的代码将在类路径中找到脚本文件,并传递所需的参数。 在我们的例子中,“/logs 1 1”是 3 个参数,这意味着

  • 要监视的目录是/logs
  • 删除一天的日志文件,然后
  • 请勿在任何时候存储超过 1 GB 的日志文件。

添加StreamEater

因此,我们已经添加了一个 bash 脚本和一个用于运行脚本的执行器代码。 您必须编写自己的线程才能在执行器上方定期运行。

现在,我们将研究StreamEater,它实际上收集命令输出并提供给您的应用代码,因此应用可以记录它或执行所需的任何操作。

我们已经在上面的执行器中使用过StreamEater,现在我给出其代码:

  1. package corejava.dischandler;
  2. import java.io.BufferedReader;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. public class StreamEater extends Thread
  6. {
  7. /**
  8. * Stream Eater thread to eat up every thing that is the output to the
  9. * execute command
  10. */
  11. private InputStream iStream;
  12. public InputStream getiStream() {
  13. return iStream;
  14. }
  15. public void setiStream(InputStream iStream) {
  16. this.iStream = iStream;
  17. }
  18. private StringBuffer stringBuffer;
  19. public StringBuffer getStringBuffer() {
  20. return stringBuffer;
  21. }
  22. public void setStringBuffer(StringBuffer stringBuffer) {
  23. this.stringBuffer = stringBuffer;
  24. }
  25. /**
  26. * This is the constructor.
  27. *
  28. * @param is - It is the input stream
  29. * @param type - type of input stream
  30. * @param redirect - string buffer to contain the output.
  31. * @throws InstantiationException
  32. */
  33. public StreamEater(InputStream is, StringBuffer redirect) throws InstantiationException
  34. {
  35. this.iStream = is;
  36. if (redirect == null)
  37. {
  38. throw new InstantiationException("String Buffer Reference , second param can not be null");
  39. }
  40. this.stringBuffer = redirect;
  41. }
  42. /**
  43. * This is method called when the thread is started. It captures the stream
  44. * output and and store it into the buffer.
  45. */
  46. public void run()
  47. {
  48. InputStreamReader isr = null;
  49. BufferedReader br = null;
  50. try
  51. {
  52. isr = new InputStreamReader(iStream);
  53. br = new BufferedReader(isr);
  54. String line;
  55. while ((line = br.readLine()) != null)
  56. {
  57. stringBuffer.append(line).append(System.getProperty("line.separator"));
  58. }
  59. }
  60. catch (Exception ex)
  61. {
  62. ex.printStackTrace();
  63. }
  64. finally
  65. {
  66. if (isr != null)
  67. {
  68. try
  69. {
  70. isr.close();
  71. }
  72. catch (Exception e)
  73. {
  74. e.printStackTrace();
  75. }
  76. }
  77. if (br != null)
  78. {
  79. try
  80. {
  81. br.close();
  82. }
  83. catch (Exception e)
  84. {
  85. e.printStackTrace();
  86. }
  87. }
  88. }
  89. }
  90. }

如您所见,这些都是等待收集进程输出的小线程。

查看全部

使用上述类和给定的 bash 脚本,您可以轻松开发一些应用组件,以确保日志文件的大小不超过某些预定义的数目。 当您的应用负责删除实际的日志文件时,可以在任何级别对其进行自定义。

希望您在这篇文章中得到一些有用的信息。 如果需要任何帮助或有任何疑问,请给我写信。

学习愉快!