# 使用 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 脚本
*   编写脚本执行器
*   添加`StreamEater`
*   查看全部

## 确定方法

我相信，要把工作做好，我们肯定需要一个 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 脚本，您可以轻松开发一些应用组件，以确保日志文件的大小不超过某些预定义的数目。 当您的应用负责删除实际的日志文件时，可以在任何级别对​​其进行自定义。

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

学习愉快！