原文: https://howtodoinjava.com/linux/manage-system-log-files-in-linux-using-java/
如今,大多数应用都需要管理自己的日志文件,包括在达到特定大小限制时将其删除。 在本文中,我将尝试为这种日志文件管理提出一种解决方案。 我还将建议捕获 linux 进程的输出并将其记录到一些单独的日志文件中的方法。
本文是我上一篇文章的延续:自动重载配置,其中我讨论了只要有人在文件系统中更改配置文件,应用如何无需重新启动应用即可完成其配置重载的工作。 。
这篇文章中的部分:
- 确定方法
- 编写 bash 脚本
- 编写脚本执行器
- 添加
StreamEater
- 查看全部
确定方法
我相信,要把工作做好,我们肯定需要一个 bash 脚本。 Linux 具有一些非常有用的内置命令,这些命令在通过命令窗口执行时可以立即执行此工作。 bash 脚本的优势包括将实际应用的文件处理器代码解耦,如果需要任何特定于平台的更改,可以对其进行修改。
编写 bash 脚本
我已经编写了一个演示脚本。 您可以根据需要使用它:
#!/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
命令检查目录的当前大小。 如果大小超过DIR_SIZE
(以 GB 为单位),脚本将开始使用ls -1tra | head -1
命令并开始将它们一个一个地删除。 它将继续直到目录大小未达到所需的限制。
编写脚本执行器
至于本文,核心组件将保留在 bash 脚本之上,但仍然需要一种从应用运行*.sh
文件的方法。 最好的方法是使用线程(如果需要,可以使用执行器)。 该线程将以可配置的速率定期执行以上 bash 脚本。 我不会写那部分代码。 如果执行代码时遇到任何问题,请写下评论。
让我给你一个示例代码::
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
,现在我给出其代码:
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 脚本,您可以轻松开发一些应用组件,以确保日志文件的大小不超过某些预定义的数目。 当您的应用负责删除实际的日志文件时,可以在任何级别对其进行自定义。
希望您在这篇文章中得到一些有用的信息。 如果需要任何帮助或有任何疑问,请给我写信。
学习愉快!